summaryrefslogtreecommitdiff
path: root/lib-src/timer.c
diff options
context:
space:
mode:
authorJim Blandy <jimb@redhat.com>1992-08-12 12:57:12 +0000
committerJim Blandy <jimb@redhat.com>1992-08-12 12:57:12 +0000
commit9e2b097b2608f55d27df1e3521575be8dd670a0c (patch)
tree957a68070b4ce12f0392726f5446e93b88fb80bb /lib-src/timer.c
parent7e1dae733a5eda79d5681349ca39bfc36ca27871 (diff)
downloademacs-9e2b097b2608f55d27df1e3521575be8dd670a0c.tar.gz
*** empty log message ***
Diffstat (limited to 'lib-src/timer.c')
-rw-r--r--lib-src/timer.c284
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 */