Mercurial > emacs
annotate src/atimer.c @ 27551:2dd8115a9f72
(delphi): Add :version to defgroup.
author | Dave Love <fx@gnu.org> |
---|---|
date | Tue, 01 Feb 2000 14:32:21 +0000 |
parents | 7580a16f676c |
children | cf2edc15eaa9 |
rev | line source |
---|---|
27433 | 1 /* Asynchronous timers. |
2 Copyright (C) 2000 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 #include <config.h> | |
22 #include <lisp.h> | |
23 #include <signal.h> | |
24 #include <syssignal.h> | |
25 #include <systime.h> | |
26 #include <blockinput.h> | |
27 #include <atimer.h> | |
28 #include <stdio.h> | |
29 | |
30 #ifdef HAVE_UNISTD_H | |
31 #include <unistd.h> | |
32 #endif | |
33 | |
34 #ifdef HAVE_SYS_TIME_H | |
35 #include <sys/time.h> | |
36 #endif | |
37 | |
38 /* The ubiquitous min/max macros. */ | |
39 | |
40 #define max(X, Y) ((X) > (Y) ? (X) : (Y)) | |
41 #define min(X, Y) ((X) < (Y) ? (X) : (Y)) | |
42 | |
43 /* Free-list of atimer structures. */ | |
44 | |
45 static struct atimer *free_atimers; | |
46 | |
47 /* List of active atimers, sorted by expiration time. The timer that | |
48 will become ripe next is always at the front of this list. */ | |
49 | |
50 static struct atimer *atimers; | |
51 | |
52 /* Non-zero means alarm_signal_handler has found ripe timers but | |
53 interrupt_input_blocked was non-zero. In this case, timer | |
54 functions are not called until the next UNBLOCK_INPUT because timer | |
55 functions are expected to call X, and X cannot be assumed to be | |
56 reentrant. */ | |
57 | |
58 int pending_atimers; | |
59 | |
60 /* Block/unblock SIGALRM.. */ | |
61 | |
62 #define BLOCK_ATIMERS sigblock (sigmask (SIGALRM)) | |
63 #define UNBLOCK_ATIMERS sigunblock (sigmask (SIGALRM)) | |
64 | |
65 /* Function prototypes. */ | |
66 | |
67 static void set_alarm P_ ((void)); | |
68 static void schedule_atimer P_ ((struct atimer *)); | |
69 | |
70 | |
71 /* Start a new atimer of type TYPE. TIME specifies when the timer is | |
72 ripe. FN is the function to call when the timer fires. | |
73 CLIENT_DATA is stored in the client_data member of the atimer | |
74 structure returned and so made available to FN when it is called. | |
75 | |
76 If TYPE is ATIMER_ABSOLUTE, TIME is the absolute time at which the | |
77 timer fires. | |
78 | |
79 If TYPE is ATIMER_RELATIVE, the timer is ripe TIME s/us in the | |
80 future. | |
81 | |
82 In both cases, the timer is automatically freed after it has fired. | |
83 | |
84 If TYPE is ATIMER_CONTINUOUS, the timer fires every TIME s/us. | |
85 | |
86 Value is a pointer to the atimer started. It can be used in calls | |
87 to cancel_atimer; don't free it yourself. */ | |
88 | |
89 struct atimer * | |
90 start_atimer (type, time, fn, client_data) | |
91 enum atimer_type type; | |
92 EMACS_TIME time; | |
93 atimer_callback fn; | |
94 void *client_data; | |
95 { | |
96 struct atimer *t; | |
97 | |
98 /* Round TIME up to the next full second if we don't have | |
99 itimers. */ | |
100 #ifndef HAVE_SETITIMER | |
101 if (EMACS_USECS (time) != 0) | |
102 { | |
27452
7580a16f676c
(start_atimer) [!HAVE_SETITIMER]: Use EMACS_SET_SECS
Eli Zaretskii <eliz@gnu.org>
parents:
27433
diff
changeset
|
103 EMACS_SET_USECS (time, 0); |
7580a16f676c
(start_atimer) [!HAVE_SETITIMER]: Use EMACS_SET_SECS
Eli Zaretskii <eliz@gnu.org>
parents:
27433
diff
changeset
|
104 EMACS_SET_SECS (time, EMACS_SECS (time) + 1); |
27433 | 105 } |
106 #endif /* not HAVE_SETITIMER */ | |
107 | |
108 /* Get an atimer structure from the free-list, or allocate | |
109 a new one. */ | |
110 if (free_atimers) | |
111 { | |
112 t = free_atimers; | |
113 free_atimers = t->next; | |
114 } | |
115 else | |
116 t = (struct atimer *) xmalloc (sizeof *t); | |
117 | |
118 /* Fill the atimer structure. */ | |
119 bzero (t, sizeof *t); | |
120 t->type = type; | |
121 t->fn = fn; | |
122 t->client_data = client_data; | |
123 | |
124 BLOCK_ATIMERS; | |
125 | |
126 /* Compute the timer's expiration time. */ | |
127 switch (type) | |
128 { | |
129 case ATIMER_ABSOLUTE: | |
130 t->expiration = time; | |
131 break; | |
132 | |
133 case ATIMER_RELATIVE: | |
134 EMACS_GET_TIME (t->expiration); | |
135 EMACS_ADD_TIME (t->expiration, t->expiration, time); | |
136 break; | |
137 | |
138 case ATIMER_CONTINUOUS: | |
139 EMACS_GET_TIME (t->expiration); | |
140 EMACS_ADD_TIME (t->expiration, t->expiration, time); | |
141 t->interval = time; | |
142 break; | |
143 } | |
144 | |
145 /* Insert the timer in the list of active atimers. */ | |
146 schedule_atimer (t); | |
147 UNBLOCK_ATIMERS; | |
148 | |
149 /* Arrange for a SIGALRM at the time the next atimer is ripe. */ | |
150 set_alarm (); | |
151 | |
152 return t; | |
153 } | |
154 | |
155 | |
156 /* Cancel and free atimer TIMER. */ | |
157 | |
158 void | |
159 cancel_atimer (timer) | |
160 struct atimer *timer; | |
161 { | |
162 struct atimer *t, *prev; | |
163 | |
164 BLOCK_ATIMERS; | |
165 | |
166 /* See if TIMER is active. */ | |
167 for (t = atimers, prev = 0; t && t != timer; t = t->next) | |
168 ; | |
169 | |
170 /* If it is, take it off the list of active timers, put in on the | |
171 free-list. We don't bother to arrange for setting a different | |
172 alarm time, since a too early one doesn't hurt. */ | |
173 if (t) | |
174 { | |
175 if (prev) | |
176 prev->next = t->next; | |
177 else | |
178 atimers = t->next; | |
179 | |
180 t->next = free_atimers; | |
181 free_atimers = t; | |
182 } | |
183 | |
184 UNBLOCK_ATIMERS; | |
185 } | |
186 | |
187 | |
188 /* Arrange for a SIGALRM to arrive when the next timer is ripe. */ | |
189 | |
190 static void | |
191 set_alarm () | |
192 { | |
193 | |
194 #if defined (USG) && !defined (POSIX_SIGNALS) | |
195 /* USG systems forget handlers when they are used; | |
196 must reestablish each time. */ | |
197 signal (SIGALRM, alarm_signal_handler); | |
198 #endif /* USG */ | |
199 | |
200 if (atimers) | |
201 { | |
202 EMACS_TIME now, time; | |
203 #ifdef HAVE_SETITIMER | |
204 struct itimerval it; | |
205 #endif | |
206 | |
207 /* Determine s/us till the next timer is ripe. */ | |
208 EMACS_GET_TIME (now); | |
209 EMACS_SUB_TIME (time, atimers->expiration, now); | |
210 | |
211 #ifdef HAVE_SETITIMER | |
212 /* Don't set the interval to 0; this disables the timer. */ | |
213 if (EMACS_TIME_LE (atimers->expiration, now)) | |
214 { | |
215 EMACS_SET_SECS (time, 0); | |
216 EMACS_SET_USECS (time, 1000); | |
217 } | |
218 | |
219 bzero (&it, sizeof it); | |
220 it.it_value = time; | |
221 setitimer (ITIMER_REAL, &it, 0); | |
222 #else /* not HAVE_SETITIMER */ | |
223 alarm (max (EMACS_SECS (time), 1)); | |
224 #endif /* not HAVE_SETITIMER */ | |
225 } | |
226 } | |
227 | |
228 | |
229 /* Insert timer T into the list of active atimers `atimers', keeping | |
230 the list sorted by expiration time. T must not be in this list | |
231 already. */ | |
232 | |
233 static void | |
234 schedule_atimer (t) | |
235 struct atimer *t; | |
236 { | |
237 struct atimer *a = atimers, *prev = NULL; | |
238 | |
239 /* Look for the first atimer that is ripe after T. */ | |
240 while (a && EMACS_TIME_GT (t->expiration, a->expiration)) | |
241 prev = a, a = a->next; | |
242 | |
243 /* Insert T in front of the atimer found, if any. */ | |
244 if (prev) | |
245 prev->next = t; | |
246 else | |
247 atimers = t; | |
248 | |
249 t->next = a; | |
250 } | |
251 | |
252 | |
253 /* Signal handler for SIGALRM. SIGNO is the signal number, i.e. | |
254 SIGALRM. */ | |
255 | |
256 SIGTYPE | |
257 alarm_signal_handler (signo) | |
258 int signo; | |
259 { | |
260 EMACS_TIME now; | |
261 | |
262 EMACS_GET_TIME (now); | |
263 pending_atimers = 0; | |
264 | |
265 while (atimers | |
266 && (pending_atimers = interrupt_input_blocked) == 0 | |
267 && EMACS_TIME_LE (atimers->expiration, now)) | |
268 { | |
269 struct atimer *t; | |
270 | |
271 t = atimers; | |
272 atimers = atimers->next; | |
273 t->fn (t); | |
274 | |
275 if (t->type == ATIMER_CONTINUOUS) | |
276 { | |
277 EMACS_ADD_TIME (t->expiration, now, t->interval); | |
278 schedule_atimer (t); | |
279 } | |
280 else | |
281 { | |
282 t->next = free_atimers; | |
283 free_atimers = t; | |
284 } | |
285 | |
286 EMACS_GET_TIME (now); | |
287 } | |
288 | |
289 #if defined (USG) && !defined (POSIX_SIGNALS) | |
290 /* USG systems forget handlers when they are used; | |
291 must reestablish each time. */ | |
292 signal (SIGALRM, alarm_signal_handler); | |
293 #endif /* USG */ | |
294 | |
295 set_alarm (); | |
296 } | |
297 | |
298 | |
299 /* Call alarm_signal_handler for pending timers. */ | |
300 | |
301 void | |
302 do_pending_atimers () | |
303 { | |
304 if (pending_atimers) | |
305 { | |
306 BLOCK_ATIMERS; | |
307 alarm_signal_handler (SIGALRM); | |
308 UNBLOCK_ATIMERS; | |
309 } | |
310 } | |
311 | |
312 | |
313 /* Turn alarms on/off. This seems to be temporarily necessary on | |
314 some systems like HPUX (see process.c). */ | |
315 | |
316 void | |
317 turn_on_atimers (on) | |
318 int on; | |
319 { | |
320 if (on) | |
321 { | |
322 signal (SIGALRM, alarm_signal_handler); | |
323 set_alarm (); | |
324 } | |
325 else | |
326 alarm (0); | |
327 } | |
328 | |
329 | |
330 void | |
331 init_atimer () | |
332 { | |
333 free_atimers = atimers = NULL; | |
334 pending_atimers = 0; | |
335 signal (SIGALRM, alarm_signal_handler); | |
336 } |