aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src/timer.c
diff options
context:
space:
mode:
authorRichard M. Stallman1994-01-19 15:12:34 +0000
committerRichard M. Stallman1994-01-19 15:12:34 +0000
commitf8998fa90c9a923585ca4ab728fc40e9dda93188 (patch)
treee3e792e321068af9945e179b5ea4619ddca1f6e4 /lib-src/timer.c
parentdfb8966419ebc8813cc1e4f3b579a3651b1ecc59 (diff)
downloademacs-f8998fa90c9a923585ca4ab728fc40e9dda93188.tar.gz
emacs-f8998fa90c9a923585ca4ab728fc40e9dda93188.zip
Include errno.h; don't include fasync.h.
(schedule): Don't return a value. (sigcatch): Reestablish the handler first. (getevent): Always call notify at the end. (notify): Defer alarms around the whole body of function. (main): Don't request SIGIO, and don't handle it. Loop calling getevent. (sigcatch): Delete code to handle SIGIO. If defer_alarms is set, don't call notify, just set alarm_deferred. (getevent): Use read, not getchar. Handle EINTR and EAGAIN. Set defer_alarms around realloc and schedule. If alarm_deferred gets set, call notify. Likewise if this event is the only pending event. Make buf and buf_size global variables. Don't malloc buf if it is already non-zero. (schedule): Just exit if run out of memory. Return the number of events. (signal) [_CX_UX]: Add #undef.
Diffstat (limited to 'lib-src/timer.c')
-rw-r--r--lib-src/timer.c198
1 files changed, 114 insertions, 84 deletions
diff --git a/lib-src/timer.c b/lib-src/timer.c
index 0b47fac3917..acb84ea5583 100644
--- a/lib-src/timer.c
+++ b/lib-src/timer.c
@@ -1,32 +1,36 @@
1/* timer.c --- daemon to provide a tagged interval timer service 1/* timer.c --- daemon to provide a tagged interval timer service
2 2
3 This little daemon runs forever waiting for signals. SIGIO (or 3 This little daemon runs forever waiting for commands to schedule events.
4 SIGUSR1) causes it to read an event spec from stdin; that is, a 4 SIGALRM causes
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 5 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 6 one is found, its label is written to stdout. SIGTERM causes it to
8 terminate, printing a list of pending events. 7 terminate, printing a list of pending events.
9 8
10 This program is intended to be used with the lisp package called 9 This program is intended to be used with the lisp package called
11 timer.el. It was written anonymously in 1990. This version was 10 timer.el. The first such program was written anonymously in 1990.
12 documented and rewritten for portability by esr@snark.thyrsus.com, 11 This version was documented and rewritten for portability by
13 Aug 7 1992. */ 12 esr@snark.thyrsus.com, Aug 7 1992. */
14 13
15#include <stdio.h> 14#include <stdio.h>
16#include <signal.h> 15#include <signal.h>
17#include <fcntl.h> /* FASYNC */ 16#include <errno.h>
18#include <sys/types.h> /* time_t */ 17#include <sys/types.h> /* time_t */
19 18
20#include <../src/config.h> 19#include <../src/config.h>
21#ifdef USG 20#undef read
22#undef SIGIO
23#define SIGIO SIGPOLL
24#endif
25 21
26#ifdef LINUX 22#ifdef LINUX
27/* Perhaps this is correct unconditionally. */ 23/* Perhaps this is correct unconditionally. */
28#undef signal 24#undef signal
29#endif 25#endif
26#ifdef _CX_UX
27/* I agree with the comment above, this probably should be unconditional (it
28 * is already unconditional in a couple of other files in this directory),
29 * but in the spirit of minimizing the effects of my port, I am making it
30 * conditional on _CX_UX.
31 */
32#undef signal
33#endif
30 34
31 35
32extern int errno; 36extern int errno;
@@ -34,9 +38,8 @@ extern char *strerror (), *malloc ();
34extern time_t time (); 38extern time_t time ();
35 39
36/* 40/*
37 * The field separator for input. This character shouldn't be legal in a date, 41 * The field separator for input. This character shouldn't occur in dates,
38 * and should be printable so event strings are readable by people. Was 42 * and should be printable so event strings are readable by people.
39 * originally ';', then got changed to bogus `\001'.
40 */ 43 */
41#define FS '@' 44#define FS '@'
42 45
@@ -50,11 +53,27 @@ int num_events; /* How many are actually scheduled? */
50struct event *events; /* events[0 .. num_events-1] are the 53struct event *events; /* events[0 .. num_events-1] are the
51 valid events. */ 54 valid events. */
52 55
53char *pname; /* programme name for error messages */ 56char *pname; /* program name for error messages */
57
58/* This buffer is used for reading commands.
59 We make it longer when necessary, but we never free it. */
60char *buf;
61/* This is the allocated size of buf. */
62int buf_size;
63
64/* Non-zero means don't handle an alarm now;
65 instead, just set alarm_deferred if an alarm happens.
66 We set this around parts of the program that call malloc and free. */
67int defer_alarms;
54 68
55/* Accepts a string of two fields separated by FS. 69/* Non-zero if an alarm came in during the reading of a command. */
70int alarm_deferred;
71
72/* Schedule one event, and arrange an alarm for it.
73 STR is a string of two fields separated by FS.
56 First field is string for get_date, saying when to wake-up. 74 First field is string for get_date, saying when to wake-up.
57 Second field is a token to identify the request. */ 75 Second field is a token to identify the request. */
76
58void 77void
59schedule (str) 78schedule (str)
60 char *str; 79 char *str;
@@ -64,7 +83,7 @@ schedule (str)
64 time_t now; 83 time_t now;
65 register char *p; 84 register char *p;
66 static struct event *ep; 85 static struct event *ep;
67 86
68 /* check entry format */ 87 /* check entry format */
69 for (p = str; *p && *p != FS; p++) 88 for (p = str; *p && *p != FS; p++)
70 continue; 89 continue;
@@ -90,13 +109,10 @@ schedule (str)
90 if (! events) 109 if (! events)
91 { 110 {
92 fprintf (stderr, "%s: virtual memory exhausted.\n", pname); 111 fprintf (stderr, "%s: virtual memory exhausted.\n", pname);
93 112 /* Since there is so much virtual memory, and running out
94 /* Should timer exit now? Well, we've still got other 113 almost surely means something is very very wrong,
95 events in the queue, and more memory might become 114 it is best to exit rather than continue. */
96 available in the future, so we'll just toss this event. 115 exit (1);
97 This will screw up whoever scheduled the event, but
98 maybe someone else will survive. */
99 return;
100 } 116 }
101 117
102 while (old_size < events_size) 118 while (old_size < events_size)
@@ -123,6 +139,9 @@ schedule (str)
123 strcpy (ep->token, p); 139 strcpy (ep->token, p);
124 num_events++; 140 num_events++;
125} 141}
142
143/* Print the notification for the alarmed event just arrived if any,
144 and schedule an alarm for the next event if any. */
126 145
127void 146void
128notify () 147notify ()
@@ -130,12 +149,9 @@ notify ()
130 time_t now, tdiff, waitfor = -1; 149 time_t now, tdiff, waitfor = -1;
131 register struct event *ep; 150 register struct event *ep;
132 151
133 /* If an alarm timer runs out while this function is executing, 152 /* Inhibit interference with alarms while changing global vars. */
134 it could get called recursively. This would be bad, because 153 defer_alarms = 1;
135 it's not re-entrant. So we must try to suspend the signal. */ 154 alarm_deferred = 0;
136#if 0 /* This function isn't right for BSD. Fix it later. */
137 sighold(SIGIO);
138#endif
139 155
140 now = time ((time_t *) NULL); 156 now = time ((time_t *) NULL);
141 157
@@ -168,50 +184,82 @@ notify ()
168 if (num_events > 0) 184 if (num_events > 0)
169 alarm (waitfor); 185 alarm (waitfor);
170 186
171#if 0 /* This function isn't right for BSD. */ 187 /* Now check if there was another alarm
172 sigrelse(SIGIO); 188 while we were handling an explicit request. */
173#endif 189 defer_alarms = 0;
190 if (alarm_deferred)
191 notify ();
192 alarm_deferred = 0;
174} 193}
194
195/* Read one command from command from standard input
196 and schedule the event for it. */
175 197
176void 198void
177getevent () 199getevent ()
178{ 200{
179 int i; 201 int i;
180 char *buf; 202 int n_events;
181 int buf_size;
182 203
183 /* In principle the itimer should be disabled on entry to this 204 /* In principle the itimer should be disabled on entry to this
184 function, but it really doesn't make any important difference 205 function, but it really doesn't make any important difference
185 if it isn't. */ 206 if it isn't. */
186 207
187 buf_size = 80; 208 if (buf == 0)
188 buf = (char *) malloc (buf_size); 209 {
210 buf_size = 80;
211 buf = (char *) malloc (buf_size);
212 }
189 213
190 /* Read a line from standard input, expanding buf if it is too short 214 /* Read a line from standard input, expanding buf if it is too short
191 to hold the line. */ 215 to hold the line. */
192 for (i = 0; ; i++) 216 for (i = 0; ; i++)
193 { 217 {
194 int c; 218 char c;
219 int nread;
195 220
196 if (i >= buf_size) 221 if (i >= buf_size)
197 { 222 {
198 buf_size *= 2; 223 buf_size *= 2;
224 alarm_deferred = 0;
225 defer_alarms = 1;
199 buf = (char *) realloc (buf, buf_size); 226 buf = (char *) realloc (buf, buf_size);
227 defer_alarms = 0;
228 if (alarm_deferred)
229 notify ();
230 alarm_deferred = 0;
231 }
200 232
201 /* If we're out of memory, toss this event. */ 233 /* Read one character into c. */
202 do 234 while (1)
235 {
236 nread = read (fileno (stdin), &c, 1);
237
238 /* Retry after transient error. */
239 if (nread < 0
240 && (1
241#ifdef EINTR
242 || errno == EINTR
243#endif
244#ifdef EAGAIN
245 || errno == EAGAIN
246#endif
247 ))
248 continue;
249
250 /* Report serious errors. */
251 if (nread < 0)
203 { 252 {
204 c = getchar (); 253 perror ("read");
254 exit (1);
205 } 255 }
206 while (c != '\n' && c != EOF);
207
208 return;
209 }
210 256
211 c = getchar (); 257 /* On eof, exit. */
258 if (nread == 0)
259 exit (0);
212 260
213 if (c == EOF) 261 break;
214 exit (0); 262 }
215 263
216 if (c == '\n') 264 if (c == '\n')
217 { 265 {
@@ -223,27 +271,32 @@ getevent ()
223 } 271 }
224 272
225 /* Register the event. */ 273 /* Register the event. */
274 alarm_deferred = 0;
275 defer_alarms = 1;
226 schedule (buf); 276 schedule (buf);
227 free (buf); 277 defer_alarms = 0;
228
229 /* Who knows what this interrupted, or if it said "now"? */
230 notify (); 278 notify ();
279 alarm_deferred = 0;
231} 280}
232 281
282/* Handle incoming signal SIG. */
283
233SIGTYPE 284SIGTYPE
234sigcatch (sig) 285sigcatch (sig)
235 int sig; 286 int sig;
236/* dispatch on incoming signal, then restore it */
237{ 287{
238 struct event *ep; 288 struct event *ep;
239 289
290 /* required on older UNIXes; harmless on newer ones */
291 signal (sig, sigcatch);
292
240 switch (sig) 293 switch (sig)
241 { 294 {
242 case SIGALRM: 295 case SIGALRM:
243 notify (); 296 if (defer_alarms)
244 break; 297 alarm_deferred = 1;
245 case SIGIO: 298 else
246 getevent (); 299 notify ();
247 break; 300 break;
248 case SIGTERM: 301 case SIGTERM:
249 fprintf (stderr, "Events still queued:\n"); 302 fprintf (stderr, "Events still queued:\n");
@@ -253,9 +306,6 @@ sigcatch (sig)
253 exit (0); 306 exit (0);
254 break; 307 break;
255 } 308 }
256
257 /* required on older UNIXes; harmless on newer ones */
258 signal (sig, sigcatch);
259} 309}
260 310
261/*ARGSUSED*/ 311/*ARGSUSED*/
@@ -274,34 +324,14 @@ main (argc, argv)
274 events = ((struct event *) malloc (events_size * sizeof (*events))); 324 events = ((struct event *) malloc (events_size * sizeof (*events)));
275 num_events = 0; 325 num_events = 0;
276 326
277 signal (SIGIO, sigcatch);
278 signal (SIGALRM, sigcatch); 327 signal (SIGALRM, sigcatch);
279 signal (SIGTERM, sigcatch); 328 signal (SIGTERM, sigcatch);
280 329
281#ifndef USG 330 /* Loop reading commands from standard input
282 if (fcntl (0, F_SETOWN, getpid ()) == -1) 331 and scheduling alarms accordingly.
283 { 332 The alarms are handled asynchronously, while we wait for commands. */
284 fprintf (stderr, "%s: can't set ownership of stdin\n", pname); 333 while (1)
285 fprintf (stderr, "%s\n", strerror (errno)); 334 getevent ();
286 exit (1);
287 }
288 if (fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | FASYNC) == -1)
289 {
290 fprintf (stderr, "%s: can't request asynchronous I/O on stdin\n", pname);
291 fprintf (stderr, "%s\n", strerror (errno));
292 exit (1);
293 }
294#else /* USG */
295 /* Register this process for SIGPOLL. */
296 ioctl (0, I_SETSIG, S_RDNORM);
297#endif /* USG */
298
299 /* In case Emacs sent some input before we set up
300 the handling of SIGIO, read it now. */
301 kill (0, SIGIO);
302
303 for (;;)
304 pause ();
305} 335}
306 336
307#ifndef HAVE_STRERROR 337#ifndef HAVE_STRERROR