home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 620.lha / ShellTimer / ShellTimerDaemon.c < prev    next >
C/C++ Source or Header  |  1992-02-05  |  9KB  |  456 lines

  1. ;/* Execute me to Compile and link ShellTimerDaemon.c
  2. shelltimer start verbose
  3. ; For debugging, use the following command:
  4. ; lc -. -O -ms -b1 -cfistq -j73 -v -Lit -d3 -isrc:memlib -dMWDEBUG=1 ShellTimerDaemon.c
  5. ; For production, use the following command:
  6. lc -. -O -ms -b1 -cfistq -j73 -Lit ShellTimerDaemon.c
  7. echo "Time to compile and link: " NOLINE
  8. shelltimer stop
  9. quit
  10. */
  11.  
  12. /***
  13. ****    SHELLTIMERDAEMON.C
  14. ****
  15. ****    Creation:        John Lindwall
  16. ****                    19 Jan 1992
  17. ****
  18. ****    Description:    The timer server for the ShellTimer system.
  19. ****        This daemon accepts requests from the client program, ShellTimer.
  20. ****        It maintains a dynamic list of timer sessions.
  21. ****
  22. ****        When the client    requests that a timer session be started, the
  23. ****        daemon records the shell PID of the client and the current time
  24. ****        in an ST_Node data structure.  Later client requests can query
  25. ****        the value of the timer, cancel the timer session, and stop the
  26. ****        the timer.  The daemon can also be commanded to terminate.
  27. ****        Elapsed timer values are computed by the daemon and sent back to
  28. ****        client.
  29. ****
  30. ****        The AmigaDOS Break command can also be used to terminate the
  31. ****        daemon, by sending it a Control-C.
  32. ****
  33. ****        As written, this program requires AmigaDOS 2.04.  It could
  34. ****        be modified to run under 1.3, but I don't have the inclination.
  35. ****        2.0 features used include the AllocVec() call (love it!).
  36. ****
  37. ****        See ShellTimer.doc for more information.
  38. ****
  39. ****        The ShellTimer system (which includes the programs
  40. ****        ShellTimerDaemon and ShellTimer) is released into the Public
  41. ****        Domain by the author, John Lindwall.  I ask that the archive
  42. ****        be kept intact with the docs and the source code.  Bug reports
  43. ****        should be sent to me at johnl@crash.cts.com.
  44. ****
  45. ****    Note:    The code is not commented ... sorry.
  46. ****
  47. ****    Overhauls:
  48. ***/
  49.  
  50.  
  51. #include <exec/types.h>
  52. #include <exec/ports.h>
  53. #include <exec/memory.h>
  54. #include <exec/libraries.h>
  55. #include <dos/dos.h>
  56. #include <devices/timer.h>
  57.  
  58. #include <proto/exec.h>
  59. #include <proto/timer.h>
  60. #include <proto/dos.h>
  61.  
  62. #include <stdlib.h>
  63. #include <stdio.h>
  64. #include <string.h>
  65.  
  66. #include "ShellTimer.h"
  67.  
  68. #define APPNAME            "ShellTimerDaemon"
  69. #define ADOS2_VERSION    37
  70.  
  71. void CleanExit(char *, int);
  72. void SetupTimerDevice(void);
  73. void SetupMessagePort(void);
  74. void ProcessMessages(void);
  75. void StartTimer(struct ST_Message *msg);
  76. void StopTimer(struct ST_Message *msg);
  77. void QueryTimer(struct ST_Message *msg);
  78. void CancelTimer(struct ST_Message *msg);
  79. void SetupRequestList(void);
  80. void DestroyRequestList(void);
  81. BOOL InsertRequest(int requestID, struct timeval *startTime);
  82. struct ST_Node *RemoveRequest(int requestID);
  83. BOOL InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
  84.     struct timeval *currentTime);
  85. void ToggleTimer(struct ST_Message *msg);
  86. void Print(char *s);
  87.  
  88. struct ST_Node
  89. {
  90.     struct Node node;
  91.     int requestID;
  92.     struct timeval startTime;
  93. };
  94.  
  95. struct List requestList;
  96.  
  97. struct Library *TimerBase;
  98. struct timerequest *TimerIO;
  99. struct timeval *time;
  100. struct MsgPort *publicPort;
  101.  
  102. UBYTE versionTag[] = "\0$VER: " APPNAME " 1.0 (03.02.92) by John Lindwall\n";
  103.  
  104. /* Disable SAS/C Control-C/D checking */
  105. int CXBRK(void) { return(0); }
  106. int chkabort(void) { return(0); }
  107.  
  108. void
  109. main(int argc, char *argv[])
  110. {
  111.     extern struct DOSLibrary *DOSBase;
  112.  
  113.     if( DOSBase->dl_lib.lib_Version < ADOS2_VERSION )
  114.     {
  115.         CleanExit("AmigaDOS 2.0 required!\n", -20);
  116.     }
  117.     Forbid();
  118.     if( FindPort(ST_PORT) )
  119.     {
  120.         Permit();
  121.         CleanExit("Daemon already loaded!\n", -5);
  122.     }
  123.     Permit();
  124.     if( argc != 0 )
  125.     {
  126.         Print(&versionTag[7]);
  127.     }
  128. #ifdef MWDEBUG
  129.     MWInit(NULL, 0, "CON:0/0/639/199/MemLib");
  130. #endif
  131.     SetupTimerDevice();
  132.     SetupRequestList();
  133.     SetupMessagePort();
  134.     ProcessMessages();
  135.     CleanExit("Exiting.\n", 0);
  136. }
  137.  
  138. void
  139. SetupRequestList(void)
  140. {
  141.     NewList(&requestList);
  142. }
  143.  
  144. void
  145. DestroyRequestList(void)
  146. {
  147.     struct ST_Node *node;
  148.  
  149.     while( (node = (struct ST_Node *) RemHead(&requestList)) != NULL )
  150.     {
  151.         FreeVec(node);
  152.     }
  153. }
  154.  
  155. BOOL
  156. InsertRequest(int requestID, struct timeval *startTime)
  157. {
  158.     struct ST_Node *node;
  159.  
  160.     if( (node = AllocVec(sizeof(struct ST_Node), MEMF_ANY)) == NULL )
  161.     {
  162.         return(FALSE);
  163.     }
  164.     node->requestID = requestID;
  165.     node->startTime.tv_secs = startTime->tv_secs;
  166.     node->startTime.tv_micro = startTime->tv_micro;
  167.     Enqueue(&requestList, (struct Node *)node);
  168.     return(TRUE);
  169. }
  170.  
  171. struct ST_Node *
  172. RemoveRequest(int requestID)
  173. {
  174.     struct ST_Node *foundNode;
  175.     BOOL match;
  176.     static struct ST_Node copyOfFoundNode;
  177.  
  178.     if( IsListEmpty(&requestList) )
  179.     {
  180.         return(NULL);
  181.     }
  182.     match = FALSE;
  183.     foundNode = (struct ST_Node *) requestList.lh_Head;
  184.  
  185.     do
  186.     {
  187.         if( requestID == foundNode->requestID )
  188.         {
  189.             match = TRUE;
  190.             break;
  191.         }
  192.         foundNode = (struct ST_Node *) foundNode->node.ln_Succ;
  193.     }
  194.     while( ! match && foundNode->node.ln_Succ != NULL );
  195.     if( match )
  196.     {
  197.         Remove((struct Node *)foundNode);
  198.         CopyMem(foundNode, ©OfFoundNode, sizeof(struct ST_Node));
  199.         FreeVec(foundNode);
  200.         return(©OfFoundNode);
  201.     }
  202.     else
  203.     {
  204.         return(NULL);
  205.     }
  206. }
  207.  
  208.  
  209. void
  210. ProcessMessages(void)
  211. {
  212.     ULONG sigRecvd;
  213.     BOOL done = FALSE;
  214.     struct ST_Message *msg;
  215.  
  216.     while( ! done )
  217.     {
  218.         sigRecvd = Wait(SIGBREAKF_CTRL_C | 1L << publicPort->mp_SigBit);
  219.         if( sigRecvd & SIGBREAKF_CTRL_C )
  220.         {
  221.             done = TRUE;
  222.         }
  223.         else
  224.         {
  225.             msg = (struct ST_Message *) GetMsg(publicPort);
  226. #ifdef DEBUG
  227.             printf("STD: I got a message! : %ld\n", msg->code); fflush(stdout);
  228. #endif
  229.             switch( msg->code )
  230.             {
  231.                 case ST_START:
  232.                     StartTimer(msg);
  233.                     break;
  234.                 case ST_STOP:
  235.                     StopTimer(msg);
  236.                     break;
  237.                 case ST_CANCEL:
  238.                     CancelTimer(msg);
  239.                     break;
  240.                 case ST_TOGGLE:
  241.                     ToggleTimer(msg);
  242.                     break;
  243.                 case ST_QUERY:
  244.                     QueryTimer(msg);
  245.                     break;
  246.                 case ST_QUIT:
  247.                     done = TRUE;
  248.                     break;
  249.             }
  250.             ReplyMsg((struct Message *)msg);
  251.         }
  252.     }
  253. }
  254.  
  255. void
  256. StartTimer(struct ST_Message *msg)
  257. {
  258.     struct timeval currentTime;
  259.  
  260.     GetSysTime(¤tTime);
  261.     RemoveRequest(msg->requestID);
  262.     if( InsertRequest(msg->requestID, ¤tTime) )
  263.     {
  264.         msg->startTime.tv_secs  = currentTime.tv_secs;
  265.         msg->startTime.tv_micro = currentTime.tv_micro;
  266.     }
  267.     else
  268.     {
  269.         msg->code = ST_ERR;
  270.     }
  271. }
  272.  
  273. void
  274. StopTimer(struct ST_Message *msg)
  275. {
  276.     struct ST_Node *request;
  277.     struct timeval currentTime;
  278.  
  279.     GetSysTime(¤tTime);
  280.     if( (request = RemoveRequest(msg->requestID)) != NULL )
  281.     {
  282.         if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
  283.         {
  284.             msg->code = ST_TIMEWARP;
  285.         }
  286.     }
  287.     else
  288.     {
  289.         msg->code = ST_ERR_NO_PENDING;
  290.     }
  291. }
  292.  
  293. void
  294. QueryTimer(struct ST_Message *msg)
  295. {
  296.     struct ST_Node *request;
  297.     struct timeval currentTime, trueStartTime;
  298.  
  299.     GetSysTime(¤tTime);
  300.     if( (request = RemoveRequest(msg->requestID)) != NULL )
  301.     {
  302.         trueStartTime.tv_secs = request->startTime.tv_secs;
  303.         trueStartTime.tv_micro = request->startTime.tv_micro;
  304.         if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
  305.         {
  306.             msg->code = ST_TIMEWARP;
  307.             return;
  308.         }
  309.     }
  310.     else
  311.     {
  312.         msg->code = ST_ERR_NO_PENDING;
  313.         return;
  314.     }
  315.     if( ! InsertRequest(msg->requestID, &trueStartTime) )
  316.     {
  317.         msg->code = ST_ERR;
  318.     }
  319. }
  320.  
  321. BOOL
  322. InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
  323.     struct timeval *currentTime)
  324. {
  325.     if( CmpTime(currentTime, &(request->startTime)) != -1 )
  326.     {
  327.         return(FALSE);
  328.     }
  329.     msg->endTime.tv_secs =  currentTime->tv_secs;
  330.     msg->endTime.tv_micro = currentTime->tv_micro;
  331.     SubTime(currentTime, &(request->startTime));
  332.     msg->diffTime.tv_secs =  currentTime->tv_secs;
  333.     msg->diffTime.tv_micro = currentTime->tv_micro;
  334.     return(TRUE);
  335. }
  336.  
  337.  
  338. void
  339. CancelTimer(struct ST_Message *msg)
  340. {
  341.     struct ST_Node *request;
  342.  
  343.     if( (request = RemoveRequest(msg->requestID)) == NULL )
  344.     {
  345.         msg->code = ST_ERR;
  346.     }
  347. }
  348.  
  349. void
  350. ToggleTimer(struct ST_Message *msg)
  351. {
  352.     struct ST_Node *request;
  353.     struct timeval currentTime;
  354.  
  355.     GetSysTime(¤tTime);
  356.     if( (request = RemoveRequest(msg->requestID)) != NULL )
  357.     {
  358.         if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
  359.         {
  360.             msg->code = ST_TIMEWARP;
  361.         }
  362.         else
  363.         {
  364.             msg->code = ST_STOP;
  365.         }
  366.     }
  367.     else
  368.     {
  369.         if( InsertRequest(msg->requestID, ¤tTime) )
  370.         {
  371.             msg->startTime.tv_secs  = currentTime.tv_secs;
  372.             msg->startTime.tv_micro = currentTime.tv_micro;
  373.             msg->code = ST_START;
  374.         }
  375.         else
  376.         {
  377.             msg->code = ST_ERR;
  378.         }
  379.     }
  380. }
  381.  
  382. void
  383. SetupMessagePort(void)
  384. {
  385.     if( (publicPort = CreatePort(ST_PORT, 0)) == NULL )
  386.     {
  387.         CleanExit("Can't open public message port\n", -3);
  388.     }
  389. }
  390.  
  391. void
  392. SetupTimerDevice(void)
  393. {
  394.     LONG error;
  395.  
  396.     TimerIO = (struct timerequest *)
  397.         AllocVec(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR);
  398.     time = (struct timeval *)
  399.         AllocVec(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR);
  400.     if( TimerIO    == NULL || time == NULL )
  401.     {
  402.         CleanExit("Out of memory\n", -1);
  403.     }
  404.     if( error = OpenDevice(TIMERNAME, UNIT_MICROHZ,
  405.         (struct IORequest *) TimerIO, 0L) )
  406.     {
  407.         CleanExit("Can't open timer device\n", -2);
  408.     }
  409.     TimerBase = (struct Library *) TimerIO->tr_node.io_Device;
  410. }
  411.  
  412. void
  413. CleanExit(char *string, int returnCode)
  414. {
  415.     struct ST_Message *msg;
  416.  
  417.     if( string != NULL )
  418.     {
  419.         Print(APPNAME ": ");
  420.         Print(string);
  421.     }
  422.  
  423.     DestroyRequestList();
  424.     if( publicPort )
  425.     {
  426.         while( msg = (struct ST_Message *) GetMsg(publicPort) )
  427.         {
  428.             msg->code = ST_ERR;
  429.             ReplyMsg((struct Message *)msg);
  430.         }
  431.         DeletePort(publicPort);
  432.     }
  433.     if( TimerBase )
  434.     {
  435.         CloseDevice((struct IORequest *) TimerIO);
  436.     }
  437.     if( TimerIO )
  438.     {
  439.         FreeVec(TimerIO);
  440.     }
  441.     if( time )
  442.     {
  443.         FreeVec(time);
  444.     }
  445. #ifdef MWDEBUG
  446.     MWTerm();
  447. #endif
  448.     exit(returnCode);
  449. }
  450.  
  451. void
  452. Print(char *string)
  453. {
  454.     Write(Output(), string, strlen(string));
  455. }
  456.