home *** CD-ROM | disk | FTP | other *** search
- ;/* Execute me to Compile and link ShellTimerDaemon.c
- shelltimer start verbose
- ; For debugging, use the following command:
- ; lc -. -O -ms -b1 -cfistq -j73 -v -Lit -d3 -isrc:memlib -dMWDEBUG=1 ShellTimerDaemon.c
- ; For production, use the following command:
- lc -. -O -ms -b1 -cfistq -j73 -Lit ShellTimerDaemon.c
- echo "Time to compile and link: " NOLINE
- shelltimer stop
- quit
- */
-
- /***
- **** SHELLTIMERDAEMON.C
- ****
- **** Creation: John Lindwall
- **** 19 Jan 1992
- ****
- **** Description: The timer server for the ShellTimer system.
- **** This daemon accepts requests from the client program, ShellTimer.
- **** It maintains a dynamic list of timer sessions.
- ****
- **** When the client requests that a timer session be started, the
- **** daemon records the shell PID of the client and the current time
- **** in an ST_Node data structure. Later client requests can query
- **** the value of the timer, cancel the timer session, and stop the
- **** the timer. The daemon can also be commanded to terminate.
- **** Elapsed timer values are computed by the daemon and sent back to
- **** client.
- ****
- **** The AmigaDOS Break command can also be used to terminate the
- **** daemon, by sending it a Control-C.
- ****
- **** As written, this program requires AmigaDOS 2.04. It could
- **** be modified to run under 1.3, but I don't have the inclination.
- **** 2.0 features used include the AllocVec() call (love it!).
- ****
- **** See ShellTimer.doc for more information.
- ****
- **** The ShellTimer system (which includes the programs
- **** ShellTimerDaemon and ShellTimer) is released into the Public
- **** Domain by the author, John Lindwall. I ask that the archive
- **** be kept intact with the docs and the source code. Bug reports
- **** should be sent to me at johnl@crash.cts.com.
- ****
- **** Note: The code is not commented ... sorry.
- ****
- **** Overhauls:
- ***/
-
-
- #include <exec/types.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <dos/dos.h>
- #include <devices/timer.h>
-
- #include <proto/exec.h>
- #include <proto/timer.h>
- #include <proto/dos.h>
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- #include "ShellTimer.h"
-
- #define APPNAME "ShellTimerDaemon"
- #define ADOS2_VERSION 37
-
- void CleanExit(char *, int);
- void SetupTimerDevice(void);
- void SetupMessagePort(void);
- void ProcessMessages(void);
- void StartTimer(struct ST_Message *msg);
- void StopTimer(struct ST_Message *msg);
- void QueryTimer(struct ST_Message *msg);
- void CancelTimer(struct ST_Message *msg);
- void SetupRequestList(void);
- void DestroyRequestList(void);
- BOOL InsertRequest(int requestID, struct timeval *startTime);
- struct ST_Node *RemoveRequest(int requestID);
- BOOL InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
- struct timeval *currentTime);
- void ToggleTimer(struct ST_Message *msg);
- void Print(char *s);
-
- struct ST_Node
- {
- struct Node node;
- int requestID;
- struct timeval startTime;
- };
-
- struct List requestList;
-
- struct Library *TimerBase;
- struct timerequest *TimerIO;
- struct timeval *time;
- struct MsgPort *publicPort;
-
- UBYTE versionTag[] = "\0$VER: " APPNAME " 1.0 (03.02.92) by John Lindwall\n";
-
- /* Disable SAS/C Control-C/D checking */
- int CXBRK(void) { return(0); }
- int chkabort(void) { return(0); }
-
- void
- main(int argc, char *argv[])
- {
- extern struct DOSLibrary *DOSBase;
-
- if( DOSBase->dl_lib.lib_Version < ADOS2_VERSION )
- {
- CleanExit("AmigaDOS 2.0 required!\n", -20);
- }
- Forbid();
- if( FindPort(ST_PORT) )
- {
- Permit();
- CleanExit("Daemon already loaded!\n", -5);
- }
- Permit();
- if( argc != 0 )
- {
- Print(&versionTag[7]);
- }
- #ifdef MWDEBUG
- MWInit(NULL, 0, "CON:0/0/639/199/MemLib");
- #endif
- SetupTimerDevice();
- SetupRequestList();
- SetupMessagePort();
- ProcessMessages();
- CleanExit("Exiting.\n", 0);
- }
-
- void
- SetupRequestList(void)
- {
- NewList(&requestList);
- }
-
- void
- DestroyRequestList(void)
- {
- struct ST_Node *node;
-
- while( (node = (struct ST_Node *) RemHead(&requestList)) != NULL )
- {
- FreeVec(node);
- }
- }
-
- BOOL
- InsertRequest(int requestID, struct timeval *startTime)
- {
- struct ST_Node *node;
-
- if( (node = AllocVec(sizeof(struct ST_Node), MEMF_ANY)) == NULL )
- {
- return(FALSE);
- }
- node->requestID = requestID;
- node->startTime.tv_secs = startTime->tv_secs;
- node->startTime.tv_micro = startTime->tv_micro;
- Enqueue(&requestList, (struct Node *)node);
- return(TRUE);
- }
-
- struct ST_Node *
- RemoveRequest(int requestID)
- {
- struct ST_Node *foundNode;
- BOOL match;
- static struct ST_Node copyOfFoundNode;
-
- if( IsListEmpty(&requestList) )
- {
- return(NULL);
- }
- match = FALSE;
- foundNode = (struct ST_Node *) requestList.lh_Head;
-
- do
- {
- if( requestID == foundNode->requestID )
- {
- match = TRUE;
- break;
- }
- foundNode = (struct ST_Node *) foundNode->node.ln_Succ;
- }
- while( ! match && foundNode->node.ln_Succ != NULL );
- if( match )
- {
- Remove((struct Node *)foundNode);
- CopyMem(foundNode, ©OfFoundNode, sizeof(struct ST_Node));
- FreeVec(foundNode);
- return(©OfFoundNode);
- }
- else
- {
- return(NULL);
- }
- }
-
-
- void
- ProcessMessages(void)
- {
- ULONG sigRecvd;
- BOOL done = FALSE;
- struct ST_Message *msg;
-
- while( ! done )
- {
- sigRecvd = Wait(SIGBREAKF_CTRL_C | 1L << publicPort->mp_SigBit);
- if( sigRecvd & SIGBREAKF_CTRL_C )
- {
- done = TRUE;
- }
- else
- {
- msg = (struct ST_Message *) GetMsg(publicPort);
- #ifdef DEBUG
- printf("STD: I got a message! : %ld\n", msg->code); fflush(stdout);
- #endif
- switch( msg->code )
- {
- case ST_START:
- StartTimer(msg);
- break;
- case ST_STOP:
- StopTimer(msg);
- break;
- case ST_CANCEL:
- CancelTimer(msg);
- break;
- case ST_TOGGLE:
- ToggleTimer(msg);
- break;
- case ST_QUERY:
- QueryTimer(msg);
- break;
- case ST_QUIT:
- done = TRUE;
- break;
- }
- ReplyMsg((struct Message *)msg);
- }
- }
- }
-
- void
- StartTimer(struct ST_Message *msg)
- {
- struct timeval currentTime;
-
- GetSysTime(¤tTime);
- RemoveRequest(msg->requestID);
- if( InsertRequest(msg->requestID, ¤tTime) )
- {
- msg->startTime.tv_secs = currentTime.tv_secs;
- msg->startTime.tv_micro = currentTime.tv_micro;
- }
- else
- {
- msg->code = ST_ERR;
- }
- }
-
- void
- StopTimer(struct ST_Message *msg)
- {
- struct ST_Node *request;
- struct timeval currentTime;
-
- GetSysTime(¤tTime);
- if( (request = RemoveRequest(msg->requestID)) != NULL )
- {
- if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
- {
- msg->code = ST_TIMEWARP;
- }
- }
- else
- {
- msg->code = ST_ERR_NO_PENDING;
- }
- }
-
- void
- QueryTimer(struct ST_Message *msg)
- {
- struct ST_Node *request;
- struct timeval currentTime, trueStartTime;
-
- GetSysTime(¤tTime);
- if( (request = RemoveRequest(msg->requestID)) != NULL )
- {
- trueStartTime.tv_secs = request->startTime.tv_secs;
- trueStartTime.tv_micro = request->startTime.tv_micro;
- if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
- {
- msg->code = ST_TIMEWARP;
- return;
- }
- }
- else
- {
- msg->code = ST_ERR_NO_PENDING;
- return;
- }
- if( ! InsertRequest(msg->requestID, &trueStartTime) )
- {
- msg->code = ST_ERR;
- }
- }
-
- BOOL
- InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
- struct timeval *currentTime)
- {
- if( CmpTime(currentTime, &(request->startTime)) != -1 )
- {
- return(FALSE);
- }
- msg->endTime.tv_secs = currentTime->tv_secs;
- msg->endTime.tv_micro = currentTime->tv_micro;
- SubTime(currentTime, &(request->startTime));
- msg->diffTime.tv_secs = currentTime->tv_secs;
- msg->diffTime.tv_micro = currentTime->tv_micro;
- return(TRUE);
- }
-
-
- void
- CancelTimer(struct ST_Message *msg)
- {
- struct ST_Node *request;
-
- if( (request = RemoveRequest(msg->requestID)) == NULL )
- {
- msg->code = ST_ERR;
- }
- }
-
- void
- ToggleTimer(struct ST_Message *msg)
- {
- struct ST_Node *request;
- struct timeval currentTime;
-
- GetSysTime(¤tTime);
- if( (request = RemoveRequest(msg->requestID)) != NULL )
- {
- if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
- {
- msg->code = ST_TIMEWARP;
- }
- else
- {
- msg->code = ST_STOP;
- }
- }
- else
- {
- if( InsertRequest(msg->requestID, ¤tTime) )
- {
- msg->startTime.tv_secs = currentTime.tv_secs;
- msg->startTime.tv_micro = currentTime.tv_micro;
- msg->code = ST_START;
- }
- else
- {
- msg->code = ST_ERR;
- }
- }
- }
-
- void
- SetupMessagePort(void)
- {
- if( (publicPort = CreatePort(ST_PORT, 0)) == NULL )
- {
- CleanExit("Can't open public message port\n", -3);
- }
- }
-
- void
- SetupTimerDevice(void)
- {
- LONG error;
-
- TimerIO = (struct timerequest *)
- AllocVec(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR);
- time = (struct timeval *)
- AllocVec(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR);
- if( TimerIO == NULL || time == NULL )
- {
- CleanExit("Out of memory\n", -1);
- }
- if( error = OpenDevice(TIMERNAME, UNIT_MICROHZ,
- (struct IORequest *) TimerIO, 0L) )
- {
- CleanExit("Can't open timer device\n", -2);
- }
- TimerBase = (struct Library *) TimerIO->tr_node.io_Device;
- }
-
- void
- CleanExit(char *string, int returnCode)
- {
- struct ST_Message *msg;
-
- if( string != NULL )
- {
- Print(APPNAME ": ");
- Print(string);
- }
-
- DestroyRequestList();
- if( publicPort )
- {
- while( msg = (struct ST_Message *) GetMsg(publicPort) )
- {
- msg->code = ST_ERR;
- ReplyMsg((struct Message *)msg);
- }
- DeletePort(publicPort);
- }
- if( TimerBase )
- {
- CloseDevice((struct IORequest *) TimerIO);
- }
- if( TimerIO )
- {
- FreeVec(TimerIO);
- }
- if( time )
- {
- FreeVec(time);
- }
- #ifdef MWDEBUG
- MWTerm();
- #endif
- exit(returnCode);
- }
-
- void
- Print(char *string)
- {
- Write(Output(), string, strlen(string));
- }
-