summaryrefslogtreecommitdiffstats
path: root/grapher/grapher.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'grapher/grapher.cxx')
-rw-r--r--grapher/grapher.cxx454
1 files changed, 264 insertions, 190 deletions
diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx
index 429d0537..fe9880b2 100644
--- a/grapher/grapher.cxx
+++ b/grapher/grapher.cxx
@@ -10,10 +10,13 @@
#include <sstream>
#include <string>
#include <map>
+#include <memory>
#include <vector>
#include <signal.h>
+#include <boost/bind.hpp>
+
#include <gtkmm.h>
#include <gtkmm/button.h>
#include <gtkmm/stock.h>
@@ -31,6 +34,20 @@ using namespace std;
using namespace systemtap;
+// magic for noticing that the child stap process has died.
+int signalPipe[2] = {-1, -1};
+
+extern "C"
+{
+ void handleChild(int signum, siginfo_t* info, void* context)
+ {
+ char buf[1];
+ ssize_t err;
+ buf[0] = 1;
+ err = write(signalPipe[1], buf, 1);
+ }
+}
+
// Waits for a gtk I/O signal, indicating that a child has died, then
// performs an action
@@ -46,6 +63,20 @@ public:
ChildDeathReader(int sigfd_) : sigfd(sigfd_) {}
int getSigfd() { return sigfd; }
void setSigfd(int sigfd_) { sigfd = sigfd_; }
+ virtual pid_t reap()
+ {
+ pid_t pid;
+ int status;
+ if ((pid = waitpid(-1, &status, WNOHANG)) == -1)
+ {
+ std::perror("waitpid");
+ return -1;
+ }
+ else
+ {
+ return pid;
+ }
+ }
bool ioCallback(Glib::IOCondition ioCondition)
{
if ((ioCondition & Glib::IO_IN) == 0)
@@ -54,152 +85,26 @@ public:
if (read(sigfd, &buf, 1) <= 0)
return true;
- int status;
- while (wait(&status) != -1)
- ;
+ reap();
return true;
}
private:
int sigfd;
};
-class StapLauncher;
-
-class GraphicalStapLauncher
-{
-public:
- GraphicalStapLauncher(StapLauncher* launcher);
- bool runDialog();
- void onLaunch();
- void onLaunchCancel();
-private:
- Glib::RefPtr<Gnome::Glade::Xml> _launchStapDialog;
- Gtk::Window* _scriptWindow;
- Gtk::FileChooserButton* _chooserButton;
- Gtk::Entry* _stapArgEntry;
- Gtk::Entry* _scriptArgEntry;
- StapLauncher* _launcher;
-};
-
-class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback
-{
-public:
- GrapherWindow();
- virtual ~GrapherWindow() {}
- Gtk::VBox m_Box;
- Gtk::ScrolledWindow scrolled;
- GraphWidget w;
- void childDied(int pid);
- void setGraphicalLauncher(GraphicalStapLauncher* launcher)
- {
- _graphicalLauncher = launcher;
- }
- GraphicalStapLauncher* getGraphicalLauncher() { return _graphicalLauncher; }
-protected:
- virtual void on_menu_file_quit();
- virtual void on_menu_script_start();
- void addGraph();
- // menu support
- Glib::RefPtr<Gtk::UIManager> m_refUIManager;
- Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
- GraphicalStapLauncher* _graphicalLauncher;
-
-};
-
-GrapherWindow::GrapherWindow()
-{
- set_title("systemtap grapher");
- add(m_Box);
-
-
- //Create actions for menus and toolbars:
- m_refActionGroup = Gtk::ActionGroup::create();
- //File menu:
- m_refActionGroup->add(Gtk::Action::create("FileMenu", "File"));
- m_refActionGroup->add(Gtk::Action::create("StartScript", "Start script"),
- sigc::mem_fun(*this,
- &GrapherWindow::on_menu_script_start));
- m_refActionGroup->add(Gtk::Action::create("AddGraph", "Add graph"),
- sigc::mem_fun(*this, &GrapherWindow::addGraph));
- m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
- sigc::mem_fun(*this,
- &GrapherWindow::on_menu_file_quit));
- m_refUIManager = Gtk::UIManager::create();
- m_refUIManager->insert_action_group(m_refActionGroup);
-
- add_accel_group(m_refUIManager->get_accel_group());
- //Layout the actions in a menubar and toolbar:
- Glib::ustring ui_info =
- "<ui>"
- " <menubar name='MenuBar'>"
- " <menu action='FileMenu'>"
- " <menuitem action='StartScript'/>"
- " <menuitem action='AddGraph'/>"
- " <menuitem action='FileQuit'/>"
- " </menu>"
- " </menubar>"
- "</ui>";
- try
- {
- m_refUIManager->add_ui_from_string(ui_info);
- }
- catch(const Glib::Error& ex)
- {
- std::cerr << "building menus failed: " << ex.what();
- }
- Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar");
- scrolled.add(w);
- if(pMenubar)
- m_Box.pack_start(*pMenubar, Gtk::PACK_SHRINK);
- m_Box.pack_start(scrolled, Gtk::PACK_EXPAND_WIDGET);
- scrolled.show();
-
- show_all_children();
-
-}
-
-void GrapherWindow::on_menu_file_quit()
-{
- hide();
-}
-
-void GrapherWindow::on_menu_script_start()
-{
- _graphicalLauncher->runDialog();
-}
-
-void GrapherWindow::childDied(int pid)
-{
- hide();
-}
-
-// magic for noticing that the child stap process has died.
-int signalPipe[2] = {-1, -1};
-
-extern "C"
-{
- void handleChild(int signum, siginfo_t* info, void* context)
- {
- char buf[1];
- ssize_t err;
- buf[0] = 1;
- err = write(signalPipe[1], buf, 1);
- }
-}
-
// Depending on how args are passed, either launch stap directly or
// use the shell to parse arguments
class StapLauncher : public ChildDeathReader
{
public:
- StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0), _stapParser(0) {}
+ StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0) {}
StapLauncher(char** argv)
- : _argv(argv), _childPid(-1), _deathCallback(0), _stapParser(0)
+ : _argv(argv), _childPid(-1), _deathCallback(0)
{
}
StapLauncher(const string& stapArgs, const string& script,
const string& scriptArgs)
- : _childPid(-1), _deathCallback(0), _stapParser(0)
+ : _childPid(-1), _deathCallback(0), _win(0), _widget(0)
{
setArgs(stapArgs, script, scriptArgs);
}
@@ -239,12 +144,41 @@ public:
{
_deathCallback = callback;
}
- void setStapParser(StapParser *parser)
+ void setWinParams(Gtk::Window* win, GraphWidget* widget)
{
- _stapParser = parser;
+ _win = win;
+ _widget = widget;
}
int launch();
void cleanUp();
+ tr1::shared_ptr<StapParser> makeStapParser()
+ {
+ tr1::shared_ptr<StapParser> result(new StapParser(_win, _widget));
+ _parsers.push_back(ParserInstance(-1, result));
+ return result;
+ }
+ pid_t reap()
+ {
+ pid_t pid = ChildDeathReader::reap();
+ if (pid < 0)
+ return pid;
+ ParserList::iterator itr
+ = find_if(_parsers.begin(), _parsers.end(),
+ boost::bind(&ParserInstance::childPid, _1) == pid);
+ if (itr != _parsers.end())
+ itr->childPid = -1;
+ return pid;
+ }
+ void killAll()
+ {
+ for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end();
+ itr != end;
+ ++itr)
+ {
+ if (itr->childPid >= 0)
+ kill(itr->childPid, SIGTERM);
+ }
+ }
protected:
char** _argv;
string _stapArgs;
@@ -252,17 +186,39 @@ protected:
string _scriptArgs;
int _childPid;
ChildDeathReader::Callback* _deathCallback;
- StapParser* _stapParser;
+ Gtk::Window* _win;
+ GraphWidget* _widget;
+ struct ParserInstance
+ {
+ ParserInstance() : childPid(-1) {}
+ ParserInstance(int childPid_, tr1::shared_ptr<StapParser> stapParser_)
+ : childPid(childPid_), stapParser(stapParser_)
+ {
+ }
+ pid_t childPid;
+ tr1::shared_ptr<StapParser> stapParser;
+ };
+ typedef vector<ParserInstance> ParserList;
+ ParserList _parsers;
};
int StapLauncher::launch()
{
- int stapErrFd = -1;
-
- if (pipe(&signalPipe[0]) < 0)
+ int childPid = -1;
+ if (signalPipe[0] < 0)
{
- std::perror("pipe");
- exit(1);
+ if (pipe(&signalPipe[0]) < 0)
+ {
+ std::perror("pipe");
+ exit(1);
+ }
+ setSigfd(signalPipe[0]);
+ if (signalPipe[0] >= 0)
+ {
+ Glib::signal_io().connect(sigc::mem_fun(*this,
+ &ChildDeathReader::ioCallback),
+ signalPipe[0], Glib::IO_IN);
+ }
}
struct sigaction action;
action.sa_sigaction = handleChild;
@@ -280,15 +236,12 @@ int StapLauncher::launch()
std::perror("pipe");
exit(1);
}
- if ((_childPid = fork()) == -1)
+ if ((childPid = fork()) == -1)
{
exit(1);
}
- else if (_childPid)
+ else if (childPid)
{
- dup2(pipefd[0], STDIN_FILENO);
- stapErrFd = pipefd[2];
- close(pipefd[0]);
close(pipefd[1]);
close(pipefd[3]);
}
@@ -296,8 +249,8 @@ int StapLauncher::launch()
{
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[3], STDERR_FILENO);
- for (int i = 0; i < 4; ++i)
- close(pipefd[i]);
+ for_each(&pipefd[0], &pipefd[4], close);
+ for_each(&signalPipe[0], &signalPipe[2], close);
if (_argv)
{
char argv0[] = "stap";
@@ -318,70 +271,192 @@ int StapLauncher::launch()
}
_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,
+ tr1::shared_ptr<StapParser> sp(new StapParser(_win, _widget));
+ _parsers.push_back(ParserInstance(childPid, sp));
+ sp->setErrFd(pipefd[2]);
+ sp->setInFd(pipefd[0]);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
+ &StapParser::errIoCallback),
+ pipefd[2],
+ Glib::IO_IN);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
&StapParser::ioCallback),
- STDIN_FILENO,
+ pipefd[0],
Glib::IO_IN | Glib::IO_HUP);
- return _childPid;
+ return childPid;
}
void StapLauncher::cleanUp()
{
- if (_childPid > 0)
- kill(_childPid, SIGTERM);
- int status;
- while (wait(&status) != -1)
- ;
- if (_deathCallback)
+ struct sigaction action;
+ action.sa_handler = SIG_DFL;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction(SIGCLD, &action, 0);
+ // Drain any outstanding signals
+ close(signalPipe[1]);
+ char buf;
+ while (read(signalPipe[0], &buf, 1) > 0)
+ reap();
+ for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end();
+ itr != end;
+ ++itr)
{
- _deathCallback->childDied(_childPid);
- _childPid = -1;
+ if (itr->childPid > 0)
+ kill(itr->childPid, SIGTERM);
+ int status;
+ pid_t killedPid = -1;
+ if ((killedPid = wait(&status)) == -1)
+ {
+ std::perror("wait");
+ }
+ else if (killedPid != itr->childPid)
+ {
+ std::cerr << "wait: killed Pid " << killedPid << " != child Pid "
+ << itr->childPid << "\n";
+ }
+ else if (_deathCallback)
+ _deathCallback->childDied(itr->childPid);
}
}
-StapLauncher launcher;
+class GraphicalStapLauncher : public StapLauncher
+{
+public:
+ GraphicalStapLauncher();
+ bool runDialog();
+ void onLaunch();
+ void onLaunchCancel();
+private:
+ Glib::RefPtr<Gnome::Glade::Xml> _launchStapDialog;
+ Gtk::Window* _scriptWindow;
+ Gtk::FileChooserButton* _chooserButton;
+ Gtk::Entry* _stapArgEntry;
+ Gtk::Entry* _scriptArgEntry;
+};
+
+class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback
+{
+public:
+ GrapherWindow();
+ virtual ~GrapherWindow() {}
+ Gtk::VBox m_Box;
+ Gtk::ScrolledWindow scrolled;
+ GraphWidget w;
+ void childDied(int pid);
+ void setGraphicalLauncher(GraphicalStapLauncher* launcher)
+ {
+ _graphicalLauncher = launcher;
+ }
+ GraphicalStapLauncher* getGraphicalLauncher() { return _graphicalLauncher; }
+protected:
+ virtual void on_menu_file_quit();
+ virtual void on_menu_script_start();
+ void addGraph();
+ // menu support
+ Glib::RefPtr<Gtk::UIManager> m_refUIManager;
+ Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
+ GraphicalStapLauncher* _graphicalLauncher;
+
+};
+
+GrapherWindow::GrapherWindow()
+{
+ set_title("systemtap grapher");
+ add(m_Box);
+
+
+ //Create actions for menus and toolbars:
+ m_refActionGroup = Gtk::ActionGroup::create();
+ //File menu:
+ m_refActionGroup->add(Gtk::Action::create("FileMenu", "File"));
+ m_refActionGroup->add(Gtk::Action::create("StartScript", "Start script"),
+ sigc::mem_fun(*this,
+ &GrapherWindow::on_menu_script_start));
+ m_refActionGroup->add(Gtk::Action::create("AddGraph", "Add graph"),
+ sigc::mem_fun(*this, &GrapherWindow::addGraph));
+ m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
+ sigc::mem_fun(*this,
+ &GrapherWindow::on_menu_file_quit));
+ m_refUIManager = Gtk::UIManager::create();
+ m_refUIManager->insert_action_group(m_refActionGroup);
+
+ add_accel_group(m_refUIManager->get_accel_group());
+ //Layout the actions in a menubar and toolbar:
+ Glib::ustring ui_info =
+ "<ui>"
+ " <menubar name='MenuBar'>"
+ " <menu action='FileMenu'>"
+ " <menuitem action='StartScript'/>"
+ " <menuitem action='AddGraph'/>"
+ " <menuitem action='FileQuit'/>"
+ " </menu>"
+ " </menubar>"
+ "</ui>";
+ try
+ {
+ m_refUIManager->add_ui_from_string(ui_info);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << "building menus failed: " << ex.what();
+ }
+ Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar");
+ scrolled.add(w);
+ if(pMenubar)
+ m_Box.pack_start(*pMenubar, Gtk::PACK_SHRINK);
+ m_Box.pack_start(scrolled, Gtk::PACK_EXPAND_WIDGET);
+ scrolled.show();
+
+ show_all_children();
+
+}
+
+void GrapherWindow::on_menu_file_quit()
+{
+ hide();
+}
+
+void GrapherWindow::on_menu_script_start()
+{
+ _graphicalLauncher->runDialog();
+}
+
+void GrapherWindow::childDied(int pid)
+{
+ hide();
+}
+
+
+
int main(int argc, char** argv)
{
Gtk::Main app(argc, argv);
-
+ GraphicalStapLauncher launcher;
GrapherWindow win;
win.set_title("Grapher");
win.set_default_size(600, 200);
+ launcher.setWinParams(&win, &win.w);
- StapParser stapParser(win, win.w);
- launcher.setStapParser(&stapParser);
- GraphicalStapLauncher graphicalLauncher(&launcher);
- win.setGraphicalLauncher(&graphicalLauncher);
- if (argc > 1)
- {
- launcher.setArgv(argv + 1);
- launcher.setDeathCallback(&win);
- launcher.launch();
- }
- else
+ win.setGraphicalLauncher(&launcher);
+
+ if (argc == 2 && !std::strcmp(argv[1], "-"))
{
- Glib::signal_io().connect(sigc::mem_fun(stapParser,
+ tr1::shared_ptr<StapParser> sp = launcher.makeStapParser();
+ sp->setInFd(STDIN_FILENO);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
&StapParser::ioCallback),
STDIN_FILENO,
Glib::IO_IN | Glib::IO_HUP);
}
+ else if (argc > 1)
+ {
+ launcher.setArgv(argv + 1);
+ launcher.setDeathCallback(&win);
+ launcher.launch();
+ }
Gtk::Main::run(win);
launcher.cleanUp();
return 0;
@@ -393,8 +468,7 @@ void GrapherWindow::addGraph()
}
-GraphicalStapLauncher::GraphicalStapLauncher(StapLauncher* launcher)
- : _launcher(launcher)
+GraphicalStapLauncher::GraphicalStapLauncher()
{
try
{
@@ -428,10 +502,10 @@ bool GraphicalStapLauncher::runDialog()
void GraphicalStapLauncher::onLaunch()
{
- _launcher->setArgs(_stapArgEntry->get_text(), _chooserButton->get_filename(),
- _scriptArgEntry->get_text());
+ setArgs(_stapArgEntry->get_text(), _chooserButton->get_filename(),
+ _scriptArgEntry->get_text());
_scriptWindow->hide();
- _launcher->launch();
+ launch();
}
void GraphicalStapLauncher::onLaunchCancel()