Mercurial > emacs
annotate lib-src/=timer.c @ 4774:8e36034f65e2
(doprnt): Use a fixed buffer to store the format
specification, but only if we are sure it will fit. Otherwise,
use alloca () to get enouhg space. Don't allow negative size
specifications to core dump; instead, treat them as positive
("%-20d" == "%20d").
author | Brian Fox <bfox@gnu.org> |
---|---|
date | Wed, 22 Sep 1993 18:12:09 +0000 |
parents | 1fc792473491 |
children | 1d84e80b47a4 |
rev | line source |
---|---|
998 | 1 /* timer.c --- daemon to provide a tagged interval timer service |
2 | |
3 This little daemon runs forever waiting for signals. SIGIO (or | |
4 SIGUSR1) causes it to read an event spec from stdin; that is, a | |
5 date followed by colon followed by an event label. SIGALRM causes | |
6 it to check its queue for events attached to the current second; if | |
7 one is found, its label is written to stdout. SIGTERM causes it to | |
8 terminate, printing a list of pending events. | |
9 | |
10 This program is intended to be used with the lisp package called | |
11 timer.el. It was written anonymously in 1990. This version was | |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
12 documented and rewritten for portability by esr@snark.thyrsus.com, |
998 | 13 Aug 7 1992. */ |
14 | |
45 | 15 #include <stdio.h> |
16 #include <signal.h> | |
17 #include <fcntl.h> /* FASYNC */ | |
958 | 18 #include <sys/types.h> /* time_t */ |
19 | |
4696
1fc792473491
Include <config.h> instead of "config.h".
Roland McGrath <roland@gnu.org>
parents:
4392
diff
changeset
|
20 #include <../src/config.h> |
958 | 21 #ifdef USG |
22 #undef SIGIO | |
23 #define SIGIO SIGUSR1 | |
45 | 24 #endif |
25 | |
3392 | 26 #ifdef LINUX |
27 /* Perhaps this is correct unconditionally. */ | |
28 #undef signal | |
29 #endif | |
30 | |
31 | |
45 | 32 extern int errno; |
998 | 33 extern char *sys_errlist[], *malloc (); |
34 extern time_t time (); | |
958 | 35 |
36 /* | |
37 * The field separator for input. This character shouldn't be legal in a date, | |
38 * and should be printable so event strings are readable by people. Was | |
39 * originally ';', then got changed to bogus `\001'. | |
40 */ | |
41 #define FS '@' | |
45 | 42 |
958 | 43 struct event |
998 | 44 { |
958 | 45 char *token; |
46 time_t reply_at; | |
998 | 47 }; |
48 int events_size; /* How many slots have we allocated? */ | |
49 int num_events; /* How many are actually scheduled? */ | |
50 struct event *events; /* events[0 .. num_events-1] are the | |
51 valid events. */ | |
45 | 52 |
53 char *pname; /* programme name for error messages */ | |
54 | |
3591
507f64624555
Apply typo patches from Paul Eggert.
Jim Blandy <jimb@redhat.com>
parents:
3392
diff
changeset
|
55 /* Accepts a string of two fields separated by FS. |
2813
89b1121e2d43
* timer.c: Fix mispellings of get_date function's name.
Jim Blandy <jimb@redhat.com>
parents:
2592
diff
changeset
|
56 First field is string for get_date, saying when to wake-up. |
998 | 57 Second field is a token to identify the request. */ |
58 void | |
59 schedule (str) | |
60 char *str; | |
45 | 61 { |
2813
89b1121e2d43
* timer.c: Fix mispellings of get_date function's name.
Jim Blandy <jimb@redhat.com>
parents:
2592
diff
changeset
|
62 extern time_t get_date (); |
998 | 63 extern char *strcpy (); |
64 time_t now; | |
65 register char *p; | |
66 static struct event *ep; | |
958 | 67 |
998 | 68 /* check entry format */ |
69 for (p = str; *p && *p != FS; p++) | |
70 continue; | |
71 if (!*p) | |
958 | 72 { |
1751
fac61b478a41
Also, write a newline after the token.
Michael I. Bushnell <mib@gnu.org>
parents:
1750
diff
changeset
|
73 fprintf (stderr, "%s: bad input format: %s\n", pname, str); |
998 | 74 return; |
958 | 75 } |
998 | 76 *p++ = 0; |
45 | 77 |
998 | 78 /* allocate an event slot */ |
79 ep = events + num_events; | |
958 | 80 |
998 | 81 /* If the event array is full, stretch it. After stretching, we know |
82 that ep will be pointing to an available event spot. */ | |
83 if (ep == events + events_size) | |
84 { | |
85 int old_size = events_size; | |
86 | |
87 events_size *= 2; | |
88 events = ((struct event *) | |
89 realloc (events, events_size * sizeof (struct event))); | |
90 if (! events) | |
91 { | |
92 fprintf (stderr, "%s: virtual memory exhausted.\n", pname); | |
45 | 93 |
998 | 94 /* Should timer exit now? Well, we've still got other |
95 events in the queue, and more memory might become | |
96 available in the future, so we'll just toss this event. | |
97 This will screw up whoever scheduled the event, but | |
98 maybe someone else will survive. */ | |
99 return; | |
100 } | |
101 | |
102 while (old_size < events_size) | |
103 events[old_size++].token = NULL; | |
104 } | |
105 | |
106 /* Don't allow users to schedule events in past time. */ | |
107 ep->reply_at = get_date (str, NULL); | |
108 if (ep->reply_at - time (&now) < 0) | |
958 | 109 { |
1751
fac61b478a41
Also, write a newline after the token.
Michael I. Bushnell <mib@gnu.org>
parents:
1750
diff
changeset
|
110 fprintf (stderr, "%s: bad time spec: %s%c%s\n", pname, str, FS, p); |
998 | 111 return; |
112 } | |
45 | 113 |
998 | 114 /* save the event description */ |
115 ep->token = (char *) malloc ((unsigned) strlen (p) + 1); | |
116 if (! ep->token) | |
117 { | |
1751
fac61b478a41
Also, write a newline after the token.
Michael I. Bushnell <mib@gnu.org>
parents:
1750
diff
changeset
|
118 fprintf (stderr, "%s: malloc %s: %s%c%s\n", |
998 | 119 pname, sys_errlist[errno], str, FS, p); |
120 return; | |
958 | 121 } |
998 | 122 |
123 strcpy (ep->token, p); | |
124 num_events++; | |
45 | 125 } |
126 | |
127 void | |
998 | 128 notify () |
958 | 129 { |
1995
f149ad4ad9d4
* timer.c (notify): Initialize waitfor properly.
Jim Blandy <jimb@redhat.com>
parents:
1751
diff
changeset
|
130 time_t now, tdiff, waitfor = -1; |
998 | 131 register struct event *ep; |
132 | |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
133 /* If an alarm timer runs out while this function is executing, |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
134 it could get called recursively. This would be bad, because |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
135 it's not re-entrant. So we must try to suspend the signal. */ |
2820
37954061f933
* timer.c (notify): Don't call sighold or sigrelse; they're USG
Jim Blandy <jimb@redhat.com>
parents:
2813
diff
changeset
|
136 #if 0 /* This function isn't right for BSD. Fix it later. */ |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
137 sighold(SIGIO); |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
138 #endif |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
139 |
998 | 140 now = time ((time_t *) NULL); |
45 | 141 |
998 | 142 for (ep = events; ep < events + num_events; ep++) |
143 /* Are any events ready to fire? */ | |
144 if (ep->reply_at <= now) | |
145 { | |
146 fputs (ep->token, stdout); | |
1750
2a92e870a448
Also, write a newline after the token.
Michael I. Bushnell <mib@gnu.org>
parents:
1749
diff
changeset
|
147 putc ('\n', stdout); |
1746
7c4fc10fde41
timer.c (notify): Flush stdout after writing message to avoid lossage
Michael I. Bushnell <mib@gnu.org>
parents:
998
diff
changeset
|
148 fflush (stdout); |
998 | 149 free (ep->token); |
45 | 150 |
998 | 151 /* We now have a hole in the event array; fill it with the last |
152 event. */ | |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
153 ep->token = events[num_events - 1].token; |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
154 ep->reply_at = events[num_events - 1].reply_at; |
998 | 155 num_events--; |
45 | 156 |
998 | 157 /* We ought to scan this event again. */ |
158 ep--; | |
159 } | |
160 else | |
161 { | |
162 /* next timeout should be the soonest of any remaining */ | |
163 if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0) | |
164 waitfor = (long)tdiff; | |
165 } | |
958 | 166 |
998 | 167 /* If there are no more events, we needn't bother setting an alarm. */ |
168 if (num_events > 0) | |
169 alarm (waitfor); | |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
170 |
2820
37954061f933
* timer.c (notify): Don't call sighold or sigrelse; they're USG
Jim Blandy <jimb@redhat.com>
parents:
2813
diff
changeset
|
171 #if 0 /* This function isn't right for BSD. */ |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
172 sigrelse(SIGIO); |
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
173 #endif |
45 | 174 } |
175 | |
176 void | |
998 | 177 getevent () |
958 | 178 { |
998 | 179 int i; |
180 char *buf; | |
181 int buf_size; | |
182 | |
183 /* In principle the itimer should be disabled on entry to this | |
184 function, but it really doesn't make any important difference | |
185 if it isn't. */ | |
186 | |
187 buf_size = 80; | |
188 buf = (char *) malloc (buf_size); | |
45 | 189 |
998 | 190 /* Read a line from standard input, expanding buf if it is too short |
191 to hold the line. */ | |
192 for (i = 0; ; i++) | |
193 { | |
194 int c; | |
195 | |
196 if (i >= buf_size) | |
197 { | |
198 buf_size *= 2; | |
199 buf = (char *) realloc (buf, buf_size); | |
958 | 200 |
998 | 201 /* If we're out of memory, toss this event. */ |
202 do | |
203 { | |
204 c = getchar (); | |
205 } | |
206 while (c != '\n' && c != EOF); | |
207 | |
208 return; | |
209 } | |
210 | |
211 c = getchar (); | |
212 | |
213 if (c == EOF) | |
214 exit (0); | |
45 | 215 |
998 | 216 if (c == '\n') |
217 { | |
218 buf[i] = '\0'; | |
219 break; | |
220 } | |
45 | 221 |
998 | 222 buf[i] = c; |
223 } | |
224 | |
225 /* Register the event. */ | |
226 schedule (buf); | |
227 free (buf); | |
228 | |
229 /* Who knows what this interrupted, or if it said "now"? */ | |
230 notify (); | |
958 | 231 } |
45 | 232 |
2102
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
233 SIGTYPE |
998 | 234 sigcatch (sig) |
235 int sig; | |
958 | 236 /* dispatch on incoming signal, then restore it */ |
237 { | |
998 | 238 struct event *ep; |
45 | 239 |
998 | 240 switch (sig) |
958 | 241 { |
242 case SIGALRM: | |
998 | 243 notify (); |
244 break; | |
958 | 245 case SIGIO: |
998 | 246 getevent (); |
247 break; | |
958 | 248 case SIGTERM: |
998 | 249 fprintf (stderr, "Events still queued:\n"); |
250 for (ep = events; ep < events + num_events; ep++) | |
1751
fac61b478a41
Also, write a newline after the token.
Michael I. Bushnell <mib@gnu.org>
parents:
1750
diff
changeset
|
251 fprintf (stderr, "%d = %ld @ %s\n", |
998 | 252 ep - events, ep->reply_at, ep->token); |
253 exit (0); | |
254 break; | |
958 | 255 } |
45 | 256 |
998 | 257 /* required on older UNIXes; harmless on newer ones */ |
258 signal (sig, sigcatch); | |
45 | 259 } |
958 | 260 |
45 | 261 /*ARGSUSED*/ |
262 int | |
998 | 263 main (argc, argv) |
45 | 264 int argc; |
265 char **argv; | |
266 { | |
998 | 267 for (pname = argv[0] + strlen (argv[0]); |
268 *pname != '/' && pname != argv[0]; | |
45 | 269 pname--); |
998 | 270 if (*pname == '/') |
271 pname++; | |
45 | 272 |
998 | 273 events_size = 16; |
274 events = ((struct event *) malloc (events_size * sizeof (*events))); | |
275 num_events = 0; | |
276 | |
277 signal (SIGIO, sigcatch); | |
278 signal (SIGALRM, sigcatch); | |
279 signal (SIGTERM, sigcatch); | |
958 | 280 |
281 #ifndef USG | |
2102
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
282 if (fcntl (0, F_SETOWN, getpid ()) == -1) |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
283 { |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
284 fprintf (stderr, "%s: can't set ownership of stdin\n", pname); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
285 fprintf (stderr, "%s\n", sys_errlist[errno]); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
286 exit (1); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
287 } |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
288 if (fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | FASYNC) == -1) |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
289 { |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
290 fprintf (stderr, "%s: can't request asynchronous I/O on stdin\n", pname); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
291 fprintf (stderr, "%s\n", sys_errlist[errno]); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
292 exit (1); |
b11495a4ecdf
* timer.c (main): Set the ownership of the stdin file descriptor
Jim Blandy <jimb@redhat.com>
parents:
1995
diff
changeset
|
293 } |
958 | 294 #endif /* USG */ |
45 | 295 |
4392
b64b1b80f371
(main): Generate a SIGIO as soon as we've initialized.
Richard M. Stallman <rms@gnu.org>
parents:
3591
diff
changeset
|
296 /* In case Emacs sent some input before we set up |
b64b1b80f371
(main): Generate a SIGIO as soon as we've initialized.
Richard M. Stallman <rms@gnu.org>
parents:
3591
diff
changeset
|
297 the handling of SIGIO, read it now. */ |
b64b1b80f371
(main): Generate a SIGIO as soon as we've initialized.
Richard M. Stallman <rms@gnu.org>
parents:
3591
diff
changeset
|
298 kill (0, SIGIO); |
b64b1b80f371
(main): Generate a SIGIO as soon as we've initialized.
Richard M. Stallman <rms@gnu.org>
parents:
3591
diff
changeset
|
299 |
2592
2e57e16282f0
(notify): Bug fix. Treat the body of this function as a critical region.
Eric S. Raymond <esr@snark.thyrsus.com>
parents:
2102
diff
changeset
|
300 for (;;) |
4392
b64b1b80f371
(main): Generate a SIGIO as soon as we've initialized.
Richard M. Stallman <rms@gnu.org>
parents:
3591
diff
changeset
|
301 pause (); |
45 | 302 } |
958 | 303 |
304 /* timer.c ends here */ |