execmon.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: execmon.cpp
  3. // Purpose: A simple execution monitor to test if wx samples crash at startup or not
  4. // Author: Francesco Montorsi
  5. // Modified by:
  6. // Created: 25/3/09
  7. // Copyright: (c) 2009 Francesco Montorsi
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // ============================================================================
  11. // declarations
  12. // ============================================================================
  13. // ----------------------------------------------------------------------------
  14. // headers
  15. // ----------------------------------------------------------------------------
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18. #ifdef __BORLANDC__
  19. #pragma hdrstop
  20. #endif
  21. #ifndef WX_PRECOMP
  22. #include "wx/app.h"
  23. #include "wx/log.h"
  24. #endif // WX_PRECOMP
  25. #include "wx/cmdline.h"
  26. #include "wx/vector.h"
  27. #include "wx/process.h"
  28. #include "wx/sstream.h"
  29. #include "wx/utils.h"
  30. #include "wx/filename.h"
  31. #include "wx/app.h"
  32. #include "wx/log.h"
  33. // ============================================================================
  34. // implementation
  35. // ============================================================================
  36. // ----------------------------------------------------------------------------
  37. // utility classes
  38. // ----------------------------------------------------------------------------
  39. class MonitoredProcess : public wxProcess
  40. {
  41. public:
  42. MonitoredProcess()
  43. { Redirect(); m_crashed=false; m_exitCode=0; }
  44. void OnTerminate(int WXUNUSED(pid), int status)
  45. {
  46. wxStringOutputStream out, err;
  47. if (GetInputStream()) out.Write(*GetInputStream());
  48. if (GetErrorStream()) err.Write(*GetErrorStream());
  49. //wxPrintf("%s\n", stdout.GetString());
  50. //wxPrintf("%s\n", stderr.GetString());
  51. // when wx programs assert on wxGTK/wxMac, they put on stderr a message like:
  52. // [Debug] date somefilename.pp(nnnn): assert "xxxxx" failed in yyyy
  53. // but then the assert dialog pop-ups and thus the app doesn't exit
  54. // FIXME: make assertion detection work also under other platforms
  55. // see http://trac.wxwidgets.org/ticket/10697
  56. m_crashed = out.GetString().Contains("assert") ||
  57. err.GetString().Contains("assert");
  58. m_exitCode = status;
  59. }
  60. void Kill()
  61. {
  62. wxProcess::Kill(GetPid());
  63. // wxProcess::Kill doesn't trigger a call to OnTerminate() normally...
  64. // but we still need to call it!
  65. OnTerminate(0, -1);
  66. }
  67. bool Crashed() const
  68. { return m_crashed; }
  69. int GetExitCode() const
  70. { return m_exitCode; }
  71. private:
  72. bool m_crashed;
  73. int m_exitCode;
  74. };
  75. class MonitorData
  76. {
  77. public:
  78. MonitorData(const wxString& cmd) : program(cmd) {}
  79. wxString program;
  80. MonitoredProcess process;
  81. };
  82. // ----------------------------------------------------------------------------
  83. // the real main
  84. // ----------------------------------------------------------------------------
  85. bool TestExec(const wxVector<wxFileName>& programs, long timeout)
  86. {
  87. size_t i;
  88. wxVector<MonitorData*> data;
  89. // run all programs specified as command line parameters
  90. wxArrayLong procID;
  91. for (i=0; i<programs.size(); i++)
  92. {
  93. MonitorData *dt = new MonitorData(programs[i].GetFullPath());
  94. long pid = wxExecute(programs[i].GetFullPath(), wxEXEC_ASYNC, &dt->process);
  95. if (pid == 0)
  96. {
  97. wxLogError("could not run the program '%s'", programs[i].GetFullPath());
  98. }
  99. else
  100. {
  101. wxLogMessage("started program '%s' (pid %d)...",
  102. programs[i].GetFullPath(), pid);
  103. wxASSERT(dt->process.GetPid() == pid);
  104. data.push_back(dt);
  105. }
  106. }
  107. // sleep some moments
  108. wxSleep(timeout);
  109. // check if all processes are still running
  110. bool allok = true;
  111. for (i=0; i<data.size(); i++)
  112. {
  113. MonitoredProcess& proc = data[i]->process;
  114. const wxString& prog = data[i]->program;
  115. if (wxProcess::Exists(proc.GetPid()))
  116. proc.Kill();
  117. else
  118. {
  119. // this typically never happens, at least when running wx-programs
  120. // built with debug builds of wx (see MonitoredProcess::OnTerminate;
  121. // even if an asserts fail the app doesn't automatically close!):
  122. wxLogMessage("program '%s' (pid %d) is NOT running anymore...",
  123. prog, proc.GetPid());
  124. allok = false;
  125. }
  126. if (data[i]->process.Crashed())
  127. {
  128. allok = false;
  129. wxLogMessage("program '%s' (pid %d) crashed...",
  130. prog, proc.GetPid());
  131. }
  132. else
  133. wxLogMessage("program '%s' (pid %d) ended with exit code %d...",
  134. prog, proc.GetPid(), proc.GetExitCode());
  135. }
  136. return allok;
  137. }
  138. // ----------------------------------------------------------------------------
  139. // main
  140. // ----------------------------------------------------------------------------
  141. int main(int argc, char **argv)
  142. {
  143. wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "execmon");
  144. wxInitializer initializer;
  145. if ( !initializer )
  146. {
  147. fprintf(stderr, "Failed to initialize the wxWidgets library, aborting.");
  148. return -1;
  149. }
  150. static const wxCmdLineEntryDesc cmdLineDesc[] =
  151. {
  152. { wxCMD_LINE_SWITCH, "h", "help",
  153. "show this help message",
  154. wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
  155. { wxCMD_LINE_OPTION, "t", "timeout",
  156. "kills all processes still alive after 'num' seconds",
  157. wxCMD_LINE_VAL_NUMBER, 0 },
  158. { wxCMD_LINE_PARAM, "", "",
  159. "program-to-run",
  160. wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE },
  161. { wxCMD_LINE_NONE }
  162. };
  163. wxLog::DisableTimestamp();
  164. wxCmdLineParser parser(cmdLineDesc, argc, argv);
  165. switch ( parser.Parse() )
  166. {
  167. case -1:
  168. // help was shown
  169. break;
  170. case 0:
  171. {
  172. // check arguments
  173. wxVector<wxFileName> programs;
  174. for (unsigned int i=0; i<parser.GetParamCount(); i++)
  175. {
  176. wxFileName fn(parser.GetParam(i));
  177. if (!fn.IsAbsolute())
  178. fn.MakeAbsolute();
  179. programs.push_back(fn);
  180. }
  181. long timeout;
  182. if (!parser.Found("t", &timeout))
  183. timeout = 3;
  184. return TestExec(programs, timeout) ? 0 : 1;
  185. }
  186. break;
  187. default:
  188. // syntax error
  189. break;
  190. }
  191. return 0;
  192. }