Brent Benson's patch to support `cd -'.
[emacs.git] / lib-src / timer.c
blob84c384c9f226a32b2ad913b44e1058c5fd00ddde
1 /* timer.c --- daemon to provide a tagged interval timer service
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.
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
12 documented and rewritten for portability by esr@snark,thyrsus.com,
13 Aug 7 1992. */
15 #include <stdio.h>
16 #include <signal.h>
17 #include <fcntl.h> /* FASYNC */
18 #include <sys/types.h> /* time_t */
20 #include "../src/config.h"
21 #ifdef USG
22 #undef SIGIO
23 #define SIGIO SIGUSR1
24 #endif
26 extern int errno;
27 extern char *sys_errlist[], *malloc ();
28 extern time_t time ();
31 * The field separator for input. This character shouldn't be legal in a date,
32 * and should be printable so event strings are readable by people. Was
33 * originally ';', then got changed to bogus `\001'.
35 #define FS '@'
37 struct event
39 char *token;
40 time_t reply_at;
42 int events_size; /* How many slots have we allocated? */
43 int num_events; /* How many are actually scheduled? */
44 struct event *events; /* events[0 .. num_events-1] are the
45 valid events. */
47 char *pname; /* programme name for error messages */
49 /* Accepts a string of two fields seperated by FS.
50 First field is string for getdate, saying when to wake-up.
51 Second field is a token to identify the request. */
52 void
53 schedule (str)
54 char *str;
56 extern time_t getdate ();
57 extern char *strcpy ();
58 time_t now;
59 register char *p;
60 static struct event *ep;
62 /* check entry format */
63 for (p = str; *p && *p != FS; p++)
64 continue;
65 if (!*p)
67 fprintf (stderr, "%s: bad input format: %s\n", pname, str);
68 return;
70 *p++ = 0;
72 /* allocate an event slot */
73 ep = events + num_events;
75 /* If the event array is full, stretch it. After stretching, we know
76 that ep will be pointing to an available event spot. */
77 if (ep == events + events_size)
79 int old_size = events_size;
81 events_size *= 2;
82 events = ((struct event *)
83 realloc (events, events_size * sizeof (struct event)));
84 if (! events)
86 fprintf (stderr, "%s: virtual memory exhausted.\n", pname);
88 /* Should timer exit now? Well, we've still got other
89 events in the queue, and more memory might become
90 available in the future, so we'll just toss this event.
91 This will screw up whoever scheduled the event, but
92 maybe someone else will survive. */
93 return;
96 while (old_size < events_size)
97 events[old_size++].token = NULL;
100 /* Don't allow users to schedule events in past time. */
101 ep->reply_at = get_date (str, NULL);
102 if (ep->reply_at - time (&now) < 0)
104 fprintf (stderr, "%s: bad time spec: %s%c%s\n", pname, str, FS, p);
105 return;
108 /* save the event description */
109 ep->token = (char *) malloc ((unsigned) strlen (p) + 1);
110 if (! ep->token)
112 fprintf (stderr, "%s: malloc %s: %s%c%s\n",
113 pname, sys_errlist[errno], str, FS, p);
114 return;
117 strcpy (ep->token, p);
118 num_events++;
121 void
122 notify ()
124 time_t now, tdiff, waitfor = -1;
125 register struct event *ep;
127 now = time ((time_t *) NULL);
129 for (ep = events; ep < events + num_events; ep++)
130 /* Are any events ready to fire? */
131 if (ep->reply_at <= now)
133 fputs (ep->token, stdout);
134 putc ('\n', stdout);
135 fflush (stdout);
136 free (ep->token);
138 /* We now have a hole in the event array; fill it with the last
139 event. */
140 ep->token = events[num_events].token;
141 ep->reply_at = events[num_events].reply_at;
142 num_events--;
144 /* We ought to scan this event again. */
145 ep--;
147 else
149 /* next timeout should be the soonest of any remaining */
150 if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0)
151 waitfor = (long)tdiff;
154 /* If there are no more events, we needn't bother setting an alarm. */
155 if (num_events > 0)
156 alarm (waitfor);
159 void
160 getevent ()
162 int i;
163 char *buf;
164 int buf_size;
166 /* In principle the itimer should be disabled on entry to this
167 function, but it really doesn't make any important difference
168 if it isn't. */
170 buf_size = 80;
171 buf = (char *) malloc (buf_size);
173 /* Read a line from standard input, expanding buf if it is too short
174 to hold the line. */
175 for (i = 0; ; i++)
177 int c;
179 if (i >= buf_size)
181 buf_size *= 2;
182 buf = (char *) realloc (buf, buf_size);
184 /* If we're out of memory, toss this event. */
187 c = getchar ();
189 while (c != '\n' && c != EOF);
191 return;
194 c = getchar ();
196 if (c == EOF)
197 exit (0);
199 if (c == '\n')
201 buf[i] = '\0';
202 break;
205 buf[i] = c;
208 /* Register the event. */
209 schedule (buf);
210 free (buf);
212 /* Who knows what this interrupted, or if it said "now"? */
213 notify ();
216 SIGTYPE
217 sigcatch (sig)
218 int sig;
219 /* dispatch on incoming signal, then restore it */
221 struct event *ep;
223 switch (sig)
225 case SIGALRM:
226 notify ();
227 break;
228 case SIGIO:
229 getevent ();
230 break;
231 case SIGTERM:
232 fprintf (stderr, "Events still queued:\n");
233 for (ep = events; ep < events + num_events; ep++)
234 fprintf (stderr, "%d = %ld @ %s\n",
235 ep - events, ep->reply_at, ep->token);
236 exit (0);
237 break;
240 /* required on older UNIXes; harmless on newer ones */
241 signal (sig, sigcatch);
244 /*ARGSUSED*/
246 main (argc, argv)
247 int argc;
248 char **argv;
250 for (pname = argv[0] + strlen (argv[0]);
251 *pname != '/' && pname != argv[0];
252 pname--);
253 if (*pname == '/')
254 pname++;
256 events_size = 16;
257 events = ((struct event *) malloc (events_size * sizeof (*events)));
258 num_events = 0;
260 signal (SIGIO, sigcatch);
261 signal (SIGALRM, sigcatch);
262 signal (SIGTERM, sigcatch);
264 #ifndef USG
265 if (fcntl (0, F_SETOWN, getpid ()) == -1)
267 fprintf (stderr, "%s: can't set ownership of stdin\n", pname);
268 fprintf (stderr, "%s\n", sys_errlist[errno]);
269 exit (1);
271 if (fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | FASYNC) == -1)
273 fprintf (stderr, "%s: can't request asynchronous I/O on stdin\n", pname);
274 fprintf (stderr, "%s\n", sys_errlist[errno]);
275 exit (1);
277 #endif /* USG */
279 while (1) pause ();
282 /* timer.c ends here */