From: Tim Moore Date: Tue, 8 Dec 2009 22:17:47 +0000 (+0100) Subject: grapher: start of a dialog for displaying active stap processes X-Git-Tag: release-1.0.9~40^2~12 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=8cabc8bcdcd22e8726734f1a18f23ed7d9c19e9f;p=systemtap.git grapher: start of a dialog for displaying active stap processes The names of active scripts are displayed in a list; mock buttons suggest being able to stop and restart them. * grapher/processwindow.glade: new file * grapher/Makefile.am: add processwindow.glade to installed files * grapher/StapParser.hxx (StapProcess): new class (StapParser): factor out members that are now in StapProcess (ioCallback): Use the new childDied signal instead of aborting the whole grapher when a child dies. * grapher/grapher.cxx (ProcModelColumns, ProcWindow): classes for displaying stap process window. (GrapherWindow::on_menu_proc_window): new function --- diff --git a/grapher/Makefile.am b/grapher/Makefile.am index 5bca286a1..1087f44db 100644 --- a/grapher/Makefile.am +++ b/grapher/Makefile.am @@ -9,5 +9,5 @@ stapgraph_CPPFLAGS = -DPKGDATADIR='"${pkgdatadir}"' stapgraph_CXXFLAGS = $(libglade_CFLAGS) -Wall -Werror stapgraph_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx GraphStyle.cxx stapgraph_LDADD = $(libglade_LIBS) -dist_pkgdata_DATA = graph-dialog.glade stap-start.glade +dist_pkgdata_DATA = graph-dialog.glade stap-start.glade processwindow.glade endif diff --git a/grapher/Makefile.in b/grapher/Makefile.in index f06402bc8..c608e5160 100644 --- a/grapher/Makefile.in +++ b/grapher/Makefile.in @@ -112,7 +112,8 @@ am__base_list = \ man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) -am__dist_pkgdata_DATA_DIST = graph-dialog.glade stap-start.glade +am__dist_pkgdata_DATA_DIST = graph-dialog.glade stap-start.glade \ + processwindow.glade DATA = $(dist_pkgdata_DATA) ETAGS = etags CTAGS = ctags @@ -246,7 +247,7 @@ top_srcdir = @top_srcdir@ @BUILD_GRAPHER_TRUE@stapgraph_CXXFLAGS = $(libglade_CFLAGS) -Wall -Werror @BUILD_GRAPHER_TRUE@stapgraph_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx GraphStyle.cxx @BUILD_GRAPHER_TRUE@stapgraph_LDADD = $(libglade_LIBS) -@BUILD_GRAPHER_TRUE@dist_pkgdata_DATA = graph-dialog.glade stap-start.glade +@BUILD_GRAPHER_TRUE@dist_pkgdata_DATA = graph-dialog.glade stap-start.glade processwindow.glade all: all-am .SUFFIXES: diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 653c00deb..b82cc0247 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -25,6 +25,12 @@ namespace systemtap using namespace std; using namespace std::tr1; + sigc::signal& childDiedSignal() + { + static sigc::signal deathSignal; + return deathSignal; + } + vector commaSplit(const boost::sub_range& range) { using namespace boost; @@ -72,7 +78,7 @@ vector commaSplit(const boost::sub_range& range) using namespace boost; if (ioCondition & Glib::IO_HUP) { - _win->hide(); + childDiedSignal().emit(getPid()); return true; } if ((ioCondition & Glib::IO_IN) == 0) @@ -82,7 +88,7 @@ vector commaSplit(const boost::sub_range& range) bytes_read = read(_inFd, buf, sizeof(buf) - 1); if (bytes_read <= 0) { - _win->hide(); + childDiedSignal().emit(getPid()); return true; } _buffer.append(buf, bytes_read); @@ -242,7 +248,7 @@ vector commaSplit(const boost::sub_range& range) bytes_read = read(_errFd, buf, sizeof(buf) - 1); if (bytes_read <= 0) { - _win->hide(); + cerr << "StapParser: error reading from stderr!\n"; return true; } if (write(STDOUT_FILENO, buf, bytes_read) < 0) diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index eba8a7af8..cfb807a8a 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -9,30 +9,61 @@ #include "GraphData.hxx" #include +#include + +#include + namespace systemtap { -class StapParser -{ - std::string _buffer; - typedef std::map > DataMap; - DataMap _dataSets; - CSVData _csv; - Gtk::Window* _win; - int _errFd; - int _inFd; - unsigned char _lineEndChar; -public: - StapParser(Gtk::Window* win) - : _win(win), _errFd(-1), _inFd(-1), _lineEndChar('\n') + // arguments and script for a stap process + struct StapProcess { - } - void parseData(std::tr1::shared_ptr gdata, - int64_t time, const std::string& dataString); - bool ioCallback(Glib::IOCondition ioCondition); - bool errIoCallback(Glib::IOCondition ioCondition); - int getErrFd() { return _errFd; } - void setErrFd(int fd) { _errFd = fd; } - int getInFd() { return _inFd; } - void setInFd(int fd) { _inFd = fd; } -}; + StapProcess(pid_t pid_ = -1) : pid(pid_) {} + std::string stapArgs; + std::string script; + std::string scriptArgs; + // arguments passed from a single array, like from the command line. + char **argv; + // -1 if the grapher is reading from stdin + pid_t pid; + }; + + class StapParser + { + std::string _buffer; + typedef std::map > DataMap; + DataMap _dataSets; + CSVData _csv; + int _errFd; + int _inFd; + unsigned char _lineEndChar; + std::tr1::shared_ptr _process; + public: + StapParser() + : _errFd(-1), _inFd(-1), _lineEndChar('\n') + { + } + void parseData(std::tr1::shared_ptr gdata, + int64_t time, const std::string& dataString); + bool ioCallback(Glib::IOCondition ioCondition); + bool errIoCallback(Glib::IOCondition ioCondition); + int getErrFd() const { return _errFd; } + void setErrFd(int fd) { _errFd = fd; } + int getInFd() const { return _inFd; } + void setInFd(int fd) { _inFd = fd; } + pid_t getPid() const + { + if (_process) + return _process->pid; + else + return -1; + } + std::tr1::shared_ptr getProcess() { return _process; } + void setProcess(std::tr1::shared_ptr process) + { + _process = process; + } + }; + + sigc::signal& childDiedSignal(); } diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 4769877fa..2a9a617b2 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -39,6 +39,7 @@ #include using namespace std; +using namespace tr1; using namespace systemtap; @@ -159,22 +160,33 @@ public: } int launch(); void cleanUp(); - tr1::shared_ptr makeStapParser() + shared_ptr makeStapParser() { - tr1::shared_ptr result(new StapParser(_win)); - _parsers.push_back(ParserInstance(-1, result)); + shared_ptr result(new StapParser); + _parsers.push_back(result); return result; } +private: + struct pidPred + { + pidPred(pid_t pid_) : pid(pid_) {} + bool operator()(const shared_ptr& parser) const + { + return parser->getPid() == pid; + } + pid_t pid; + }; +public: pid_t reap() { + using namespace boost; 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); + = find_if(_parsers.begin(), _parsers.end(), pidPred(pid)); if (itr != _parsers.end()) - itr->childPid = -1; + (*itr)->setProcess(tr1::shared_ptr()); return pid; } void killAll() @@ -183,10 +195,12 @@ public: itr != end; ++itr) { - if (itr->childPid >= 0) - kill(itr->childPid, SIGTERM); + if ((*itr)->getPid() >= 0) + kill((*itr)->getPid(), SIGTERM); } } + typedef vector > ParserList; + ParserList _parsers; protected: char** _argv; string _stapArgs; @@ -196,18 +210,6 @@ protected: ChildDeathReader::Callback* _deathCallback; Gtk::Window* _win; GraphWidget* _widget; - struct ParserInstance - { - ParserInstance() : childPid(-1) {} - ParserInstance(int childPid_, tr1::shared_ptr stapParser_) - : childPid(childPid_), stapParser(stapParser_) - { - } - pid_t childPid; - tr1::shared_ptr stapParser; - }; - typedef vector ParserList; - ParserList _parsers; }; int StapLauncher::launch() @@ -274,8 +276,18 @@ int StapLauncher::launch() } _exit(1); } - tr1::shared_ptr sp(new StapParser(_win)); - _parsers.push_back(ParserInstance(childPid, sp)); + tr1::shared_ptr sp(new StapParser); + shared_ptr proc(new StapProcess(childPid)); + if (_argv) + proc->argv = _argv; + else + { + proc->stapArgs = _stapArgs; + proc->script = _script; + proc->scriptArgs = _scriptArgs; + } + sp->setProcess(proc); + _parsers.push_back(sp); sp->setErrFd(pipefd[2]); sp->setInFd(pipefd[0]); Glib::signal_io().connect(sigc::mem_fun(sp.get(), @@ -305,21 +317,22 @@ void StapLauncher::cleanUp() itr != end; ++itr) { - if (itr->childPid > 0) - kill(itr->childPid, SIGTERM); + pid_t childPid = (*itr)->getPid(); + if (childPid > 0) + kill(childPid, SIGTERM); int status; pid_t killedPid = -1; if ((killedPid = wait(&status)) == -1) { std::perror("wait"); } - else if (killedPid != itr->childPid) + else if (killedPid != childPid) { std::cerr << "wait: killed Pid " << killedPid << " != child Pid " - << itr->childPid << "\n"; + << childPid << "\n"; } else if (_deathCallback) - _deathCallback->childDied(itr->childPid); + _deathCallback->childDied(childPid); } } @@ -338,6 +351,58 @@ private: Gtk::Entry* _scriptArgEntry; }; +class ProcModelColumns : public Gtk::TreeModelColumnRecord +{ +public: + ProcModelColumns() + { + add(_scriptName); + add(_proc); + } + Gtk::TreeModelColumn _scriptName; + Gtk::TreeModelColumn > _proc; +}; + +class ProcWindow +{ +public: + ProcWindow(); + ProcModelColumns _modelColumns; + Glib::RefPtr _xml; + Gtk::Window* _window; + Gtk::TreeView* _dataTreeView; + Glib::RefPtr _listStore; + void onClose(); +}; + +ProcWindow::ProcWindow() +{ + try + { + _xml = Gnome::Glade::Xml::create(PKGDATADIR "/processwindow.glade"); + _xml->get_widget("window1", _window); + _xml->get_widget("treeview1", _dataTreeView); + + } + catch (const Gnome::Glade::XmlError& ex ) + { + std::cerr << ex.what() << std::endl; + throw; + } + _listStore = Gtk::ListStore::create(_modelColumns); + _dataTreeView->set_model(_listStore); + _dataTreeView->append_column("Script", _modelColumns._scriptName); + Gtk::Button* button = 0; + _xml->get_widget("button5", button); + button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onClose), + false); +} + +void ProcWindow::onClose() +{ + _window->hide(); +} + class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback { public: @@ -355,25 +420,28 @@ public: protected: virtual void on_menu_file_quit(); virtual void on_menu_script_start(); + virtual void on_menu_proc_window(); void addGraph(); // menu support Glib::RefPtr m_refUIManager; Glib::RefPtr m_refActionGroup; GraphicalStapLauncher* _graphicalLauncher; - + shared_ptr _procWindow; }; + GrapherWindow::GrapherWindow() + : _procWindow(new ProcWindow) { 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"), + 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"), @@ -381,6 +449,12 @@ GrapherWindow::GrapherWindow() m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT), sigc::mem_fun(*this, &GrapherWindow::on_menu_file_quit)); + // Window menu + m_refActionGroup->add(Gtk::Action::create("WindowMenu", "Window")); + m_refActionGroup->add(Gtk::Action::create("ProcessWindow", + "Stap processes..."), + sigc::mem_fun(*this, + &GrapherWindow::on_menu_proc_window)); m_refUIManager = Gtk::UIManager::create(); m_refUIManager->insert_action_group(m_refActionGroup); @@ -394,6 +468,9 @@ GrapherWindow::GrapherWindow() " " " " " " + " " + " " + " " " " ""; try @@ -425,6 +502,25 @@ void GrapherWindow::on_menu_script_start() _graphicalLauncher->runDialog(); } + +void GrapherWindow::on_menu_proc_window() +{ + _procWindow->_listStore->clear(); + for (StapLauncher::ParserList::iterator spitr + = _graphicalLauncher->_parsers.begin(), + end = _graphicalLauncher->_parsers.end(); + spitr != end; + ++spitr) + { + shared_ptr sp = (*spitr)->getProcess(); + Gtk::TreeModel::iterator litr = _procWindow->_listStore->append(); + Gtk::TreeModel::Row row = *litr; + if (sp) + row[_procWindow->_modelColumns._scriptName] = sp->script; + } + _procWindow->_window->show(); +} + void GrapherWindow::childDied(int pid) { hide(); diff --git a/grapher/processwindow.glade b/grapher/processwindow.glade new file mode 100644 index 000000000..ad1bdd142 --- /dev/null +++ b/grapher/processwindow.glade @@ -0,0 +1,372 @@ + + + + + + + stap processes + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + True + True + False + + + + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Kill + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + False + False + + + + + + True + True + True + False + + + + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-refresh + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Restart + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + False + False + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 300 + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + 26 + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + False + 0 + + + + 17 + True + label1 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 20 + True + True + True + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 0 + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/grapher/processwindow.gladep b/grapher/processwindow.gladep new file mode 100644 index 000000000..183077ba9 --- /dev/null +++ b/grapher/processwindow.gladep @@ -0,0 +1,8 @@ + + + + + + + FALSE +