diff options
author | Jim Blandy <jimb@redhat.com> | 1992-08-12 12:57:12 +0000 |
---|---|---|
committer | Jim Blandy <jimb@redhat.com> | 1992-08-12 12:57:12 +0000 |
commit | 9e2b097b2608f55d27df1e3521575be8dd670a0c (patch) | |
tree | 957a68070b4ce12f0392726f5446e93b88fb80bb /lib-src/timer.c | |
parent | 7e1dae733a5eda79d5681349ca39bfc36ca27871 (diff) | |
download | emacs-9e2b097b2608f55d27df1e3521575be8dd670a0c.tar.gz |
*** empty log message ***
Diffstat (limited to 'lib-src/timer.c')
-rw-r--r-- | lib-src/timer.c | 284 |
1 files changed, 175 insertions, 109 deletions
diff --git a/lib-src/timer.c b/lib-src/timer.c index d7084bfcdc4..2c1b9a729f6 100644 --- a/lib-src/timer.c +++ b/lib-src/timer.c @@ -1,155 +1,221 @@ +/* + * timer.c --- daemon to provide a tagged interval timer service + * + * This little daemon runs forever waiting for signals. SIGIO (or SIGUSR1) + * causes it to read an event spec from stdin; that is, a date followed by + * colon followed by an event label. SIGALRM causes it to check its queue + * for events attached to the current second; if one is found, its label + * is written to stdout. SIGTERM causes it to terminate, printing a list + * of pending events. + * + * This program is intended to be used with the lisp package called timer.el. + * It was written anonymously in 1990. This version was documented and + * rewritten for portability by esr@snark,thyrsus.com, Aug 7 1992. + */ #include <stdio.h> #include <signal.h> #include <fcntl.h> /* FASYNC */ -#ifdef USG /* FASYNC for SysV */ -#include <sys/file.h> -#endif -#include <sys/time.h> /* itimer */ #include <sys/types.h> /* time_t */ +#include "../src/config.h" +#ifdef USG +#undef SIGIO +#define SIGIO SIGUSR1 +#endif + extern int errno; extern char *sys_errlist[], *malloc(); extern time_t time(); #define MAXEVENTS 256 -#define FS 1 /* field seperator for input */ -struct event { - char *token; - time_t reply_at; -} *events[MAXEVENTS]; +/* + * The field separator for input. This character shouldn't be legal in a date, + * and should be printable so event strings are readable by people. Was + * originally ';', then got changed to bogus `\001'. + */ +#define FS '@' + +struct event +{ + char *token; + time_t reply_at; +} +events[MAXEVENTS]; -int slot; /* The next open place in the events array */ -int mevent = 0; /* 1+ the highest event number */ char *pname; /* programme name for error messages */ -/* Accepts a string of two fields seperated by a ';' +/* Accepts a string of two fields seperated by FS. * First field is string for getdate, saying when to wake-up. * Second field is a token to identify the request. */ -struct event * -schedule(str) - char *str; - +void schedule(str) + char *str; { - extern time_t getdate(); - extern char *strcpy(); - time_t now; - register char *p; - static struct event e; - - for(p = str; *p && *p != FS; p++); - if (!*p) { - (void)fprintf(stderr, "%s: bad input format: %s", pname, str); - return((struct event *)NULL); - } - *p++ = 0; + extern time_t getdate(); + extern char *strcpy(); + time_t now; + register char *p; + static struct event *ep; + +#ifdef DEBUG + (void) fprintf(stderr, "Timer sees: %s", str); +#endif /* DEBUG */ + + /* check entry format */ + for(p = str; *p && *p != FS; p++) + continue; + if (!*p) + { + (void)fprintf(stderr, "%s: bad input format: %s", pname, str); + return; + } + *p++ = 0; - if ((e.reply_at = get_date(str, NULL)) - time(&now) < 0) { - (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p); - return((struct event *)NULL); - } - - if ((e.token = malloc((unsigned)strlen(p) + 1)) == NULL) { - (void)fprintf(stderr, "%s: malloc %s: %s%c%s", - pname, sys_errlist[errno], str, FS, p); - return((struct event *)NULL); - } - (void)strcpy(e.token,p); - - return(&e); + /* allocate an event slot */ + for(ep = events; ep < events + MAXEVENTS; ep++) + if (ep->token == (char *)NULL) + break; + if (ep == events + MAXEVENTS) + (void) fprintf(stderr, "%s: too many events: %s", pname, str); + + /* don't allow users to schedule events in past time */ + else if ((ep->reply_at = get_date(str, NULL)) - time(&now) < 0) + (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p); + + /* save the event description */ + else if ((ep->token = malloc((unsigned)strlen(p) + 1)) == NULL) + (void)fprintf(stderr, "%s: malloc %s: %s%c%s", + pname, sys_errlist[errno], str, FS, p); + else + { + (void)strcpy(ep->token, p); + +#ifdef DEBUG + (void) fprintf(stderr, + "New event: %ld: %s", ep->reply_at, ep->token); +#endif /* DEBUG */ + } } void notify() - { - time_t now, tdiff; - register int i, newmax = 0; - /* I prefer using the interval timer rather than alarm(); the latter - could be substituted if portability requires it. */ - struct itimerval itimer; - - now = time((time_t *)NULL); - slot = mevent; - itimer.it_interval.tv_sec = itimer.it_interval.tv_usec = 0; - itimer.it_value.tv_usec = 0; - itimer.it_value.tv_sec = -1; - - for(i=0; i < mevent; i++) { - while (events[i] && events[i]->reply_at <= now) { - (void)fputs(events[i]->token, stdout); - free(events[i]->token); - free((char *)events[i]); - events[i] = 0; - } - - if (events[i]) { - newmax = i+1; - if ((tdiff = events[i]->reply_at - now) < (time_t)itimer.it_value.tv_sec - || itimer.it_value.tv_sec < 0) - /* next timeout */ - itimer.it_value.tv_sec = (long)tdiff; - } else { - /* Keep slot as the lowest unused events element */ - if (i < slot) slot = i; + time_t now, tdiff, waitfor = -1; + register struct event *ep; + + now = time((time_t *)NULL); + + for(ep = events; ep < events + MAXEVENTS; ep++) + if (ep->token) + { + /* any events ready to fire? */ + if (ep->reply_at <= now) + { +#ifdef DEBUG + (void) fprintf(stderr, + "Event %d firing: %ld @ %s", + (ep - events), ep->reply_at, ep->token); +#endif /* DEBUG */ + (void)fputs(ep->token, stdout); + free(ep->token); + ep->token = (char *)NULL; + } + else + { +#ifdef DEBUG + (void) fprintf(stderr, + "Event %d still waiting: %ld @ %s", + (ep - events), ep->reply_at, ep->token); +#endif /* DEBUG */ + + /* next timeout should be the soonest of any remaining */ + if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0) + waitfor = (long)tdiff; + } + } + + /* If there's no more events, SIGIO should be next wake-up */ + if (waitfor != -1) + { +#ifdef DEBUG + (void) fprintf(stderr, + "Setting %d-second alarm\n", waitfor); +#endif /* DEBUG */ + (void)alarm(waitfor); } - } - /* if the array is full to mevent, slot should be the next available spot */ - if (slot > (mevent = newmax)) slot = mevent; - /* If there's no more events, SIGIO should be next wake-up */ - if (mevent) (void)setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL); } void getevent() +{ + extern char *fgets(); + struct event *ep; + char buf[BUFSIZ]; + + /* in principle the itimer should be disabled on entry to this function, + but it really doesn't make any important difference if it isn't */ + + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(0); + + /* register the event */ + schedule(buf); + /* Who knows what this interrupted, or if it said "now"? */ + notify(); +} + +void +sigcatch(sig) +/* dispatch on incoming signal, then restore it */ { - extern char *fgets(); - struct event *ep; - char buf[256]; - - /* in principle the itimer should be disabled on entry to this function, - but it really doesn't make any important difference if it isn't */ - - if (fgets(buf, sizeof(buf), stdin) == NULL) exit(0); - - if (slot == MAXEVENTS) - (void)fprintf(stderr, "%s: too many events: %s", pname, buf); - - else { - if ((events[slot] = (struct event *)malloc((sizeof(struct event)))) - == NULL) - (void)fprintf(stderr,"%s: malloc %s: %s", pname, sys_errlist[errno],buf); - - else { - if ((ep = schedule(buf)) == NULL) - free((char *)events[slot]), events[slot] = 0; - - else { - memcpy((char *)events[slot],(char *)ep,sizeof(struct event)); - if (slot == mevent) mevent++; - } /* schedule */ - } /* malloc */ - } /* limit events */ - /* timing, timing. Who knows what this interrupted, or if it said "now"? */ - notify(); + struct event *ep; + + switch(sig) + { + case SIGALRM: +#ifdef DEBUG + (void) fprintf(stderr, "Alarm signal received\n"); +#endif /* DEBUG */ + notify(); + break; + case SIGIO: + getevent(); + break; + case SIGTERM: + (void) fprintf(stderr, "Events still queued:\n"); + for (ep = events; ep < events + MAXEVENTS; ep++) + if (ep->token) + (void) fprintf(stderr, "%d = %ld @ %s", + ep - events, ep->reply_at, ep->token); + exit(0); + break; + } + + /* required on older UNIXes; harmless on newer ones */ + (void) signal(sig, sigcatch); } - + /*ARGSUSED*/ int main(argc, argv) int argc; char **argv; - { for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0]; pname--); if (*pname == '/') pname++; - (void)signal(SIGIO, getevent); - (void)signal(SIGALRM, notify); + (void)signal(SIGIO, sigcatch); + (void)signal(SIGALRM, sigcatch); + (void)signal(SIGTERM, sigcatch); + +#ifndef USG (void)fcntl(0, F_SETFL, FASYNC); +#endif /* USG */ while (1) pause(); } + +/* timer.c ends here */ |