diff options
| author | Ken Raeburn | 2001-07-06 08:41:36 +0000 |
|---|---|---|
| committer | Ken Raeburn | 2001-07-06 08:41:36 +0000 |
| commit | ad782551325b7c694ee234b5ff4c5688d90e561c (patch) | |
| tree | f4355f141142b6018183518fa1761b53e295ede2 /lib-src/timer.c | |
| parent | f25cfe53951f57e1b2c3972877297df3d86bb980 (diff) | |
| download | emacs-ad782551325b7c694ee234b5ff4c5688d90e561c.tar.gz emacs-ad782551325b7c694ee234b5ff4c5688d90e561c.zip | |
properly mark Attic files as deleted
Diffstat (limited to 'lib-src/timer.c')
| -rw-r--r-- | lib-src/timer.c | 368 |
1 files changed, 0 insertions, 368 deletions
diff --git a/lib-src/timer.c b/lib-src/timer.c deleted file mode 100644 index 9bd547ce8f2..00000000000 --- a/lib-src/timer.c +++ /dev/null | |||
| @@ -1,368 +0,0 @@ | |||
| 1 | /* timer.c --- daemon to provide a tagged interval timer service | ||
| 2 | |||
| 3 | This little daemon runs forever waiting for commands to schedule events. | ||
| 4 | SIGALRM causes | ||
| 5 | it to check its queue for events attached to the current second; if | ||
| 6 | one is found, its label is written to stdout. SIGTERM causes it to | ||
| 7 | terminate, printing a list of pending events. | ||
| 8 | |||
| 9 | This program is intended to be used with the lisp package called | ||
| 10 | timer.el. The first such program was written anonymously in 1990. | ||
| 11 | This version was documented and rewritten for portability by | ||
| 12 | esr@snark.thyrsus.com, Aug 7 1992. */ | ||
| 13 | |||
| 14 | #include <stdio.h> | ||
| 15 | #include <signal.h> | ||
| 16 | #include <errno.h> | ||
| 17 | #include <sys/types.h> /* time_t */ | ||
| 18 | |||
| 19 | #include <../src/config.h> | ||
| 20 | #undef read | ||
| 21 | |||
| 22 | #ifdef LINUX | ||
| 23 | /* Perhaps this is correct unconditionally. */ | ||
| 24 | #undef signal | ||
| 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 | ||
| 34 | |||
| 35 | |||
| 36 | extern int errno; | ||
| 37 | extern char *strerror (); | ||
| 38 | extern time_t time (); | ||
| 39 | |||
| 40 | /* | ||
| 41 | * The field separator for input. This character shouldn't occur in dates, | ||
| 42 | * and should be printable so event strings are readable by people. | ||
| 43 | */ | ||
| 44 | #define FS '@' | ||
| 45 | |||
| 46 | struct event | ||
| 47 | { | ||
| 48 | char *token; | ||
| 49 | time_t reply_at; | ||
| 50 | }; | ||
| 51 | int events_size; /* How many slots have we allocated? */ | ||
| 52 | int num_events; /* How many are actually scheduled? */ | ||
| 53 | struct event *events; /* events[0 .. num_events-1] are the | ||
| 54 | valid events. */ | ||
| 55 | |||
| 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; | ||
| 68 | |||
| 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. | ||
| 74 | First field is string for get_date, saying when to wake-up. | ||
| 75 | Second field is a token to identify the request. */ | ||
| 76 | |||
| 77 | void | ||
| 78 | schedule (str) | ||
| 79 | char *str; | ||
| 80 | { | ||
| 81 | extern time_t get_date (); | ||
| 82 | extern char *strcpy (); | ||
| 83 | time_t now; | ||
| 84 | register char *p; | ||
| 85 | static struct event *ep; | ||
| 86 | |||
| 87 | /* check entry format */ | ||
| 88 | for (p = str; *p && *p != FS; p++) | ||
| 89 | continue; | ||
| 90 | if (!*p) | ||
| 91 | { | ||
| 92 | fprintf (stderr, "%s: bad input format: %s\n", pname, str); | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | *p++ = 0; | ||
| 96 | |||
| 97 | /* allocate an event slot */ | ||
| 98 | ep = events + num_events; | ||
| 99 | |||
| 100 | /* If the event array is full, stretch it. After stretching, we know | ||
| 101 | that ep will be pointing to an available event spot. */ | ||
| 102 | if (ep == events + events_size) | ||
| 103 | { | ||
| 104 | int old_size = events_size; | ||
| 105 | |||
| 106 | events_size *= 2; | ||
| 107 | events = ((struct event *) | ||
| 108 | realloc (events, events_size * sizeof (struct event))); | ||
| 109 | if (! events) | ||
| 110 | { | ||
| 111 | fprintf (stderr, "%s: virtual memory exhausted.\n", pname); | ||
| 112 | /* Since there is so much virtual memory, and running out | ||
| 113 | almost surely means something is very very wrong, | ||
| 114 | it is best to exit rather than continue. */ | ||
| 115 | exit (1); | ||
| 116 | } | ||
| 117 | |||
| 118 | while (old_size < events_size) | ||
| 119 | events[old_size++].token = NULL; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Don't allow users to schedule events in past time. */ | ||
| 123 | ep->reply_at = get_date (str, NULL); | ||
| 124 | if (ep->reply_at - time (&now) < 0) | ||
| 125 | { | ||
| 126 | fprintf (stderr, "%s: bad time spec: %s%c%s\n", pname, str, FS, p); | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* save the event description */ | ||
| 131 | ep->token = (char *) malloc ((unsigned) strlen (p) + 1); | ||
| 132 | if (! ep->token) | ||
| 133 | { | ||
| 134 | fprintf (stderr, "%s: malloc %s: %s%c%s\n", | ||
| 135 | pname, strerror (errno), str, FS, p); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | strcpy (ep->token, p); | ||
| 140 | num_events++; | ||
| 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. */ | ||
| 145 | |||
| 146 | void | ||
| 147 | notify () | ||
| 148 | { | ||
| 149 | time_t now, tdiff, waitfor = -1; | ||
| 150 | register struct event *ep; | ||
| 151 | |||
| 152 | /* Inhibit interference with alarms while changing global vars. */ | ||
| 153 | defer_alarms = 1; | ||
| 154 | alarm_deferred = 0; | ||
| 155 | |||
| 156 | now = time ((time_t *) NULL); | ||
| 157 | |||
| 158 | for (ep = events; ep < events + num_events; ep++) | ||
| 159 | /* Are any events ready to fire? */ | ||
| 160 | if (ep->reply_at <= now) | ||
| 161 | { | ||
| 162 | fputs (ep->token, stdout); | ||
| 163 | putc ('\n', stdout); | ||
| 164 | fflush (stdout); | ||
| 165 | free (ep->token); | ||
| 166 | |||
| 167 | /* We now have a hole in the event array; fill it with the last | ||
| 168 | event. */ | ||
| 169 | ep->token = events[num_events - 1].token; | ||
| 170 | ep->reply_at = events[num_events - 1].reply_at; | ||
| 171 | num_events--; | ||
| 172 | |||
| 173 | /* We ought to scan this event again. */ | ||
| 174 | ep--; | ||
| 175 | } | ||
| 176 | else | ||
| 177 | { | ||
| 178 | /* next timeout should be the soonest of any remaining */ | ||
| 179 | if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0) | ||
| 180 | waitfor = (long)tdiff; | ||
| 181 | } | ||
| 182 | |||
| 183 | /* If there are no more events, we needn't bother setting an alarm. */ | ||
| 184 | if (num_events > 0) | ||
| 185 | alarm (waitfor); | ||
| 186 | |||
| 187 | /* Now check if there was another alarm | ||
| 188 | while we were handling an explicit request. */ | ||
| 189 | defer_alarms = 0; | ||
| 190 | if (alarm_deferred) | ||
| 191 | notify (); | ||
| 192 | alarm_deferred = 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Read one command from command from standard input | ||
| 196 | and schedule the event for it. */ | ||
| 197 | |||
| 198 | void | ||
| 199 | getevent () | ||
| 200 | { | ||
| 201 | int i; | ||
| 202 | |||
| 203 | /* In principle the itimer should be disabled on entry to this | ||
| 204 | function, but it really doesn't make any important difference | ||
| 205 | if it isn't. */ | ||
| 206 | |||
| 207 | if (buf == 0) | ||
| 208 | { | ||
| 209 | buf_size = 80; | ||
| 210 | buf = (char *) malloc (buf_size); | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Read a line from standard input, expanding buf if it is too short | ||
| 214 | to hold the line. */ | ||
| 215 | for (i = 0; ; i++) | ||
| 216 | { | ||
| 217 | char c; | ||
| 218 | int nread; | ||
| 219 | |||
| 220 | if (i >= buf_size) | ||
| 221 | { | ||
| 222 | buf_size *= 2; | ||
| 223 | alarm_deferred = 0; | ||
| 224 | defer_alarms = 1; | ||
| 225 | buf = (char *) realloc (buf, buf_size); | ||
| 226 | defer_alarms = 0; | ||
| 227 | if (alarm_deferred) | ||
| 228 | notify (); | ||
| 229 | alarm_deferred = 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* Read one character into c. */ | ||
| 233 | while (1) | ||
| 234 | { | ||
| 235 | nread = read (fileno (stdin), &c, 1); | ||
| 236 | |||
| 237 | /* Retry after transient error. */ | ||
| 238 | if (nread < 0 | ||
| 239 | && (1 | ||
| 240 | #ifdef EINTR | ||
| 241 | || errno == EINTR | ||
| 242 | #endif | ||
| 243 | #ifdef EAGAIN | ||
| 244 | || errno == EAGAIN | ||
| 245 | #endif | ||
| 246 | )) | ||
| 247 | continue; | ||
| 248 | |||
| 249 | /* Report serious errors. */ | ||
| 250 | if (nread < 0) | ||
| 251 | { | ||
| 252 | perror ("read"); | ||
| 253 | exit (1); | ||
| 254 | } | ||
| 255 | |||
| 256 | /* On eof, exit. */ | ||
| 257 | if (nread == 0) | ||
| 258 | exit (0); | ||
| 259 | |||
| 260 | break; | ||
| 261 | } | ||
| 262 | |||
| 263 | if (c == '\n') | ||
| 264 | { | ||
| 265 | buf[i] = '\0'; | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | |||
| 269 | buf[i] = c; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* Register the event. */ | ||
| 273 | alarm_deferred = 0; | ||
| 274 | defer_alarms = 1; | ||
| 275 | schedule (buf); | ||
| 276 | defer_alarms = 0; | ||
| 277 | notify (); | ||
| 278 | alarm_deferred = 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* Handle incoming signal SIG. */ | ||
| 282 | |||
| 283 | SIGTYPE | ||
| 284 | sigcatch (sig) | ||
| 285 | int sig; | ||
| 286 | { | ||
| 287 | struct event *ep; | ||
| 288 | |||
| 289 | /* required on older UNIXes; harmless on newer ones */ | ||
| 290 | signal (sig, sigcatch); | ||
| 291 | |||
| 292 | switch (sig) | ||
| 293 | { | ||
| 294 | case SIGALRM: | ||
| 295 | if (defer_alarms) | ||
| 296 | alarm_deferred = 1; | ||
| 297 | else | ||
| 298 | notify (); | ||
| 299 | break; | ||
| 300 | case SIGTERM: | ||
| 301 | fprintf (stderr, "Events still queued:\n"); | ||
| 302 | for (ep = events; ep < events + num_events; ep++) | ||
| 303 | fprintf (stderr, "%d = %ld @ %s\n", | ||
| 304 | ep - events, ep->reply_at, ep->token); | ||
| 305 | exit (0); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | /*ARGSUSED*/ | ||
| 311 | int | ||
| 312 | main (argc, argv) | ||
| 313 | int argc; | ||
| 314 | char **argv; | ||
| 315 | { | ||
| 316 | for (pname = argv[0] + strlen (argv[0]); | ||
| 317 | *pname != '/' && pname != argv[0]; | ||
| 318 | pname--); | ||
| 319 | if (*pname == '/') | ||
| 320 | pname++; | ||
| 321 | |||
| 322 | events_size = 16; | ||
| 323 | events = ((struct event *) malloc (events_size * sizeof (*events))); | ||
| 324 | num_events = 0; | ||
| 325 | |||
| 326 | signal (SIGALRM, sigcatch); | ||
| 327 | signal (SIGTERM, sigcatch); | ||
| 328 | |||
| 329 | /* Loop reading commands from standard input | ||
| 330 | and scheduling alarms accordingly. | ||
| 331 | The alarms are handled asynchronously, while we wait for commands. */ | ||
| 332 | while (1) | ||
| 333 | getevent (); | ||
| 334 | } | ||
| 335 | |||
| 336 | #ifndef HAVE_STRERROR | ||
| 337 | char * | ||
| 338 | strerror (errnum) | ||
| 339 | int errnum; | ||
| 340 | { | ||
| 341 | extern char *sys_errlist[]; | ||
| 342 | extern int sys_nerr; | ||
| 343 | |||
| 344 | if (errnum >= 0 && errnum < sys_nerr) | ||
| 345 | return sys_errlist[errnum]; | ||
| 346 | return (char *) "Unknown error"; | ||
| 347 | } | ||
| 348 | |||
| 349 | #endif /* ! HAVE_STRERROR */ | ||
| 350 | |||
| 351 | long * | ||
| 352 | xmalloc (size) | ||
| 353 | int size; | ||
| 354 | { | ||
| 355 | register long *val; | ||
| 356 | |||
| 357 | val = (long *) malloc (size); | ||
| 358 | |||
| 359 | if (!val && size) | ||
| 360 | { | ||
| 361 | fprintf (stderr, "timer: virtual memory exceeded\n"); | ||
| 362 | exit (1); | ||
| 363 | } | ||
| 364 | |||
| 365 | return val; | ||
| 366 | } | ||
| 367 | |||
| 368 | /* timer.c ends here */ | ||