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 / AsyncAgent.C < prev    next >
C/C++ Source or Header  |  1998-10-25  |  9KB  |  412 lines

  1. // $Id: AsyncAgent.C,v 1.24 1998/10/25 19:44:46 zeller Exp $
  2. // Asynchron Agent Interface
  3.  
  4. // Copyright (C) 1995-1998 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 AsyncAgent_rcsid[] = 
  30.     "$Id: AsyncAgent.C,v 1.24 1998/10/25 19:44:46 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36.  
  37. #include "AsyncAgent.h"
  38. #include "TimeOut.h"
  39. #include "misc.h"
  40.  
  41. #include <sys/types.h>
  42. #include <strstream.h>
  43. #include <unistd.h>
  44. #include <stdlib.h>
  45.  
  46. DEFINE_TYPE_INFO_1(AsyncAgent, Agent)
  47. DEFINE_TYPE_INFO_0(AsyncAgentWorkProc)
  48. DEFINE_TYPE_INFO_0(AsyncAgentWorkProcInfo)
  49.  
  50. // Process child status change
  51.  
  52. #if ASYNC_CHILD_STATUS_CHANGE
  53. void AsyncAgent::_childStatusChange(XtPointer client_data, XtSignalId *)
  54. {
  55.     AsyncAgent *a = (AsyncAgent *)client_data;
  56.  
  57.     // if we have a dummy agent running, prefer this one
  58.     Agent *agent = Agent::runningAgents.search(a->pid());
  59.     if (agent == 0)
  60.     agent = a;
  61.  
  62.     agent->commit();
  63. }
  64. #endif
  65.  
  66. void AsyncAgent::statusChange()
  67. {
  68.     // Set new agent state
  69.     hasNewStatus(new_status);
  70.  
  71.     // Check if we're still running
  72.     running();
  73.  
  74.     // Clear `pending' flag
  75.     status_change_pending = false;
  76. }
  77.  
  78. void AsyncAgent::childStatusChange(Agent *agent, void *, void *call_data)
  79. {
  80.     AsyncAgent *a = (AsyncAgent *)agent;
  81.     a->new_status  = (int)(long)call_data;
  82.  
  83.     // Process status change when back in event loop
  84. #if ASYNC_CHILD_STATUS_CHANGE
  85.     // Since we're called from a handler, this is the safe way to do it
  86.     XtNoticeSignal(a->signal_id);
  87. #endif
  88.  
  89.     // In X11R5 and earlier, we cannot call any Xt function -- simply
  90.     // wait for the next AgentManager::commit()
  91.     a->status_change_pending = true;
  92. }
  93.  
  94. void AsyncAgent::commit()
  95. {
  96.     if (status_change_pending)
  97.     statusChange();
  98. }
  99.  
  100.  
  101. // data from agent is ready to be read
  102. void AsyncAgent::somethingHappened(XtPointer client_data, int *fid,
  103.     XtInputId *inputId)
  104. {
  105.     AsyncAgent *agent = (AsyncAgent *)client_data;
  106.     agent->dispatch(fid, inputId);
  107. }
  108.  
  109.  
  110. // communication handlers
  111.  
  112. // Initialize handlers
  113. void AsyncAgent::initHandlers()
  114. {
  115.     for (unsigned type = 0; type < AsyncAgent_NHandlers; type++)
  116.     {
  117.     _handlers[type] = 0;
  118.     _ids[type] = 0;
  119.     }
  120.  
  121. #if ASYNC_CHILD_STATUS_CHANGE
  122.     signal_id = XtAppAddSignal(appContext(), _childStatusChange, 
  123.                    XtPointer(this));
  124. #endif
  125. }
  126.  
  127. // Clear handlers
  128. void AsyncAgent::clearHandlers()
  129. {
  130.     for (unsigned type = 0; type < AsyncAgent_NHandlers; type++)
  131.     setHandler(type);
  132.  
  133. #if ASYNC_CHILD_STATUS_CHANGE
  134.     XtRemoveSignal(signal_id);
  135. #endif
  136. }
  137.  
  138. // Process "Death of child" signal as soon as possible
  139. void AsyncAgent::addDeathOfChildHandler()
  140. {
  141.     addHandler(_Died, childStatusChange, XtPointer(this));
  142. }
  143.  
  144.  
  145. // Set Handler
  146. AsyncAgentHandler AsyncAgent::setHandler(unsigned type, AsyncAgentHandler h)
  147. {
  148.     // Remove old handler if set
  149.     AsyncAgentHandler old_handler = handler(type);
  150.     if (id(type))
  151.     {
  152.     XtRemoveInput(id(type));
  153.     _ids[type] = 0;
  154.     }
  155.  
  156.     // Register new handler
  157.     FILE *sourcefp      = 0;
  158.     XtPointer condition = 0;
  159.  
  160.     switch(type)
  161.     {
  162.     case OutputReady:
  163.         sourcefp  = outputfp();
  164.         condition = XtPointer(XtInputWriteMask);
  165.         break;
  166.  
  167.     case InputReady:
  168.         sourcefp  = inputfp();
  169.         condition = XtPointer(XtInputReadMask);
  170.         break;
  171.  
  172.     case ErrorReady:
  173.         sourcefp  = errorfp();
  174.         condition = XtPointer(XtInputReadMask);
  175.         break;
  176.  
  177.     case OutputException:
  178.         sourcefp  = outputfp();
  179.         condition = XtPointer(XtInputExceptMask);
  180.         break;
  181.  
  182.     case InputException:
  183.         sourcefp  = inputfp();
  184.         condition = XtPointer(XtInputExceptMask);
  185.         break;
  186.  
  187.     case ErrorException:
  188.         sourcefp  = errorfp();
  189.         condition = XtPointer(XtInputExceptMask);
  190.         break;
  191.  
  192.     default:
  193.         assert(0);        // illegal type
  194.         ::abort();
  195.     }
  196.  
  197.     _handlers[type] = h;
  198.  
  199.     if (h && sourcefp)
  200.     _ids[type] = XtAppAddInput(appContext(), fileno(sourcefp), condition,
  201.         somethingHappened, (XtPointer)this);
  202.  
  203.     return old_handler;
  204. }
  205.  
  206.  
  207. // Dispatcher
  208. void AsyncAgent::dispatch(int *, XtInputId *inputId)
  209. {
  210.     // search handler
  211.     unsigned type;
  212.     for (type = 0; type < AsyncAgent_NHandlers && id(type) != *inputId; type++)
  213.     ;
  214.     
  215.     // call it
  216.     if (type < AsyncAgent_NHandlers)
  217.     {
  218.     (*(handler(type)))(this);
  219.     }
  220. #if 0
  221.     else
  222.     {
  223.     ostrstream os;
  224.     os << "unhandled input id " << *inputId;
  225.     string s(os);
  226.     raiseMsg(s);
  227.     }
  228. #endif
  229. }
  230.  
  231. // Abort
  232. void AsyncAgent::abort()
  233. {
  234.     // remove previously installed handlers
  235.     for (unsigned type = 0; type < AsyncAgent_NHandlers; type++)
  236.     removeInput(type);
  237.  
  238.     // inhibit further communication
  239.     Agent::abort();
  240. }
  241.  
  242.  
  243. // Close a channel
  244. void AsyncAgent::closeChannel(FILE *fp)
  245. {
  246.     if (fp)
  247.     {
  248.     if (fp == inputfp())
  249.     {
  250.         removeInput(InputReady);
  251.         removeInput(InputException);
  252.     }
  253.     if (fp == errorfp())
  254.     {
  255.         removeInput(ErrorReady);
  256.         removeInput(ErrorException);
  257.     }
  258.     if (fp == outputfp())
  259.     {
  260.         removeInput(OutputReady);
  261.         removeInput(OutputException);
  262.     }
  263.     }
  264.  
  265.     Agent::closeChannel(fp);
  266. }
  267.  
  268.  
  269. // Terminator
  270. void AsyncAgent::terminateProcess(XtPointer client_data, XtIntervalId *)
  271. {
  272.     pid_t pid = (pid_t)(long)client_data;
  273.     kill(pid, SIGTERM);
  274. }
  275.  
  276. void AsyncAgent::hangupProcess(XtPointer client_data, XtIntervalId *)
  277.     pid_t pid = (pid_t)(long)client_data;
  278.     kill(pid, SIGHUP);
  279. }
  280.  
  281. void AsyncAgent::killProcess(XtPointer client_data, XtIntervalId *)
  282. {
  283.     pid_t pid = (pid_t)(long)client_data;
  284.     kill(pid, SIGKILL);
  285. }
  286.  
  287. void AsyncAgent::terminate(bool onExit)
  288. {
  289.     bool was_running = (pid() > 0 && running());
  290.  
  291.     Agent::terminate(onExit);
  292.  
  293.     if (onExit)
  294.     {
  295.     Agent::waitToTerminate();
  296.     }
  297.     else if (was_running && !killing_asynchronously)
  298.     {
  299.     // Kill asynchronously.  We don't want to wait until the
  300.     // process dies, so we just send out some signals and pretend
  301.     // the process has terminated gracefully.
  302.     killing_asynchronously = true;
  303.  
  304.     if (terminateTimeOut() >= 0)
  305.         XtAppAddTimeOut(appContext(), terminateTimeOut() * 1000,
  306.                 terminateProcess, XtPointer(pid()));
  307.  
  308.     if (hangupTimeOut() >= 0)
  309.         XtAppAddTimeOut(appContext(), hangupTimeOut() * 1000,
  310.                 hangupProcess, XtPointer(pid()));
  311.  
  312.     if (killTimeOut() >= 0)
  313.         XtAppAddTimeOut(appContext(), killTimeOut() * 1000,
  314.                 killProcess, XtPointer(pid()));
  315.  
  316.     // Inhibit further communication
  317.     hasNewStatus(-1);
  318.     abort();
  319.     callHandlers(Died, "Exit 0");
  320.     }
  321. }
  322.  
  323. void AsyncAgent::waitToTerminate()
  324. {
  325.     // Do nothing
  326. }
  327.  
  328.  
  329. // Delayed Event Handling
  330.  
  331. void AsyncAgent::callTheHandlersIfIdle(XtPointer client_data, XtIntervalId *)
  332. {
  333.     AsyncAgentWorkProcInfo *info = (AsyncAgentWorkProcInfo *)client_data;
  334.  
  335.     if (info->agent->isIdle())
  336.     {
  337.     // call handlers
  338.     info->agent->callHandlers(info->type, info->call_data);
  339.     info->agent->deleteWorkProc(info, false);
  340.     }
  341.     else
  342.     {
  343.     // try again in 10 ms
  344.     XtAppAddTimeOut(info->agent->appContext(), 10, callTheHandlersIfIdle,
  345.             XtPointer(info));
  346.     }
  347. }
  348.  
  349. Boolean AsyncAgent::callTheHandlers(XtPointer client_data)
  350. {
  351.     AsyncAgentWorkProcInfo *info = (AsyncAgentWorkProcInfo *)client_data;
  352.     XtAppAddTimeOut(info->agent->appContext(), 1, callTheHandlersIfIdle,
  353.             XtPointer(info));
  354.  
  355.     return true;
  356. }
  357.  
  358. void AsyncAgent::callHandlersWhenIdle(int type, void *call_data)
  359. {
  360.     // Create required callback information
  361.     AsyncAgentWorkProcInfo *info =
  362.     new AsyncAgentWorkProcInfo(this, type, call_data);
  363.  
  364.     // Register background work procedure (called when idle)
  365.     XtWorkProcId workProcId =
  366.     XtAppAddWorkProc(appContext(), callTheHandlers, info);
  367.  
  368.     // Memoize work procedure so that it may be cancelled
  369.     workProcs = new AsyncAgentWorkProc(workProcId, info, workProcs);
  370. }
  371.  
  372. void AsyncAgent::deleteWorkProc(AsyncAgentWorkProcInfo *info,
  373.                 bool remove)
  374. {
  375.     AsyncAgentWorkProc *prev = 0;
  376.     for (AsyncAgentWorkProc *c = workProcs; c != 0; c = c->next)
  377.     {
  378.         if (c->info == info)
  379.         {
  380.             if (prev == 0)
  381.                 workProcs = c->next;
  382.             else
  383.                 prev->next = c->next;
  384.  
  385.             if (remove)
  386.         XtRemoveWorkProc(c->proc_id);
  387.         delete c->info;
  388.         delete c;
  389.         }
  390.         else
  391.         {
  392.             prev = c;
  393.         }
  394.     }
  395. }
  396.  
  397. void AsyncAgent::deleteAllWorkProcs()
  398. {
  399.     while (workProcs)
  400.     deleteWorkProc(workProcs->info);
  401. }
  402.  
  403.  
  404. // reference XtToolkitInitialize to avoid these stupid
  405. // "ld.so: Undefined symbol: __XtInherit" messages
  406.  
  407. void _just_make_sure_XtInherit_is_loaded()
  408. {
  409.     XtToolkitInitialize();
  410. }
  411.