diff options
author | Tim Moore <timoore@redhat.com> | 2009-09-23 18:03:00 +0200 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2009-09-30 20:40:30 +0200 |
commit | 4cba1a1a2cb6d5fc03f0f89f480c6761974938af (patch) | |
tree | 923ca4f615869d34867e28b9df41da68e374ca78 | |
parent | 735d2a19eac533188e96a578142c0ec0d1311fdb (diff) | |
download | systemtap-steved-4cba1a1a2cb6d5fc03f0f89f480c6761974938af.tar.gz systemtap-steved-4cba1a1a2cb6d5fc03f0f89f480c6761974938af.tar.xz systemtap-steved-4cba1a1a2cb6d5fc03f0f89f480c6761974938af.zip |
classes for launching stap and listening for its death
* grapher/grapher.cxx (ChildDeathReader): New class to handle I/O signalling
death of a child.
(GrapherWindow): Inherit from ChildDeathReader.
(StapLauncher): New class for passing arguments to inferior stap process
and checking for its demise.
(main): Move launching logic to StapLauncher.
-rw-r--r-- | grapher/grapher.cxx | 315 |
1 files changed, 221 insertions, 94 deletions
diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 82f60b79..62a54aec 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -1,6 +1,7 @@ #include "GraphWidget.hxx" #include "StapParser.hxx" +#include <algorithm> #include <cerrno> #include <cmath> #include <cstdio> @@ -9,6 +10,7 @@ #include <sstream> #include <string> #include <map> +#include <vector> #include <signal.h> @@ -22,10 +24,45 @@ #include <signal.h> #include <sys/types.h> #include <sys/wait.h> +#include <getopt.h> + +using namespace std; using namespace systemtap; -class GrapherWindow : public Gtk::Window +// Waits for a gtk I/O signal, indicating that a child has died, then +// performs an action + +class ChildDeathReader +{ +public: + struct Callback + { + virtual void childDied(int pid) {} + }; + ChildDeathReader() : sigfd(-1) {} + ChildDeathReader(int sigfd_) : sigfd(sigfd_) {} + int getSigfd() { return sigfd; } + void setSigfd(int sigfd_) { sigfd = sigfd_; } + bool ioCallback(Glib::IOCondition ioCondition) + { + if ((ioCondition & Glib::IO_IN) == 0) + return true; + char buf; + + if (read(sigfd, &buf, 1) <= 0) + return true; + int status; + while (wait(&status) != -1) + ; + return true; + } +private: + int sigfd; +}; + + +class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback { public: GrapherWindow(); @@ -33,6 +70,7 @@ public: Gtk::VBox m_Box; Gtk::ScrolledWindow scrolled; GraphWidget w; + void childDied(int pid); protected: virtual void on_menu_file_quit(); void addGraph(); @@ -93,9 +131,12 @@ void GrapherWindow::on_menu_file_quit() hide(); } -// magic for noticing that the child stap process has died. -int childPid = -1; +void GrapherWindow::childDied(int pid) +{ + hide(); +} +// magic for noticing that the child stap process has died. int signalPipe[2] = {-1, -1}; extern "C" @@ -109,30 +150,174 @@ extern "C" } } -class SignalReader +// Depending on how args are passed, either launch stap directly or +// use the shell to parse arguments +class StapLauncher : public ChildDeathReader { public: - SignalReader(GrapherWindow& win_, int sigfd_) : win(win_), sigfd(sigfd_) {} - bool ioCallback(Glib::IOCondition ioCondition) + StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0), _stapParser(0) {} + StapLauncher(char** argv) + : _argv(argv), _childPid(-1), _deathCallback(0), _stapParser(0) { - if ((ioCondition & Glib::IO_IN) == 0) - return true; - char buf; - - if (read(sigfd, &buf, 1) <= 0) - return true; - int status; - while (wait(&status) != -1) - ; - childPid = -1; - win.hide(); - return true; } -private: - GrapherWindow& win; - int sigfd; + StapLauncher(const string& stapArgs, const string& script, + const string& scriptArgs) + : _childPid(-1), _deathCallback(0), _stapParser(0) + { + setArgs(stapArgs, script, scriptArgs); + } + void setArgv(char** argv) + { + _argv = argv; + } + + char** getArgv() + { + return _argv; + } + + void setArgs(const string& stapArgs, const string& script, + const string& scriptArgs) + { + _stapArgs = stapArgs; + _script = script; + _scriptArgs = scriptArgs; + } + + void getArgs(string& stapArgs, string& script, string& scriptArgs) + { + stapArgs = _stapArgs; + script = _script; + scriptArgs = _scriptArgs; + } + + void reset() + { + _argv = 0; + _stapArgs.clear(); + _script.clear(); + _scriptArgs.clear(); + } + void setDeathCallback(ChildDeathReader::Callback* callback) + { + _deathCallback = callback; + } + void setStapParser(StapParser *parser) + { + _stapParser = parser; + } + int launch(); + void cleanUp(); +protected: + char** _argv; + string _stapArgs; + string _script; + string _scriptArgs; + int _childPid; + ChildDeathReader::Callback* _deathCallback; + StapParser* _stapParser; }; +int StapLauncher::launch() +{ + int stapErrFd = -1; + + if (pipe(&signalPipe[0]) < 0) + { + std::perror("pipe"); + exit(1); + } + struct sigaction action; + action.sa_sigaction = handleChild; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP; + sigaction(SIGCLD, &action, 0); + int pipefd[4]; + if (pipe(&pipefd[0]) < 0) + { + std::perror("pipe"); + exit(1); + } + if (pipe(&pipefd[2]) < 0) + { + std::perror("pipe"); + exit(1); + } + if ((_childPid = fork()) == -1) + { + exit(1); + } + else if (_childPid) + { + dup2(pipefd[0], STDIN_FILENO); + stapErrFd = pipefd[2]; + close(pipefd[0]); + close(pipefd[1]); + close(pipefd[3]); + } + else + { + dup2(pipefd[1], STDOUT_FILENO); + dup2(pipefd[3], STDERR_FILENO); + for (int i = 0; i < 4; ++i) + close(pipefd[i]); + if (_argv) + { + char argv0[] = "stap"; + char** argvEnd = _argv; + for (; *argvEnd; ++argvEnd) + ; + char** realArgv = new char*[argvEnd - _argv + 2]; + realArgv[0] = argv0; + std::copy(_argv, argvEnd + 1, &realArgv[1]); + execvp("stap", realArgv); + } + else + { + string argString = "stap" + _stapArgs + " " + _script + " " + + _scriptArgs; + execl("/bin/sh", "-c", argString.c_str(), static_cast<char*>(0)); + } + _exit(1); + } + if (stapErrFd >= 0) + { + _stapParser->setErrFd(stapErrFd); + Glib::signal_io().connect(sigc::mem_fun(*_stapParser, + &StapParser::errIoCallback), + stapErrFd, + Glib::IO_IN); + } + setSigfd(signalPipe[0]); + if (signalPipe[0] >= 0) + { + Glib::signal_io().connect(sigc::mem_fun(*this, + &ChildDeathReader::ioCallback), + signalPipe[0], Glib::IO_IN); + } + Glib::signal_io().connect(sigc::mem_fun(*_stapParser, + &StapParser::ioCallback), + STDIN_FILENO, + Glib::IO_IN | Glib::IO_HUP); + return _childPid; +} + +void StapLauncher::cleanUp() +{ + if (_childPid > 0) + kill(_childPid, SIGTERM); + int status; + while (wait(&status) != -1) + ; + if (_deathCallback) + { + _deathCallback->childDied(_childPid); + _childPid = -1; + } +} + +StapLauncher launcher; + int main(int argc, char** argv) { Gtk::Main app(argc, argv); @@ -143,82 +328,24 @@ int main(int argc, char** argv) win.set_default_size(600, 200); StapParser stapParser(win, win.w); + launcher.setStapParser(&stapParser); - int stapErrFd = -1; if (argc > 1) { - if (pipe(&signalPipe[0]) < 0) - { - std::perror("pipe"); - exit(1); - } - struct sigaction action; - action.sa_sigaction = handleChild; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP; - sigaction(SIGCLD, &action, 0); - int pipefd[4]; - if (pipe(&pipefd[0]) < 0) - { - std::perror("pipe"); - exit(1); - } - if (pipe(&pipefd[2]) < 0) - { - std::perror("pipe"); - exit(1); - } - if ((childPid = fork()) == -1) - { - exit(1); - } - else if (childPid) - { - dup2(pipefd[0], STDIN_FILENO); - stapErrFd = pipefd[2]; - close(pipefd[0]); - close(pipefd[1]); - close(pipefd[3]); - } - else - { - dup2(pipefd[1], STDOUT_FILENO); - dup2(pipefd[3], STDERR_FILENO); - for (int i = 0; i < 4; ++i) - close(pipefd[i]); - char argv0[] = "stap"; - argv[0] = argv0; - execvp("stap", argv); - exit(1); - return 1; - } - } - Glib::signal_io().connect(sigc::mem_fun(stapParser, - &StapParser::ioCallback), - STDIN_FILENO, - Glib::IO_IN | Glib::IO_HUP); - if (stapErrFd >= 0) - { - stapParser.setErrFd(stapErrFd); - Glib::signal_io().connect(sigc::mem_fun(stapParser, - &StapParser::errIoCallback), - stapErrFd, - Glib::IO_IN); - } - SignalReader sigReader(win, signalPipe[0]); - if (signalPipe[0] >= 0) - { - Glib::signal_io().connect(sigc::mem_fun(sigReader, - &SignalReader::ioCallback), - signalPipe[0], Glib::IO_IN); - } - Gtk::Main::run(win); - if (childPid > 0) - kill(childPid, SIGTERM); - int status; - while (wait(&status) != -1) - ; - return 0; + launcher.setArgv(argv + 1); + launcher.setDeathCallback(&win); + launcher.launch(); + } + else + { + Glib::signal_io().connect(sigc::mem_fun(stapParser, + &StapParser::ioCallback), + STDIN_FILENO, + Glib::IO_IN | Glib::IO_HUP); + } + Gtk::Main::run(win); + launcher.cleanUp(); + return 0; } void GrapherWindow::addGraph() |