aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src/timer.c
diff options
context:
space:
mode:
authorJim Blandy1992-08-12 12:57:12 +0000
committerJim Blandy1992-08-12 12:57:12 +0000
commit9e2b097b2608f55d27df1e3521575be8dd670a0c (patch)
tree957a68070b4ce12f0392726f5446e93b88fb80bb /lib-src/timer.c
parent7e1dae733a5eda79d5681349ca39bfc36ca27871 (diff)
downloademacs-9e2b097b2608f55d27df1e3521575be8dd670a0c.tar.gz
emacs-9e2b097b2608f55d27df1e3521575be8dd670a0c.zip
*** empty log message ***
Diffstat (limited to 'lib-src/timer.c')
-rw-r--r--lib-src/timer.c284
1 files changed, 175 insertions, 109 deletions
diff --git a/lib-src/timer.c b/lib-src/timer.c
index d7084bfcdc4..2c1b9a729f6 100644
--- a/lib-src/timer.c
+++ b/lib-src/timer.c
@@ -1,155 +1,221 @@
1/*
2 * timer.c --- daemon to provide a tagged interval timer service
3 *
4 * This little daemon runs forever waiting for signals. SIGIO (or SIGUSR1)
5 * causes it to read an event spec from stdin; that is, a date followed by
6 * colon followed by an event label. SIGALRM causes it to check its queue
7 * for events attached to the current second; if one is found, its label
8 * is written to stdout. SIGTERM causes it to terminate, printing a list
9 * of pending events.
10 *
11 * This program is intended to be used with the lisp package called timer.el.
12 * It was written anonymously in 1990. This version was documented and
13 * rewritten for portability by esr@snark,thyrsus.com, Aug 7 1992.
14 */
1#include <stdio.h> 15#include <stdio.h>
2#include <signal.h> 16#include <signal.h>
3#include <fcntl.h> /* FASYNC */ 17#include <fcntl.h> /* FASYNC */
4#ifdef USG /* FASYNC for SysV */
5#include <sys/file.h>
6#endif
7#include <sys/time.h> /* itimer */
8#include <sys/types.h> /* time_t */ 18#include <sys/types.h> /* time_t */
9 19
20#include "../src/config.h"
21#ifdef USG
22#undef SIGIO
23#define SIGIO SIGUSR1
24#endif
25
10extern int errno; 26extern int errno;
11extern char *sys_errlist[], *malloc(); 27extern char *sys_errlist[], *malloc();
12extern time_t time(); 28extern time_t time();
13 29
14#define MAXEVENTS 256 30#define MAXEVENTS 256
15#define FS 1 /* field seperator for input */
16 31
17struct event { 32/*
18 char *token; 33 * The field separator for input. This character shouldn't be legal in a date,
19 time_t reply_at; 34 * and should be printable so event strings are readable by people. Was
20} *events[MAXEVENTS]; 35 * originally ';', then got changed to bogus `\001'.
36 */
37#define FS '@'
38
39struct event
40{
41 char *token;
42 time_t reply_at;
43}
44events[MAXEVENTS];
21 45
22int slot; /* The next open place in the events array */
23int mevent = 0; /* 1+ the highest event number */
24char *pname; /* programme name for error messages */ 46char *pname; /* programme name for error messages */
25 47
26/* Accepts a string of two fields seperated by a ';' 48/* Accepts a string of two fields seperated by FS.
27 * First field is string for getdate, saying when to wake-up. 49 * First field is string for getdate, saying when to wake-up.
28 * Second field is a token to identify the request. 50 * Second field is a token to identify the request.
29 */ 51 */
30struct event * 52void schedule(str)
31schedule(str) 53 char *str;
32 char *str;
33
34{ 54{
35 extern time_t getdate(); 55 extern time_t getdate();
36 extern char *strcpy(); 56 extern char *strcpy();
37 time_t now; 57 time_t now;
38 register char *p; 58 register char *p;
39 static struct event e; 59 static struct event *ep;
40 60
41 for(p = str; *p && *p != FS; p++); 61#ifdef DEBUG
42 if (!*p) { 62 (void) fprintf(stderr, "Timer sees: %s", str);
43 (void)fprintf(stderr, "%s: bad input format: %s", pname, str); 63#endif /* DEBUG */
44 return((struct event *)NULL); 64
45 } 65 /* check entry format */
46 *p++ = 0; 66 for(p = str; *p && *p != FS; p++)
67 continue;
68 if (!*p)
69 {
70 (void)fprintf(stderr, "%s: bad input format: %s", pname, str);
71 return;
72 }
73 *p++ = 0;
47 74
48 if ((e.reply_at = get_date(str, NULL)) - time(&now) < 0) { 75 /* allocate an event slot */
49 (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p); 76 for(ep = events; ep < events + MAXEVENTS; ep++)
50 return((struct event *)NULL); 77 if (ep->token == (char *)NULL)
51 } 78 break;
52 79 if (ep == events + MAXEVENTS)
53 if ((e.token = malloc((unsigned)strlen(p) + 1)) == NULL) { 80 (void) fprintf(stderr, "%s: too many events: %s", pname, str);
54 (void)fprintf(stderr, "%s: malloc %s: %s%c%s", 81
55 pname, sys_errlist[errno], str, FS, p); 82 /* don't allow users to schedule events in past time */
56 return((struct event *)NULL); 83 else if ((ep->reply_at = get_date(str, NULL)) - time(&now) < 0)
57 } 84 (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p);
58 (void)strcpy(e.token,p); 85
59 86 /* save the event description */
60 return(&e); 87 else if ((ep->token = malloc((unsigned)strlen(p) + 1)) == NULL)
88 (void)fprintf(stderr, "%s: malloc %s: %s%c%s",
89 pname, sys_errlist[errno], str, FS, p);
90 else
91 {
92 (void)strcpy(ep->token, p);
93
94#ifdef DEBUG
95 (void) fprintf(stderr,
96 "New event: %ld: %s", ep->reply_at, ep->token);
97#endif /* DEBUG */
98 }
61} 99}
62 100
63void 101void
64notify() 102notify()
65
66{ 103{
67 time_t now, tdiff; 104 time_t now, tdiff, waitfor = -1;
68 register int i, newmax = 0; 105 register struct event *ep;
69 /* I prefer using the interval timer rather than alarm(); the latter 106
70 could be substituted if portability requires it. */ 107 now = time((time_t *)NULL);
71 struct itimerval itimer; 108
72 109 for(ep = events; ep < events + MAXEVENTS; ep++)
73 now = time((time_t *)NULL); 110 if (ep->token)
74 slot = mevent; 111 {
75 itimer.it_interval.tv_sec = itimer.it_interval.tv_usec = 0; 112 /* any events ready to fire? */
76 itimer.it_value.tv_usec = 0; 113 if (ep->reply_at <= now)
77 itimer.it_value.tv_sec = -1; 114 {
78 115#ifdef DEBUG
79 for(i=0; i < mevent; i++) { 116 (void) fprintf(stderr,
80 while (events[i] && events[i]->reply_at <= now) { 117 "Event %d firing: %ld @ %s",
81 (void)fputs(events[i]->token, stdout); 118 (ep - events), ep->reply_at, ep->token);
82 free(events[i]->token); 119#endif /* DEBUG */
83 free((char *)events[i]); 120 (void)fputs(ep->token, stdout);
84 events[i] = 0; 121 free(ep->token);
85 } 122 ep->token = (char *)NULL;
86 123 }
87 if (events[i]) { 124 else
88 newmax = i+1; 125 {
89 if ((tdiff = events[i]->reply_at - now) < (time_t)itimer.it_value.tv_sec 126#ifdef DEBUG
90 || itimer.it_value.tv_sec < 0) 127 (void) fprintf(stderr,
91 /* next timeout */ 128 "Event %d still waiting: %ld @ %s",
92 itimer.it_value.tv_sec = (long)tdiff; 129 (ep - events), ep->reply_at, ep->token);
93 } else { 130#endif /* DEBUG */
94 /* Keep slot as the lowest unused events element */ 131
95 if (i < slot) slot = i; 132 /* next timeout should be the soonest of any remaining */
133 if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0)
134 waitfor = (long)tdiff;
135 }
136 }
137
138 /* If there's no more events, SIGIO should be next wake-up */
139 if (waitfor != -1)
140 {
141#ifdef DEBUG
142 (void) fprintf(stderr,
143 "Setting %d-second alarm\n", waitfor);
144#endif /* DEBUG */
145 (void)alarm(waitfor);
96 } 146 }
97 }
98 /* if the array is full to mevent, slot should be the next available spot */
99 if (slot > (mevent = newmax)) slot = mevent;
100 /* If there's no more events, SIGIO should be next wake-up */
101 if (mevent) (void)setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL);
102} 147}
103 148
104void 149void
105getevent() 150getevent()
151{
152 extern char *fgets();
153 struct event *ep;
154 char buf[BUFSIZ];
155
156 /* in principle the itimer should be disabled on entry to this function,
157 but it really doesn't make any important difference if it isn't */
158
159 if (fgets(buf, sizeof(buf), stdin) == NULL)
160 exit(0);
161
162 /* register the event */
163 schedule(buf);
106 164
165 /* Who knows what this interrupted, or if it said "now"? */
166 notify();
167}
168
169void
170sigcatch(sig)
171/* dispatch on incoming signal, then restore it */
107{ 172{
108 extern char *fgets(); 173 struct event *ep;
109 struct event *ep; 174
110 char buf[256]; 175 switch(sig)
111 176 {
112 /* in principle the itimer should be disabled on entry to this function, 177 case SIGALRM:
113 but it really doesn't make any important difference if it isn't */ 178#ifdef DEBUG
114 179 (void) fprintf(stderr, "Alarm signal received\n");
115 if (fgets(buf, sizeof(buf), stdin) == NULL) exit(0); 180#endif /* DEBUG */
116 181 notify();
117 if (slot == MAXEVENTS) 182 break;
118 (void)fprintf(stderr, "%s: too many events: %s", pname, buf); 183 case SIGIO:
119 184 getevent();
120 else { 185 break;
121 if ((events[slot] = (struct event *)malloc((sizeof(struct event)))) 186 case SIGTERM:
122 == NULL) 187 (void) fprintf(stderr, "Events still queued:\n");
123 (void)fprintf(stderr,"%s: malloc %s: %s", pname, sys_errlist[errno],buf); 188 for (ep = events; ep < events + MAXEVENTS; ep++)
124 189 if (ep->token)
125 else { 190 (void) fprintf(stderr, "%d = %ld @ %s",
126 if ((ep = schedule(buf)) == NULL) 191 ep - events, ep->reply_at, ep->token);
127 free((char *)events[slot]), events[slot] = 0; 192 exit(0);
128 193 break;
129 else { 194 }
130 memcpy((char *)events[slot],(char *)ep,sizeof(struct event)); 195
131 if (slot == mevent) mevent++; 196 /* required on older UNIXes; harmless on newer ones */
132 } /* schedule */ 197 (void) signal(sig, sigcatch);
133 } /* malloc */
134 } /* limit events */
135 /* timing, timing. Who knows what this interrupted, or if it said "now"? */
136 notify();
137} 198}
138 199
139/*ARGSUSED*/ 200/*ARGSUSED*/
140int 201int
141main(argc, argv) 202main(argc, argv)
142 int argc; 203 int argc;
143 char **argv; 204 char **argv;
144
145{ 205{
146 for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0]; 206 for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0];
147 pname--); 207 pname--);
148 if (*pname == '/') pname++; 208 if (*pname == '/') pname++;
149 209
150 (void)signal(SIGIO, getevent); 210 (void)signal(SIGIO, sigcatch);
151 (void)signal(SIGALRM, notify); 211 (void)signal(SIGALRM, sigcatch);
212 (void)signal(SIGTERM, sigcatch);
213
214#ifndef USG
152 (void)fcntl(0, F_SETFL, FASYNC); 215 (void)fcntl(0, F_SETFL, FASYNC);
216#endif /* USG */
153 217
154 while (1) pause(); 218 while (1) pause();
155} 219}
220
221/* timer.c ends here */