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 */