diff options
| author | Richard M. Stallman | 1994-01-19 15:12:34 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-01-19 15:12:34 +0000 |
| commit | f8998fa90c9a923585ca4ab728fc40e9dda93188 (patch) | |
| tree | e3e792e321068af9945e179b5ea4619ddca1f6e4 /lib-src/timer.c | |
| parent | dfb8966419ebc8813cc1e4f3b579a3651b1ecc59 (diff) | |
| download | emacs-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.c | 198 |
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 | ||
| 32 | extern int errno; | 36 | extern int errno; |
| @@ -34,9 +38,8 @@ extern char *strerror (), *malloc (); | |||
| 34 | extern time_t time (); | 38 | extern 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? */ | |||
| 50 | struct event *events; /* events[0 .. num_events-1] are the | 53 | struct event *events; /* events[0 .. num_events-1] are the |
| 51 | valid events. */ | 54 | valid events. */ |
| 52 | 55 | ||
| 53 | char *pname; /* programme name for error messages */ | 56 | char *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. */ | ||
| 60 | char *buf; | ||
| 61 | /* This is the allocated size of buf. */ | ||
| 62 | int 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. */ | ||
| 67 | int 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. */ |
| 70 | int 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 | |||
| 58 | void | 77 | void |
| 59 | schedule (str) | 78 | schedule (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 | ||
| 127 | void | 146 | void |
| 128 | notify () | 147 | notify () |
| @@ -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 | ||
| 176 | void | 198 | void |
| 177 | getevent () | 199 | getevent () |
| 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 | |||
| 233 | SIGTYPE | 284 | SIGTYPE |
| 234 | sigcatch (sig) | 285 | sigcatch (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 |