home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / Agent.C < prev    next >
C/C++ Source or Header  |  1998-12-02  |  11KB  |  553 lines

  1. // $Id: Agent.C,v 1.23 1998/12/02 13:44:19 zeller Exp $
  2. // Three-channel Agent Interface
  3.  
  4. // Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char Agent_rcsid[] = 
  30.     "$Id: Agent.C,v 1.23 1998/12/02 13:44:19 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "assert.h"
  37. #include "config.h"
  38.  
  39. #include <iostream.h>
  40.  
  41. #include <errno.h>
  42. #include <signal.h>
  43. #include <unistd.h>
  44. #include <stdlib.h>
  45.  
  46. extern "C" {
  47. #include <sys/types.h>
  48. #include <sys/wait.h>
  49. }
  50.  
  51. #ifndef EXIT_SUCCESS
  52. #define EXIT_SUCCESS 0
  53. #endif
  54.  
  55. #ifndef EXIT_FAILURE
  56. #define EXIT_FAILURE 1
  57. #endif
  58.  
  59.  
  60. #include "sigName.h"
  61. #include "Agent.h"
  62. #include "AgentM.h"
  63.  
  64. DEFINE_TYPE_INFO_0(Agent)
  65.  
  66. // Child Status Change Handler
  67. void Agent::childStatusChange(int sig)
  68. {
  69.     // Notify agents of their new status
  70.     runningAgents.childStatusChange();
  71.  
  72.     // Reinstall ourselves (for SVR4 and others)
  73.     signal(sig, SignalProc(Agent::childStatusChange));
  74. }
  75.  
  76. // Default I/O error handler
  77. void Agent::defaultHandler(Agent *source, void *, void *call_data)
  78. {
  79.     string msg = (char *)call_data;
  80.     if (msg != "Exit 0")
  81.     cerr << source->name() << ": " << msg << "\n";
  82. }
  83.  
  84. void Agent::addDefaultHandler(unsigned type)
  85. {
  86.     addHandler(type, defaultHandler);
  87. }
  88.  
  89.  
  90. // All running agents
  91. AgentManager Agent::runningAgents((SignalProc)Agent::childStatusChange);
  92.  
  93. // Running states
  94. void Agent::setRunning()
  95. {
  96.     bool was_running = _running;
  97.     _running = true;
  98.  
  99. #if 0
  100.     Agent *agent = runningAgents.search(pid());
  101.     if (agent != 0)
  102.     cerr << "Warning: Agent " << agent->name() << " started twice\n";
  103. #endif
  104.  
  105.     runningAgents += this;
  106.     activateIO();
  107.  
  108.     if (!was_running)
  109.     callHandlers(Started, (char *)path());
  110. }
  111.  
  112. void Agent::unsetRunning()
  113. {
  114.     if (_running)
  115.     callHandlers(Stopped, (char *)path());
  116.  
  117.     deactivateIO();
  118.     runningAgents -= this;
  119.     _running = false;
  120. }
  121.  
  122.  
  123. // Duplicator
  124. Agent::Agent(const Agent& c):
  125.     _pid(c._pid), _inputfp(0), _outputfp(0), _errorfp(0), 
  126.     _running(c._running),
  127.     _beingTerminated(c._beingTerminated), _lastStatus(c._lastStatus),
  128.     _terminateTimeOut(c._terminateTimeOut),
  129.     _hangupTimeOut(c._hangupTimeOut),
  130.     _killTimeOut(c._killTimeOut),
  131.     handlers(c.handlers), next(0), _path(c._path)
  132. {
  133.     // Assume running unless shown otherwise
  134.     setRunning();
  135. }
  136.  
  137.  
  138. void Agent::restoreParentIO()
  139. {
  140.     // Nothing specific to do here
  141. }
  142.  
  143. // start Agent
  144. void Agent::start()
  145. {
  146.     // Start child process if we're not listening to stdin
  147.     if (pid() >= 0)
  148.     startChildProcess();
  149.     else
  150.     setRunning();
  151. }
  152.  
  153. // Start the child process
  154. void Agent::startChildProcess()
  155. {
  156.     if (running())
  157.     {
  158.     // Kill whatever's still running there
  159.     terminate();
  160.     }
  161.  
  162.     if (setupCommunication())
  163.     {
  164.     raiseMsg("communication setup failed");
  165.     return;
  166.     }
  167.     
  168.     if ((_pid = fork()) == 0)
  169.     {
  170.     if (setupChildCommunication())
  171.     {
  172.         raiseMsg("child communication setup failed");
  173.         exit(EXIT_FAILURE);
  174.     }
  175.     
  176.     executeChild();
  177.     }
  178.  
  179.     if (pid() == -1)
  180.     {
  181.     _pid = 0;
  182.     raiseIOMsg("cannot fork");
  183.     return;
  184.     }
  185.  
  186.     if (setupParentCommunication())
  187.     {
  188.     raiseMsg("parent communication setup failed");
  189.     return;
  190.     }
  191.  
  192.     // agent is now set up and running
  193.     setRunning();
  194. }
  195.  
  196.  
  197. // Setup common communication
  198. int Agent::setupCommunication()
  199. {
  200.     // open pipes for stdin, stdout and stderr
  201.     if (pipe(to_child) < 0)
  202.     {
  203.     raiseIOMsg("cannot open stdin pipe");
  204.     return -1;
  205.     }
  206.  
  207.     if (pipe(to_parent) < 0)
  208.     {
  209.     raiseIOMsg("cannot open stdout pipe");
  210.     return -1;
  211.     }
  212.  
  213.     if (pipe(to_parent_error) < 0)
  214.     {
  215.     raiseIOMsg("cannot open stderr pipe");
  216.     return -1;
  217.     }
  218.  
  219.     return 0;
  220. }
  221.  
  222. // Setup child communication
  223. int Agent::setupChildCommunication()
  224. {
  225.     // I am the child:
  226.     // close unused pipe ends
  227.     close(to_child[WRITE]);
  228.     close(to_parent[READ]);
  229.     close(to_parent_error[READ]);
  230.  
  231.     // assign stdin to to_child, stdout to to_parent, and
  232.     // stderr to to_parent_error
  233.     dup2(to_child[READ], fileno(stdin));
  234.     close(to_child[READ]);
  235.  
  236.     dup2(to_parent[WRITE], fileno(stdout));
  237.     close(to_parent[WRITE]);
  238.  
  239.     dup2(to_parent_error[WRITE], fileno(stderr));
  240.     close(to_parent_error[WRITE]);
  241.  
  242.     return 0;
  243. }
  244.  
  245. // Setup parent communication
  246. int Agent::setupParentCommunication()
  247. {
  248.     // I am the parent: close unused pipe ends
  249.     close(to_child[READ]);
  250.     close(to_parent[WRITE]);
  251.     close(to_parent_error[WRITE]);
  252.  
  253.     // access remaining pipe ends via stream I/O
  254.     // using error, in and out...
  255.     _errorfp = fdopen(to_parent_error[READ], "r");
  256.     if (errorfp() == NULL)
  257.     {
  258.     raiseIOMsg("cannot fdopen child's stdin pipe");
  259.     terminate();
  260.     return -1;
  261.     }
  262.  
  263.     _inputfp = fdopen(to_parent[READ], "r");
  264.     if (inputfp() == NULL)
  265.     {
  266.     raiseIOMsg("cannot fdopen child's stdout pipe");
  267.     terminate();
  268.     return -1;
  269.     }
  270.  
  271.     _outputfp = fdopen(to_child[WRITE], "w");
  272.     if (outputfp() == NULL)
  273.     {
  274.     raiseIOMsg("cannot fdopen child's stderr pipe");
  275.     terminate();
  276.     return -1;
  277.     }
  278.  
  279.     return 0;
  280. }
  281.  
  282. // Actually execute the child
  283. void Agent::executeChild()
  284. {
  285.     // start child
  286.     string exec_str = "exec " + path();
  287.     char *exec_cmd = exec_str;
  288.     execl("/bin/sh", "sh", "-c", exec_cmd, (char *)0);
  289.  
  290.     // could not find child: send message to parent via stderr
  291.     perror("/bin/sh");
  292.     _exit(EXIT_FAILURE);
  293. }
  294.  
  295.  
  296. // process all status changes since last call and check if still running
  297. bool Agent::running()
  298. {
  299.     if (_running && pid() >= 0)
  300.     {
  301.     // Ignore interrupts for a while
  302.     SignalProc istat = SignalProc(signal(SIGINT,  SignalProc(SIG_IGN)));
  303.     SignalProc qstat = SignalProc(signal(SIGQUIT, SignalProc(SIG_IGN)));
  304.     SignalProc hstat = SignalProc(signal(SIGHUP,  SignalProc(SIG_IGN)));
  305.  
  306.     // Query current process state
  307.     pid_t r;
  308.     int status;
  309.     if ((r = waitpid(pid(), &status, WNOHANG)) > 0)
  310.     {
  311.         // Agent stopped or terminated
  312.         assert(r == pid());
  313.         hasNewStatus(status);
  314.     }
  315.     else if (r < 0)
  316.     {
  317.         if (errno == ECHILD)
  318.         {
  319.         // No such child: agent is not running
  320.         abort();
  321.         }
  322.         else
  323.         _raiseIOMsg("wait failed");
  324.     }
  325.  
  326.         // restore interrupts
  327.     signal(SIGINT,  istat);
  328.     signal(SIGQUIT, qstat);
  329.     signal(SIGHUP,  hstat);
  330.     }
  331.  
  332.     return _running;
  333. }
  334.  
  335.  
  336. // child status change
  337. void Agent::hasNewStatus(int state)
  338. {
  339.     _lastStatus = state;
  340.  
  341.     if (WIFEXITED(((state))) || WIFSIGNALED(((state))))
  342.     {
  343.     // agent died: inhibit further communication
  344.     abort();
  345.     }
  346. }
  347.  
  348.  
  349. // terminate process
  350. void Agent::terminate(bool onExit)
  351. {
  352.     if (onExit)
  353.     {
  354.     // We're exiting: call only the default handlers
  355.     removeAllHandlers();
  356.     addDefaultHandler(Panic);
  357.     addDefaultHandler(Died);
  358.     }
  359.  
  360.     if (!running())
  361.     {
  362.     restoreParentIO();
  363.     return;
  364.     }
  365.  
  366.     _beingTerminated = true;
  367.     if (onExit)
  368.     {
  369.     // close files
  370.     Agent::abort();
  371.     }
  372.     else
  373.     {
  374.     // call subclasses abort handlers
  375.     abort();
  376.     }
  377.     _beingTerminated = false;
  378.  
  379.     if (pid() >= 0)
  380.     {
  381.     // wait until we're terminated
  382.     if (onExit)
  383.         Agent::waitToTerminate();
  384.     else
  385.         waitToTerminate();
  386.     }
  387.  
  388.     // now, we're really done.
  389.     unsetRunning();
  390. }
  391.  
  392.  
  393. // send KILL signal
  394. void Agent::_kill(int sig)
  395. {
  396.     if (running() && pid() >= 0)
  397.     {
  398.     // Hasta la vista, agent
  399.  
  400.     if (kill(pid(), sig) < 0)
  401.         raiseIOMsg("Could not kill");
  402.     }
  403. }
  404.  
  405.  
  406. // Wait for agent to terminate, sending signals
  407. void Agent::waitToTerminate()
  408. {
  409.     int sig = 0;
  410.  
  411.     for (int seconds = 0; running(); seconds++)
  412.     {
  413.     sig = 0;
  414.  
  415.     if (seconds == terminateTimeOut())
  416.         sig = SIGTERM;
  417.  
  418.     if (seconds == hangupTimeOut())
  419.         sig = SIGHUP;
  420.  
  421.     if (seconds == killTimeOut())
  422.         sig = SIGKILL;
  423.  
  424.         if (sig)
  425.         _kill(sig);
  426.  
  427.         if (running())
  428.         sleep(1);
  429.     }
  430.  
  431.     if (sig)
  432.     raiseMsg(string("Agent wouldn't die (") + sigName(sig) + ")");
  433. }
  434.  
  435.  
  436. // Wait for agent to terminate, not sending signals
  437. void Agent::wait()
  438. {
  439.     while (running())
  440.     {
  441.     int status;
  442.     pid_t ret = waitpid(pid(), &status, 0);
  443.     if (ret > 0)
  444.     {
  445.         // Agent stopped or terminated
  446.         assert(ret == pid());
  447.         hasNewStatus(status);
  448.     }
  449.     }
  450. }
  451.  
  452.  
  453. // Close channel
  454. // This handles several file pointers addressing one file
  455. void Agent::closeChannel(FILE *fp)
  456. {
  457.     if (fp == 0)
  458.     return;
  459.  
  460.     bool err = (fclose(fp) == EOF);
  461.  
  462.     if (fp == inputfp())
  463.     {
  464.     _inputfp = 0;
  465.     if (err)
  466.         raiseIOMsg("couldn't close input channel");
  467.     }
  468.  
  469.     if (fp == errorfp())
  470.     {
  471.     _errorfp = 0;
  472.     if (err)
  473.         raiseIOMsg("couldn't close error channel");
  474.     }
  475.  
  476.     if (fp == outputfp())
  477.     {
  478.     _outputfp = 0;
  479.     if (err)
  480.         raiseIOMsg("couldn't close output channel");
  481.     }
  482. }
  483.  
  484. // send an EOF to agent
  485. void Agent::shutdown()
  486. {
  487.     // We NEVER close stdout and stderr
  488.     if (outputfp() == stdout || outputfp() == stderr)
  489.     return;
  490.  
  491.     // Close output pipe
  492.     closeChannel(outputfp());
  493. }
  494.  
  495. // EOF on input detected
  496. void Agent::inputEOF()
  497. {
  498.     // Check if we're still running
  499.     running();
  500.  
  501.     // Call handlers
  502.     callHandlers(InputEOF);
  503.  
  504.     // Clear error condition
  505.     if (inputfp() != 0)
  506.     clearerr(inputfp());
  507. }
  508.  
  509. // EOF on error detected
  510. void Agent::errorEOF()
  511. {
  512.     // Check if we're still running
  513.     running();
  514.  
  515.     // Call handlers
  516.     callHandlers(ErrorEOF);
  517.  
  518.     // Clear error condition
  519.     if (errorfp() != 0)
  520.     clearerr(errorfp());
  521. }
  522.  
  523. // Inhibit further communication
  524. void Agent::abort()
  525. {
  526.     restoreParentIO();
  527.  
  528.     // Close pipes.  We deliberately ignore any error messages here.
  529.     shutdown();
  530.     closeChannel(inputfp());
  531.     closeChannel(errorfp());
  532.  
  533.     if (!_beingTerminated)
  534.     {
  535.     // Declare agent as "not running"
  536.     unsetRunning();
  537.     }
  538.  
  539.     if (_lastStatus >= 0)
  540.     {
  541.     // Call "Died" message handlers
  542.     callHandlers(Died, statusName(_lastStatus));
  543.     _lastStatus = -1;
  544.     }
  545. }
  546.  
  547. // Destructor
  548. Agent::~Agent()
  549. {
  550.     // terminate agent gracefully
  551.     terminate();
  552. }
  553.