This source file includes following definitions.
- block_atimers
- unblock_atimers
- start_atimer
- cancel_atimer
- append_atimer_lists
- stop_other_atimers
- run_all_atimers
- set_alarm
- schedule_atimer
- run_timers
- handle_alarm_signal
- timerfd_callback
- do_pending_atimers
- turn_on_atimers
- debug_timer_callback
- DEFUN
- have_buggy_timerfd
- init_atimer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21 #ifdef WINDOWSNT
22 #define raise(s) w32_raise(s)
23 #endif
24
25 #include "lisp.h"
26 #include "keyboard.h"
27 #include "syssignal.h"
28 #include "systime.h"
29 #include "atimer.h"
30 #include <unistd.h>
31
32 #ifdef HAVE_TIMERFD
33 #include <errno.h>
34 #include <sys/timerfd.h>
35 # ifdef CYGWIN
36 # include <sys/utsname.h>
37 # endif
38 #endif
39
40 #ifdef MSDOS
41 #include "msdos.h"
42 #endif
43
44
45
46 static struct atimer *free_atimers;
47
48
49
50
51 static struct atimer *stopped_atimers;
52
53
54
55
56 static struct atimer *atimers;
57
58 #ifdef HAVE_ITIMERSPEC
59
60
61 static timer_t alarm_timer;
62 static bool alarm_timer_ok;
63
64 # ifdef HAVE_TIMERFD
65
66 static int timerfd;
67 # else
68 enum { timerfd = -1 };
69 # endif
70 #endif
71
72
73
74 static void
75 block_atimers (sigset_t *oldset)
76 {
77 sigset_t blocked;
78 sigemptyset (&blocked);
79 sigaddset (&blocked, SIGALRM);
80 sigaddset (&blocked, SIGINT);
81 pthread_sigmask (SIG_BLOCK, &blocked, oldset);
82 }
83 static void
84 unblock_atimers (sigset_t const *oldset)
85 {
86 pthread_sigmask (SIG_SETMASK, oldset, 0);
87 }
88
89
90
91 static void set_alarm (void);
92 static void schedule_atimer (struct atimer *);
93 static struct atimer *append_atimer_lists (struct atimer *,
94 struct atimer *);
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 struct atimer *
115 start_atimer (enum atimer_type type, struct timespec timestamp,
116 atimer_callback fn, void *client_data)
117 {
118 struct atimer *t;
119 sigset_t oldset;
120
121
122 #if ! (defined HAVE_ITIMERSPEC || defined HAVE_SETITIMER)
123 if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t))
124 timestamp = make_timespec (timestamp.tv_sec + 1, 0);
125 #endif
126
127
128
129 if (free_atimers)
130 {
131 t = free_atimers;
132 free_atimers = t->next;
133 }
134 else
135 t = xmalloc (sizeof *t);
136
137
138 memset (t, 0, sizeof *t);
139 t->type = type;
140 t->fn = fn;
141 t->client_data = client_data;
142
143 block_atimers (&oldset);
144
145
146 switch (type)
147 {
148 case ATIMER_ABSOLUTE:
149 t->expiration = timestamp;
150 break;
151
152 case ATIMER_RELATIVE:
153 t->expiration = timespec_add (current_timespec (), timestamp);
154 break;
155
156 case ATIMER_CONTINUOUS:
157 t->expiration = timespec_add (current_timespec (), timestamp);
158 t->interval = timestamp;
159 break;
160 }
161
162
163 schedule_atimer (t);
164 unblock_atimers (&oldset);
165
166
167 set_alarm ();
168
169 return t;
170 }
171
172
173
174
175 void
176 cancel_atimer (struct atimer *timer)
177 {
178 int i;
179 sigset_t oldset;
180
181 block_atimers (&oldset);
182
183 for (i = 0; i < 2; ++i)
184 {
185 struct atimer *t, *prev;
186 struct atimer **list = i ? &stopped_atimers : &atimers;
187
188
189 for (t = *list, prev = NULL; t && t != timer; prev = t, t = t->next)
190 ;
191
192
193
194
195 if (t)
196 {
197 if (prev)
198 prev->next = t->next;
199 else
200 *list = t->next;
201
202 t->next = free_atimers;
203 free_atimers = t;
204 break;
205 }
206 }
207
208 unblock_atimers (&oldset);
209 }
210
211
212
213
214
215 static struct atimer *
216 append_atimer_lists (struct atimer *list_1, struct atimer *list_2)
217 {
218 if (list_1 == NULL)
219 return list_2;
220 else if (list_2 == NULL)
221 return list_1;
222 else
223 {
224 struct atimer *p;
225
226 for (p = list_1; p->next; p = p->next)
227 ;
228 p->next = list_2;
229 return list_1;
230 }
231 }
232
233
234
235
236 void
237 stop_other_atimers (struct atimer *t)
238 {
239 sigset_t oldset;
240 block_atimers (&oldset);
241
242 if (t)
243 {
244 struct atimer *p, *prev;
245
246
247 for (p = atimers, prev = NULL; p && p != t; prev = p, p = p->next)
248 ;
249
250 if (p == t)
251 {
252 if (prev)
253 prev->next = t->next;
254 else
255 atimers = t->next;
256 t->next = NULL;
257 }
258 else
259
260 t = NULL;
261 }
262
263 stopped_atimers = append_atimer_lists (atimers, stopped_atimers);
264 atimers = t;
265 unblock_atimers (&oldset);
266 }
267
268
269
270
271
272 void
273 run_all_atimers (void)
274 {
275 if (stopped_atimers)
276 {
277 struct atimer *t = atimers;
278 struct atimer *next;
279 sigset_t oldset;
280
281 block_atimers (&oldset);
282 atimers = stopped_atimers;
283 stopped_atimers = NULL;
284
285 while (t)
286 {
287 next = t->next;
288 schedule_atimer (t);
289 t = next;
290 }
291
292 unblock_atimers (&oldset);
293 }
294 }
295
296
297
298
299 static void
300 set_alarm (void)
301 {
302 if (atimers)
303 {
304 #ifdef HAVE_ITIMERSPEC
305 if (0 <= timerfd || alarm_timer_ok)
306 {
307 bool exit = false;
308 struct itimerspec ispec;
309 ispec.it_value = atimers->expiration;
310 ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0;
311 if (alarm_timer_ok
312 && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0)
313 exit = true;
314
315
316
317
318
319
320 # ifdef CYGWIN
321 if (exit)
322 return;
323 # endif
324
325 # ifdef HAVE_TIMERFD
326 if (0 <= timerfd
327 && timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0)
328 {
329 add_timer_wait_descriptor (timerfd);
330 exit = true;
331 }
332 # endif
333
334 if (exit)
335 return;
336 }
337 #endif
338
339
340 struct timespec now = current_timespec ();
341 if (timespec_cmp (atimers->expiration, now) <= 0)
342 {
343
344 raise (SIGALRM);
345 }
346 else
347 {
348 struct timespec interval = timespec_sub (atimers->expiration, now);
349
350 #ifdef HAVE_SETITIMER
351 struct itimerval it = {.it_value = make_timeval (interval)};
352 setitimer (ITIMER_REAL, &it, 0);
353 #else
354 alarm (max (interval.tv_sec, 1));
355 #endif
356 }
357 }
358 }
359
360
361
362
363
364
365 static void
366 schedule_atimer (struct atimer *t)
367 {
368 struct atimer *a = atimers, *prev = NULL;
369
370
371 while (a && timespec_cmp (a->expiration, t->expiration) < 0)
372 prev = a, a = a->next;
373
374
375 if (prev)
376 prev->next = t;
377 else
378 atimers = t;
379
380 t->next = a;
381 }
382
383 static void
384 run_timers (void)
385 {
386 struct timespec now = current_timespec ();
387
388 while (atimers && timespec_cmp (atimers->expiration, now) <= 0)
389 {
390 struct atimer *t = atimers;
391 atimers = atimers->next;
392 t->fn (t);
393
394 if (t->type == ATIMER_CONTINUOUS)
395 {
396 t->expiration = timespec_add (now, t->interval);
397 schedule_atimer (t);
398 }
399 else
400 {
401 t->next = free_atimers;
402 free_atimers = t;
403 }
404 }
405
406 set_alarm ();
407 }
408
409
410
411
412
413 static void
414 handle_alarm_signal (int sig)
415 {
416 pending_signals = 1;
417 }
418
419 #ifdef HAVE_TIMERFD
420
421
422
423
424 void
425 timerfd_callback (int fd, void *arg)
426 {
427 ptrdiff_t nbytes;
428 uint64_t expirations;
429
430 eassert (fd == timerfd);
431 nbytes = emacs_read (fd, &expirations, sizeof (expirations));
432
433 if (nbytes == sizeof (expirations))
434 {
435
436 eassert (expirations == 1);
437 do_pending_atimers ();
438 }
439 else if (nbytes < 0)
440
441
442
443 eassert (errno == EAGAIN);
444 else
445
446 emacs_abort ();
447 }
448
449 #endif
450
451
452
453 void
454 do_pending_atimers (void)
455 {
456 if (atimers)
457 {
458 sigset_t oldset;
459 block_atimers (&oldset);
460 run_timers ();
461 unblock_atimers (&oldset);
462 }
463 }
464
465
466
467
468
469 void
470 turn_on_atimers (bool on)
471 {
472 if (on)
473 set_alarm ();
474 else
475 {
476 #ifdef HAVE_ITIMERSPEC
477 struct itimerspec ispec;
478 memset (&ispec, 0, sizeof ispec);
479 if (alarm_timer_ok)
480 timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0);
481 # ifdef HAVE_TIMERFD
482 timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0);
483 # endif
484 #endif
485 alarm (0);
486 }
487 }
488
489
490
491 #ifdef ENABLE_CHECKING
492
493 #define MAXTIMERS 10
494
495 struct atimer_result
496 {
497
498 struct timespec expected;
499
500
501
502 int intime;
503 };
504
505 static void
506 debug_timer_callback (struct atimer *t)
507 {
508 struct timespec now = current_timespec ();
509 struct atimer_result *r = (struct atimer_result *) t->client_data;
510 int result = timespec_cmp (now, r->expected);
511
512 if (result < 0)
513
514 r->intime = 0;
515 else if (result >= 0)
516 {
517 bool intime = true;
518 #if defined HAVE_ITIMERSPEC || defined HAVE_SETITIMER
519 struct timespec delta = timespec_sub (now, r->expected);
520
521
522 intime = timespec_cmp (delta, make_timespec (0, 20000000)) <= 0;
523 #endif
524 r->intime = intime;
525 }
526 }
527
528 DEFUN ("debug-timer-check", Fdebug_timer_check, Sdebug_timer_check, 0, 0, 0,
529 doc:
530 )
531 (void)
532 {
533 int i, ok;
534 struct atimer *timer;
535 struct atimer_result *results[MAXTIMERS];
536 struct timespec t = make_timespec (0, 0);
537
538
539 for (i = 0; i < MAXTIMERS; i++)
540 {
541 results[i] = xmalloc (sizeof (struct atimer_result));
542 t = timespec_add (t, make_timespec (0, 100000000));
543 results[i]->expected = timespec_add (current_timespec (), t);
544 results[i]->intime = -1;
545 timer = start_atimer (ATIMER_RELATIVE, t,
546 debug_timer_callback, results[i]);
547 }
548
549 #ifdef HAVE_TIMERFD
550
551 wait_reading_process_output (1, 0, 0, false, Qnil, NULL, 0);
552 #else
553
554
555
556
557
558 struct timespec tend =
559 timespec_add (current_timespec (), make_timespec (1, 200000000));
560
561 while (timespec_cmp (current_timespec (), tend) < 0)
562 {
563
564 wait_reading_process_output (0, 5000000, 0, false, Qnil, NULL, 0);
565 if (pending_signals)
566 do_pending_atimers ();
567 }
568 #endif
569
570 (void) timer;
571
572 for (i = 0, ok = 0; i < MAXTIMERS; i++)
573 ok += results[i]->intime, xfree (results[i]);
574
575 return ok == MAXTIMERS ? Qt : Qnil;
576 }
577
578 #endif
579
580
581
582 #ifdef HAVE_TIMERFD
583 static bool
584 have_buggy_timerfd (void)
585 {
586 # ifdef CYGWIN
587 struct utsname name;
588 return uname (&name) < 0 || strverscmp (name.release, "3.0.2") < 0;
589 # else
590 return false;
591 # endif
592 }
593 #endif
594
595 void
596 init_atimer (void)
597 {
598 #ifdef HAVE_ITIMERSPEC
599 # ifdef HAVE_TIMERFD
600
601 timerfd = (egetenv ("EMACS_IGNORE_TIMERFD") || have_buggy_timerfd () ? -1 :
602 timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC));
603 # endif
604
605
606
607
608
609 struct sigevent sigev;
610 sigev.sigev_notify = SIGEV_SIGNAL;
611 sigev.sigev_signo = SIGALRM;
612 sigev.sigev_value.sival_ptr = &alarm_timer;
613 alarm_timer_ok
614 = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0;
615 #endif
616 free_atimers = stopped_atimers = atimers = NULL;
617
618
619 struct sigaction action;
620 emacs_sigaction_init (&action, handle_alarm_signal);
621 sigaction (SIGALRM, &action, 0);
622
623 #ifdef ENABLE_CHECKING
624 if (!initialized)
625 defsubr (&Sdebug_timer_check);
626 #endif
627 }