Mercurial > emacs
comparison lib-src/=timer.c @ 958:cc82116a8f1c
*** empty log message ***
| author | Jim Blandy <jimb@redhat.com> |
|---|---|
| date | Wed, 12 Aug 1992 12:57:12 +0000 |
| parents | eca8812e61cd |
| children | 61c6983219ff |
comparison
equal
deleted
inserted
replaced
| 957:2619b7a9c11e | 958:cc82116a8f1c |
|---|---|
| 1 /* | |
| 2 * timer.c --- daemon to provide a tagged interval timer service | |
| 3 * | |
| 4 * This little daemon runs forever waiting for signals. SIGIO (or SIGUSR1) | |
| 5 * causes it to read an event spec from stdin; that is, a date followed by | |
| 6 * colon followed by an event label. SIGALRM causes it to check its queue | |
| 7 * for events attached to the current second; if one is found, its label | |
| 8 * is written to stdout. SIGTERM causes it to terminate, printing a list | |
| 9 * of pending events. | |
| 10 * | |
| 11 * This program is intended to be used with the lisp package called timer.el. | |
| 12 * It was written anonymously in 1990. This version was documented and | |
| 13 * rewritten for portability by esr@snark,thyrsus.com, Aug 7 1992. | |
| 14 */ | |
| 1 #include <stdio.h> | 15 #include <stdio.h> |
| 2 #include <signal.h> | 16 #include <signal.h> |
| 3 #include <fcntl.h> /* FASYNC */ | 17 #include <fcntl.h> /* FASYNC */ |
| 4 #ifdef USG /* FASYNC for SysV */ | 18 #include <sys/types.h> /* time_t */ |
| 5 #include <sys/file.h> | 19 |
| 20 #include "../src/config.h" | |
| 21 #ifdef USG | |
| 22 #undef SIGIO | |
| 23 #define SIGIO SIGUSR1 | |
| 6 #endif | 24 #endif |
| 7 #include <sys/time.h> /* itimer */ | |
| 8 #include <sys/types.h> /* time_t */ | |
| 9 | 25 |
| 10 extern int errno; | 26 extern int errno; |
| 11 extern char *sys_errlist[], *malloc(); | 27 extern char *sys_errlist[], *malloc(); |
| 12 extern time_t time(); | 28 extern time_t time(); |
| 13 | 29 |
| 14 #define MAXEVENTS 256 | 30 #define MAXEVENTS 256 |
| 15 #define FS 1 /* field seperator for input */ | 31 |
| 16 | 32 /* |
| 17 struct event { | 33 * The field separator for input. This character shouldn't be legal in a date, |
| 18 char *token; | 34 * and should be printable so event strings are readable by people. Was |
| 19 time_t reply_at; | 35 * originally ';', then got changed to bogus `\001'. |
| 20 } *events[MAXEVENTS]; | 36 */ |
| 21 | 37 #define FS '@' |
| 22 int slot; /* The next open place in the events array */ | 38 |
| 23 int mevent = 0; /* 1+ the highest event number */ | 39 struct event |
| 40 { | |
| 41 char *token; | |
| 42 time_t reply_at; | |
| 43 } | |
| 44 events[MAXEVENTS]; | |
| 45 | |
| 24 char *pname; /* programme name for error messages */ | 46 char *pname; /* programme name for error messages */ |
| 25 | 47 |
| 26 /* Accepts a string of two fields seperated by a ';' | 48 /* Accepts a string of two fields seperated by FS. |
| 27 * First field is string for getdate, saying when to wake-up. | 49 * First field is string for getdate, saying when to wake-up. |
| 28 * Second field is a token to identify the request. | 50 * Second field is a token to identify the request. |
| 29 */ | 51 */ |
| 30 struct event * | 52 void schedule(str) |
| 31 schedule(str) | 53 char *str; |
| 32 char *str; | 54 { |
| 33 | 55 extern time_t getdate(); |
| 34 { | 56 extern char *strcpy(); |
| 35 extern time_t getdate(); | 57 time_t now; |
| 36 extern char *strcpy(); | 58 register char *p; |
| 37 time_t now; | 59 static struct event *ep; |
| 38 register char *p; | 60 |
| 39 static struct event e; | 61 #ifdef DEBUG |
| 40 | 62 (void) fprintf(stderr, "Timer sees: %s", str); |
| 41 for(p = str; *p && *p != FS; p++); | 63 #endif /* DEBUG */ |
| 42 if (!*p) { | 64 |
| 43 (void)fprintf(stderr, "%s: bad input format: %s", pname, str); | 65 /* check entry format */ |
| 44 return((struct event *)NULL); | 66 for(p = str; *p && *p != FS; p++) |
| 45 } | 67 continue; |
| 46 *p++ = 0; | 68 if (!*p) |
| 69 { | |
| 70 (void)fprintf(stderr, "%s: bad input format: %s", pname, str); | |
| 71 return; | |
| 72 } | |
| 73 *p++ = 0; | |
| 47 | 74 |
| 48 if ((e.reply_at = get_date(str, NULL)) - time(&now) < 0) { | 75 /* allocate an event slot */ |
| 49 (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p); | 76 for(ep = events; ep < events + MAXEVENTS; ep++) |
| 50 return((struct event *)NULL); | 77 if (ep->token == (char *)NULL) |
| 51 } | 78 break; |
| 52 | 79 if (ep == events + MAXEVENTS) |
| 53 if ((e.token = malloc((unsigned)strlen(p) + 1)) == NULL) { | 80 (void) fprintf(stderr, "%s: too many events: %s", pname, str); |
| 54 (void)fprintf(stderr, "%s: malloc %s: %s%c%s", | 81 |
| 55 pname, sys_errlist[errno], str, FS, p); | 82 /* don't allow users to schedule events in past time */ |
| 56 return((struct event *)NULL); | 83 else if ((ep->reply_at = get_date(str, NULL)) - time(&now) < 0) |
| 57 } | 84 (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p); |
| 58 (void)strcpy(e.token,p); | 85 |
| 59 | 86 /* save the event description */ |
| 60 return(&e); | 87 else if ((ep->token = malloc((unsigned)strlen(p) + 1)) == NULL) |
| 88 (void)fprintf(stderr, "%s: malloc %s: %s%c%s", | |
| 89 pname, sys_errlist[errno], str, FS, p); | |
| 90 else | |
| 91 { | |
| 92 (void)strcpy(ep->token, p); | |
| 93 | |
| 94 #ifdef DEBUG | |
| 95 (void) fprintf(stderr, | |
| 96 "New event: %ld: %s", ep->reply_at, ep->token); | |
| 97 #endif /* DEBUG */ | |
| 98 } | |
| 61 } | 99 } |
| 62 | 100 |
| 63 void | 101 void |
| 64 notify() | 102 notify() |
| 65 | 103 { |
| 66 { | 104 time_t now, tdiff, waitfor = -1; |
| 67 time_t now, tdiff; | 105 register struct event *ep; |
| 68 register int i, newmax = 0; | 106 |
| 69 /* I prefer using the interval timer rather than alarm(); the latter | 107 now = time((time_t *)NULL); |
| 70 could be substituted if portability requires it. */ | 108 |
| 71 struct itimerval itimer; | 109 for(ep = events; ep < events + MAXEVENTS; ep++) |
| 72 | 110 if (ep->token) |
| 73 now = time((time_t *)NULL); | 111 { |
| 74 slot = mevent; | 112 /* any events ready to fire? */ |
| 75 itimer.it_interval.tv_sec = itimer.it_interval.tv_usec = 0; | 113 if (ep->reply_at <= now) |
| 76 itimer.it_value.tv_usec = 0; | 114 { |
| 77 itimer.it_value.tv_sec = -1; | 115 #ifdef DEBUG |
| 78 | 116 (void) fprintf(stderr, |
| 79 for(i=0; i < mevent; i++) { | 117 "Event %d firing: %ld @ %s", |
| 80 while (events[i] && events[i]->reply_at <= now) { | 118 (ep - events), ep->reply_at, ep->token); |
| 81 (void)fputs(events[i]->token, stdout); | 119 #endif /* DEBUG */ |
| 82 free(events[i]->token); | 120 (void)fputs(ep->token, stdout); |
| 83 free((char *)events[i]); | 121 free(ep->token); |
| 84 events[i] = 0; | 122 ep->token = (char *)NULL; |
| 85 } | 123 } |
| 86 | 124 else |
| 87 if (events[i]) { | 125 { |
| 88 newmax = i+1; | 126 #ifdef DEBUG |
| 89 if ((tdiff = events[i]->reply_at - now) < (time_t)itimer.it_value.tv_sec | 127 (void) fprintf(stderr, |
| 90 || itimer.it_value.tv_sec < 0) | 128 "Event %d still waiting: %ld @ %s", |
| 91 /* next timeout */ | 129 (ep - events), ep->reply_at, ep->token); |
| 92 itimer.it_value.tv_sec = (long)tdiff; | 130 #endif /* DEBUG */ |
| 93 } else { | 131 |
| 94 /* Keep slot as the lowest unused events element */ | 132 /* next timeout should be the soonest of any remaining */ |
| 95 if (i < slot) slot = i; | 133 if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0) |
| 96 } | 134 waitfor = (long)tdiff; |
| 97 } | 135 } |
| 98 /* if the array is full to mevent, slot should be the next available spot */ | 136 } |
| 99 if (slot > (mevent = newmax)) slot = mevent; | 137 |
| 100 /* If there's no more events, SIGIO should be next wake-up */ | 138 /* If there's no more events, SIGIO should be next wake-up */ |
| 101 if (mevent) (void)setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL); | 139 if (waitfor != -1) |
| 140 { | |
| 141 #ifdef DEBUG | |
| 142 (void) fprintf(stderr, | |
| 143 "Setting %d-second alarm\n", waitfor); | |
| 144 #endif /* DEBUG */ | |
| 145 (void)alarm(waitfor); | |
| 146 } | |
| 102 } | 147 } |
| 103 | 148 |
| 104 void | 149 void |
| 105 getevent() | 150 getevent() |
| 106 | 151 { |
| 107 { | 152 extern char *fgets(); |
| 108 extern char *fgets(); | 153 struct event *ep; |
| 109 struct event *ep; | 154 char buf[BUFSIZ]; |
| 110 char buf[256]; | 155 |
| 111 | 156 /* in principle the itimer should be disabled on entry to this function, |
| 112 /* in principle the itimer should be disabled on entry to this function, | 157 but it really doesn't make any important difference if it isn't */ |
| 113 but it really doesn't make any important difference if it isn't */ | 158 |
| 114 | 159 if (fgets(buf, sizeof(buf), stdin) == NULL) |
| 115 if (fgets(buf, sizeof(buf), stdin) == NULL) exit(0); | 160 exit(0); |
| 116 | 161 |
| 117 if (slot == MAXEVENTS) | 162 /* register the event */ |
| 118 (void)fprintf(stderr, "%s: too many events: %s", pname, buf); | 163 schedule(buf); |
| 119 | 164 |
| 120 else { | 165 /* Who knows what this interrupted, or if it said "now"? */ |
| 121 if ((events[slot] = (struct event *)malloc((sizeof(struct event)))) | 166 notify(); |
| 122 == NULL) | 167 } |
| 123 (void)fprintf(stderr,"%s: malloc %s: %s", pname, sys_errlist[errno],buf); | 168 |
| 124 | 169 void |
| 125 else { | 170 sigcatch(sig) |
| 126 if ((ep = schedule(buf)) == NULL) | 171 /* dispatch on incoming signal, then restore it */ |
| 127 free((char *)events[slot]), events[slot] = 0; | 172 { |
| 128 | 173 struct event *ep; |
| 129 else { | 174 |
| 130 memcpy((char *)events[slot],(char *)ep,sizeof(struct event)); | 175 switch(sig) |
| 131 if (slot == mevent) mevent++; | 176 { |
| 132 } /* schedule */ | 177 case SIGALRM: |
| 133 } /* malloc */ | 178 #ifdef DEBUG |
| 134 } /* limit events */ | 179 (void) fprintf(stderr, "Alarm signal received\n"); |
| 135 /* timing, timing. Who knows what this interrupted, or if it said "now"? */ | 180 #endif /* DEBUG */ |
| 136 notify(); | 181 notify(); |
| 137 } | 182 break; |
| 138 | 183 case SIGIO: |
| 184 getevent(); | |
| 185 break; | |
| 186 case SIGTERM: | |
| 187 (void) fprintf(stderr, "Events still queued:\n"); | |
| 188 for (ep = events; ep < events + MAXEVENTS; ep++) | |
| 189 if (ep->token) | |
| 190 (void) fprintf(stderr, "%d = %ld @ %s", | |
| 191 ep - events, ep->reply_at, ep->token); | |
| 192 exit(0); | |
| 193 break; | |
| 194 } | |
| 195 | |
| 196 /* required on older UNIXes; harmless on newer ones */ | |
| 197 (void) signal(sig, sigcatch); | |
| 198 } | |
| 199 | |
| 139 /*ARGSUSED*/ | 200 /*ARGSUSED*/ |
| 140 int | 201 int |
| 141 main(argc, argv) | 202 main(argc, argv) |
| 142 int argc; | 203 int argc; |
| 143 char **argv; | 204 char **argv; |
| 144 | |
| 145 { | 205 { |
| 146 for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0]; | 206 for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0]; |
| 147 pname--); | 207 pname--); |
| 148 if (*pname == '/') pname++; | 208 if (*pname == '/') pname++; |
| 149 | 209 |
| 150 (void)signal(SIGIO, getevent); | 210 (void)signal(SIGIO, sigcatch); |
| 151 (void)signal(SIGALRM, notify); | 211 (void)signal(SIGALRM, sigcatch); |
| 212 (void)signal(SIGTERM, sigcatch); | |
| 213 | |
| 214 #ifndef USG | |
| 152 (void)fcntl(0, F_SETFL, FASYNC); | 215 (void)fcntl(0, F_SETFL, FASYNC); |
| 216 #endif /* USG */ | |
| 153 | 217 |
| 154 while (1) pause(); | 218 while (1) pause(); |
| 155 } | 219 } |
| 220 | |
| 221 /* timer.c ends here */ |
