1
/* timers.c -- call a function after a period of time has passed
2
Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>
3
$Id: timers.c,v 1.14 2001/08/02 07:12:36 jsh Exp $
5
This file is part of librep.
7
librep is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
12
librep is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with librep; see the file COPYING. If not, write to
19
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23
/* AIX requires this to be the first thing in the file. */
26
# define alloca __builtin_alloca
34
# ifndef alloca /* predefined by HP cc +Olibcalls */
50
#ifdef HAVE_SYS_TIME_H
51
# include <sys/time.h>
54
static int timer_type;
56
#define TIMER(v) ((Lisp_Timer *)rep_PTR(v))
57
#define TIMERP(v) rep_CELL16_TYPEP(v, timer_type)
59
typedef struct lisp_timer {
61
struct lisp_timer *next;
62
struct lisp_timer *next_alloc;
65
long rel_secs, rel_msecs;
70
/* List of all allocated timer objects, linked through next_alloc field */
71
static Lisp_Timer *allocated_timers;
73
/* List of all pending timers, linked through next field. Only ever
74
touch this variable if SIGALRM is blocked! */
75
static Lisp_Timer *timer_chain;
77
/* Pipe used to trigger the input callback */
78
static int pipe_fds[2];
80
/* Contains SIGALRM */
81
static sigset_t alrm_sigset;
86
timer_signal_handler (int sig)
89
Lisp_Timer *t = timer_chain;
91
t->rel_secs = t->rel_msecs = 0;
92
while (t != 0 && t->rel_secs == 0 && t->rel_msecs == 0)
97
write (pipe_fds[1], &dummy, sizeof (dummy));
100
/* only call with SIGALRM blocked */
102
setup_next_timer (void)
105
&& (timer_chain->rel_secs > 0 || timer_chain->rel_msecs > 0))
107
#ifdef HAVE_SETITIMER
108
struct itimerval it, tem;
109
it.it_interval.tv_usec = 0;
110
it.it_interval.tv_sec = 0;
111
it.it_value.tv_usec = timer_chain->rel_msecs * 1000;
112
it.it_value.tv_sec = timer_chain->rel_secs;
113
setitimer (ITIMER_REAL, &it, &tem);
115
alarm (timer_chain->secs);
117
signal (SIGALRM, timer_signal_handler);
120
signal (SIGALRM, SIG_IGN);
124
fix_time (long *secs, long *msecs)
131
while (*msecs > 1000)
139
insert_timer (Lisp_Timer *t)
142
sigprocmask (SIG_BLOCK, &alrm_sigset, &old);
143
if (t->secs > 0 || t->msecs > 0)
146
t->rel_secs = t->secs;
147
t->rel_msecs = t->msecs;
152
&& ((*x)->rel_secs < t->rel_secs
153
|| ((*x)->rel_secs == t->rel_secs
154
&& (*x)->rel_msecs <= t->rel_msecs)))
156
t->rel_msecs -= (*x)->rel_msecs;
157
t->rel_secs -= (*x)->rel_secs;
158
fix_time (&t->rel_secs, &t->rel_msecs);
163
(*x)->rel_msecs -= t->rel_msecs;
164
(*x)->rel_secs -= t->rel_secs;
165
fix_time (&(*x)->rel_secs, &(*x)->rel_msecs);
169
if (timer_chain == t)
172
sigprocmask (SIG_SETMASK, &old, 0);
176
delete_timer (Lisp_Timer *t)
181
sigprocmask (SIG_BLOCK, &alrm_sigset, &old);
184
while (*x != 0 && (*x) != t)
190
t->next->rel_msecs += t->rel_msecs;
191
t->next->rel_secs += t->rel_secs;
192
fix_time (&t->next->rel_secs, &t->next->rel_msecs);
194
t->rel_secs = t->rel_msecs = 0;
196
if (x == &timer_chain)
199
sigprocmask (SIG_SETMASK, &old, 0);
203
timer_fd_handler (int fd)
208
rep_GC_n_roots gc_timers;
212
read (pipe_fds[0], &dummy, sizeof (dummy));
213
sigprocmask (SIG_BLOCK, &alrm_sigset, &old);
215
for (t = timer_chain; t != 0 && t->fired; t = t->next)
217
timers = alloca (sizeof (repv) * ready);
218
for (i = 0; i < ready; i++)
220
timers[i] = rep_VAL(timer_chain);
221
timer_chain = timer_chain->next;
224
sigprocmask (SIG_SETMASK, &old, 0);
225
rep_PUSHGCN(gc_timers, timers, ready);
226
for (i = 0; i < ready; i++)
228
if (!TIMER(timers[i])->deleted)
229
rep_call_lisp1 (TIMER(timers[i])->function, timers[i]);
237
DEFUN("make-timer", Fmake_timer, Smake_timer,
238
(repv fun, repv secs, repv msecs), rep_Subr3) /*
239
::doc:rep.io.timers#make-timer::
240
make-timer FUNCTION [SECONDS] [MILLISECONDS]
242
Create and return a new one-shot timer object. After SECONDS*1000 +
243
MILLISECONDS milliseconds FUNCTION will be called.
245
Note that the timer will only fire _once_, use the `set-timer' function
249
Lisp_Timer *t = rep_ALLOC_CELL (sizeof (Lisp_Timer));
250
rep_data_after_gc += sizeof (Lisp_Timer);
253
t->secs = rep_get_long_int (secs);
254
t->msecs = rep_get_long_int (msecs);
255
t->next_alloc = allocated_timers;
256
allocated_timers = t;
261
DEFUN("delete-timer", Fdelete_timer, Sdelete_timer, (repv timer), rep_Subr1) /*
262
::doc:rep.io.timers#delete-timer::
265
Prevent the one-shot timer TIMER from firing (i.e. calling the function
266
associated with it). If the timer has already fired, this function has
270
rep_DECLARE1(timer, TIMERP);
271
delete_timer (TIMER(timer));
275
DEFUN("set-timer", Fset_timer, Sset_timer,
276
(repv timer, repv secs, repv msecs), rep_Subr3) /*
277
::doc:rep.io.timers#set-timer::
278
set-timer TIMER [SECONDS] [MILLISECONDS]
280
Restart the one-shot timer TIMER. If SECONDS and/or MILLISECONDS is
281
defined the period after which it fires will be reset to the specified
282
duration. Otherwise, the existing values are preserved.
285
rep_DECLARE1(timer, TIMERP);
286
rep_DECLARE2_OPT(secs, rep_NUMERICP);
287
rep_DECLARE3_OPT(msecs, rep_NUMERICP);
288
delete_timer (TIMER(timer));
289
if (secs != Qnil || msecs != Qnil)
291
TIMER(timer)->secs = rep_get_long_int (secs);
292
TIMER(timer)->msecs = rep_get_long_int (msecs);
294
insert_timer (TIMER(timer));
302
timer_mark (repv val)
304
rep_MARKVAL (TIMER(val)->function);
308
timer_mark_active (void)
312
sigprocmask (SIG_BLOCK, &alrm_sigset, &old);
316
rep_MARKVAL (rep_VAL(t));
319
sigprocmask (SIG_SETMASK, &old, 0);
325
Lisp_Timer *x = allocated_timers;
326
allocated_timers = 0;
329
Lisp_Timer *next = x->next_alloc;
330
if (!rep_GC_CELL_MARKEDP (rep_VAL(x)))
334
rep_GC_CLR_CELL (rep_VAL(x));
335
x->next_alloc = allocated_timers;
336
allocated_timers = x;
343
timer_print (repv stream, repv arg)
347
snprintf (buf, sizeof (buf), "#<timer %lds, %ldms>",
348
TIMER(arg)->secs, TIMER(arg)->msecs);
350
sprintf (buf, "#<timer %lds, %ldms>", TIMER(arg)->secs, TIMER(arg)->msecs);
352
rep_stream_puts (stream, buf, -1, rep_FALSE);
362
timer_type = rep_register_new_type ("timer", 0, timer_print, timer_print,
363
timer_sweep, timer_mark,
364
timer_mark_active, 0, 0, 0, 0, 0, 0);
366
rep_register_input_fd (pipe_fds[0], timer_fd_handler);
368
rep_unix_set_fd_cloexec (pipe_fds[1]);
370
sigemptyset (&alrm_sigset);
371
sigaddset (&alrm_sigset, SIGALRM);
372
rep_sig_restart (SIGALRM, rep_TRUE);
374
tem = rep_push_structure ("rep.io.timers");
375
/* ::alias:timers rep.io.timers:: */
376
rep_alias_structure ("timers");
377
rep_ADD_SUBR(Smake_timer);
378
rep_ADD_SUBR(Sdelete_timer);
379
rep_ADD_SUBR(Sset_timer);
380
return rep_pop_structure (tem);
386
rep_deregister_input_fd (pipe_fds[0]);
389
signal (SIGALRM, SIG_IGN);