From: <sv...@va...> - 2009-10-08 19:24:00
|
Author: cerion Date: 2009-10-08 20:23:37 +0100 (Thu, 08 Oct 2009) New Revision: 458 Log: REVIEW THIS! Long non-commited changes, needs good review Modified: branches/exec_start/src/core/memcheck_object.cpp branches/exec_start/src/core/memcheck_object.h branches/exec_start/src/core/tool_object.cpp branches/exec_start/src/core/tool_object.h branches/exec_start/src/core/valgrind_object.cpp Modified: branches/exec_start/src/core/memcheck_object.cpp =================================================================== --- branches/exec_start/src/core/memcheck_object.cpp 2009-02-21 11:03:47 UTC (rev 457) +++ branches/exec_start/src/core/memcheck_object.cpp 2009-10-08 19:23:37 UTC (rev 458) @@ -8,6 +8,10 @@ * See the file LICENSE.GPL for the full license details. */ +#include <sys/types.h> // fork +#include <unistd.h> // fork, exec +#include <string.h> // strcpy + #include "memcheck_object.h" #include "valkyrie_object.h" #include "vk_config.h" @@ -245,10 +249,7 @@ break; case Valkyrie::modeParseOutput: - proc->tryTerminate(); /* first ask nicely. */ - /* if proc still running after msec_timeout, terminate with prejudice */ - QTimer::singleShot( 2000, proc, SLOT( kill() ) ); // TODO: move N to config - + killProc(); // TODO?: if kill proc while we're i parseOutput(), we could get a segfault? break; @@ -401,21 +402,6 @@ } -/* if --vg-opt=<arg> was specified on the cmd-line, called by - valkyrie->runTool(); if set via the run-button in the gui, - then MainWindow::run() calls valkyrie->runTool(). */ -bool Memcheck::run( QStringList flags ) -{ - /* tell valkyrie what we are doing */ - emit setRunMode( Valkyrie::modeParseOutput ); - - /* Read from log_fd */ - int log_fd = vkConfig->rdInt( "log-fd", "valgrind" ); - - return runProcess( flags, log_fd, "mc_output" ); -} - - /* Run a VKProcess, as given by 'flags'. Listens to output on 'log_fd', loading this output to the toolView via xmlParser::loadItem(XmlOutput*). @@ -590,6 +576,184 @@ emitRunning( false ); } + + + + + + + +/* Can't call a member function directly, so go around the houses */ +void glbl_valgrind_handler( int vg_signum ) +{ + // fprintf(stderr, "glbl_valgrind_handler(%d)\n", vg_signum); + Memcheck* mc = (Memcheck*)vkConfig->vkObject( "memcheck" ); + mc->valgrind_handler( vg_signum ); +} + +/* set valgrindExited, so parseLogFileLive can quit on this */ +void Memcheck::valgrind_handler( int vg_signum ) +{ + /* We got a SIGCHLD + for now, assuming child is ready to terminate + TODO: deal with child SIGSTOP'ed etc + */ + + fprintf(stderr, "valgrind_handler(%d)\n", vg_signum); + valgrindExited = true; +} + +void Memcheck::parseLogFileLive( QString& logFname ) +{ + QFile logFile(logFname); + + if ( !logFile.open( IO_ReadOnly ) ) { + fprintf(stderr, "err opening file for reading"); + return; + } + + setupParser( true ); + + if ( !reader.parse( &source, true ) ) { + /* if we get here, it means either: + a) Output from valgrind run is bad + b) Output from vk_logmerge run is bad + - neither should happen, so die. + Not very nice, but output-to-date is saved in the auto-log file. + TODO: do sthng nicer here - but rem not to block this function! + */ + vk_assert_never_reached(); + } + + QTextStream stream( &logFile ); + while ( true ) { + QString line; + while ( !stream.atEnd() ) { + line = stream.readLine(); /* line of text excluding '\n' */ + + if (line.isNull()) /* last line for now... */ + break; + +#if 0//DEBUG_ON + fprintf(stderr, "V: %s\n", line.latin1()); +#endif + + // Forward line to xmlparser + source.setData( line ); + bool ok = reader.parseContinue(); + if ( !ok ) { + fprintf(stderr, "\nMemcheck::parseLogFileLive(%s): '%s'\n", + logFname.latin1(), line.latin1() ); + /* if we get here, it means either: + a) Output from valgrind run is bad + b) Output from vk_logmerge run is bad + - neither should happen, so die. + Not very nice, but output-to-date is saved in the auto-log file. + TODO: do sthng nicer here - but rem not to block this function! + */ + vk_assert_never_reached(); + } + + if (line == "</valgrindoutput>") + break; + } /* while ( !stream.atEnd ) */ + + /* SIGCHLD will reset this when valgrind done: */ + if (valgrindExited) { +#if 0//DEBUG_ON + fprintf(stderr, "Memcheck::parseLogFileLive(): valgrind finished\n"); +#endif + break; + } + /* or we might have found the last line already: */ + if (line == "</valgrindoutput>") { + break; + } + + /* so gui still lives (and stop button works!) */ + qApp->processEvents(); + + int millisec = 100; + usleep(millisec * 1000); // microseconds + } /* while (true) */ + + logFile.close(); + setupParser( false ); +} + + +/* if --vg-opt=<arg> was specified on the cmd-line, called by + valkyrie->runTool(); if set via the run-button in the gui, + then MainWindow::run() calls valkyrie->runTool(). */ +bool Memcheck::run( QStringList flags ) +{ + /* tell valkyrie what we are doing */ + emit setRunMode( Valkyrie::modeParseOutput ); + + /* TODO: scan flags for --log- options, and set logFname accordingly */ + QString logFname = vk_mkstemp( "mc_output", vkConfig->logsDir(), ".xml" ); + QString logOpt = "--log-file-exactly=" + logFname; + flags.insert( flags.at(1), logOpt ); + + char* valg_argv[flags.count()+1]; + unsigned int i; + for ( i=0; i<flags.count(); i++ ) { + valg_argv[i] = new char[flags[i].length() + 1]; + strcpy(valg_argv[i], flags[i].latin1()); + } + valg_argv[i] = NULL; + + /* fork */ + int pid = fork(); + if (pid < 0) { + vkError( this->view(), "Error", "<p>fork() failed:<br>%s</p>", + strerror(errno) ); + return false; + } + + if (pid == 0) { + /* child */ + + /* new valgrind process */ + execvp( flags[0].latin1(), valg_argv ); + + /* shouldn't reach here */ + vkError( this->view(), "Error", "<p>execvp failed on: <br>%s<br>%s</p>", + flags.join(" ").latin1(), strerror(errno) ); + return false; + } + + fileSaved = false; + emitRunning( true ); + valgrindExited = false; + saveFname = logFname; + + /* parent */ + valg_pid = pid; /* keep track of pid, so can control later */ + + /* we need to know when valgrind has finished. */ + signal(SIGCHLD, glbl_valgrind_handler ); + + /* go read the log, real-time */ + parseLogFileLive( logFname ); + + /* clean up valg_argv[] */ + for ( i=1; i<flags.count(); i++ ) { + delete valg_argv[i]; + } + + /* kill child, if alive */ + // killProc(); + + emitRunning( false ); + return true; +} + + + + + + /* brings up a fileSaveDialog until successfully saved, or user pressed Cancel. if fname.isEmpty, ask user for a name first. Modified: branches/exec_start/src/core/memcheck_object.h =================================================================== --- branches/exec_start/src/core/memcheck_object.h 2009-02-21 11:03:47 UTC (rev 457) +++ branches/exec_start/src/core/memcheck_object.h 2009-10-08 19:23:37 UTC (rev 458) @@ -63,6 +63,8 @@ bool fileSaveDialog( QString fname ); + void valgrind_handler( int vg_signum ); + public slots: void loadClientOutput( const QString&, int log_fd=-1 ); @@ -89,6 +91,8 @@ bool runProcess( QStringList flags, int log_fd, QString fbasename ); + void parseLogFileLive( QString& logFname ); + private: XMLParser* xmlParser; QXmlSimpleReader reader; Modified: branches/exec_start/src/core/tool_object.cpp =================================================================== --- branches/exec_start/src/core/tool_object.cpp 2009-02-21 11:03:47 UTC (rev 457) +++ branches/exec_start/src/core/tool_object.cpp 2009-10-08 19:23:37 UTC (rev 458) @@ -12,6 +12,9 @@ * See the file LICENSE.GPL for the full license details. */ +#include <sys/types.h> /* waitpid */ +#include <sys/wait.h> /* waitpid */ + #include "tool_object.h" #include "tool_view.h" #include "vk_config.h" @@ -32,6 +35,8 @@ { m_view = 0; proc = 0; + valgrindExited = false; + valg_pid = 0; is_Running = false; fileSaved = true; @@ -44,9 +49,20 @@ /* kill proc if it is running */ void ToolObject::killProc() { + if (valg_pid > 0) { // valid pid? + if (kill( valg_pid, SIGKILL ) == -1) { + perror("ToolObject::killProc()"); + return; + } + + /* TODO: sthng with SIGALRM to wait 2 secs, then kill(SIGKILL) */ + + valgrindExited = true; + valg_pid = 0; + } + if ( proc != 0 ) { if ( proc->isRunning() ) { - /* if this view is closed, don't leave the process running */ proc->tryTerminate(); QTimer::singleShot( 5000, proc, SLOT( kill() ) ); } Modified: branches/exec_start/src/core/tool_object.h =================================================================== --- branches/exec_start/src/core/tool_object.h 2009-02-21 11:03:47 UTC (rev 457) +++ branches/exec_start/src/core/tool_object.h 2009-10-08 19:23:37 UTC (rev 458) @@ -74,6 +74,9 @@ bool fileSaved; VKProcess* proc; + + bool valgrindExited; + int valg_pid; /* pid of valgrind process */ }; Modified: branches/exec_start/src/core/valgrind_object.cpp =================================================================== --- branches/exec_start/src/core/valgrind_object.cpp 2009-02-21 11:03:47 UTC (rev 457) +++ branches/exec_start/src/core/valgrind_object.cpp 2009-10-08 19:23:37 UTC (rev 458) @@ -329,9 +329,10 @@ } } break; - case LOG_PID: /* log to <file>.pid<pid> */ - case LOG_FILE: /* log to <file> */ +// case LOG_PID: /* log to <file>.pid<pid> */ +// case LOG_FILE: /* log to <file> */ case LOG_SOCKET: /* log to socket ipaddr:port */ + case LOG_FD: /* log to file descriptor */ break; case XML_OUTPUT: /* the sine qua non */ |