1 /* Copyright (C) 1995,1996 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice.
61 /* {Asynchronous Events}
64 * Async == thunk + mark.
66 * Setting the mark guarantees future execution of the thunk. More
67 * than one set may be satisfied by a single execution.
69 * scm_tick_clock decremented once per SCM_ALLOW_INTS.
70 * Async execution triggered by SCM_ALLOW_INTS when scm_tick_clock drops to 0.
71 * Async execution prevented by scm_mask_ints != 0.
73 * If the clock reaches 0 when scm_mask_ints != 0, then reset the clock
76 * If the clock reaches 0 any other time, run marked asyncs.
78 * From a unix signal handler, mark a corresponding async and set the clock
79 * to 1. Do SCM_REDEFER_INTS;/SCM_REALLOW_INTS so that if the signal handler is not
80 * called in the dynamic scope of a critical section, it is excecuted immediately.
82 * Overall, closely timed signals of a particular sort may be combined. Pending signals
83 * are delivered in a fixed priority order, regardless of arrival order.
87 /* True between SCM_DEFER_INTS and SCM_ALLOW_INTS, and
88 * when the interpreter is not running at all.
90 int scm_ints_disabled
= 1;
92 unsigned int scm_async_clock
= 20;
93 static unsigned int scm_async_rate
= 20;
94 unsigned int scm_mask_ints
= 1;
96 static unsigned int scm_tick_clock
= 0;
97 static unsigned int scm_tick_rate
= 0;
98 static unsigned int scm_desired_tick_rate
= 0;
99 static unsigned int scm_switch_clock
= 0;
100 static unsigned int scm_switch_rate
= 0;
101 static unsigned int scm_desired_switch_rate
= 0;
103 static SCM system_signal_asyncs
[SCM_NUM_SIGS
];
104 static SCM handler_var
;
105 static SCM symbol_signal
;
110 int got_it
; /* needs to be delivered? */
111 SCM thunk
; /* the handler. */
115 static long scm_tc16_async
;
117 #define SCM_ASYNCP(X) (scm_tc16_async == SCM_GCTYP16 (X))
118 #define SCM_ASYNC(X) ((struct scm_async *)SCM_CDR (X))
125 static int asyncs_pending
SCM_P ((void));
132 while (pos
!= SCM_EOL
)
135 struct scm_async
* it
;
153 if (!scm_switch_rate
)
156 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
157 scm_desired_switch_rate
= 0;
161 owe_switch
= (scm_async_rate
>= scm_switch_clock
);
164 if (scm_desired_switch_rate
)
166 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
167 scm_desired_switch_rate
= 0;
170 scm_switch_clock
= scm_switch_rate
;
174 if (scm_desired_switch_rate
)
176 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
177 scm_desired_switch_rate
= 0;
180 scm_switch_clock
-= scm_async_rate
;
196 r
= scm_desired_tick_rate
;
199 scm_desired_tick_rate
= 0;
206 owe_tick
= (scm_async_rate
>= scm_tick_clock
);
209 scm_tick_clock
= scm_tick_rate
= scm_desired_tick_rate
;
210 scm_desired_tick_rate
= 0;
214 if (scm_desired_tick_rate
)
216 scm_tick_clock
= scm_tick_rate
= scm_desired_tick_rate
;
217 scm_desired_tick_rate
= 0;
220 scm_tick_clock
-= scm_async_rate
;
225 scm_async_mark (system_signal_asyncs
[SCM_SIG_ORD(SCM_TICK_SIGNAL
)]);
228 if (scm_tick_rate
&& scm_switch_rate
)
230 scm_async_rate
= min (scm_tick_clock
, scm_switch_clock
);
231 scm_async_clock
= scm_async_rate
;
233 else if (scm_tick_rate
)
235 scm_async_clock
= scm_async_rate
= scm_tick_clock
;
237 else if (scm_switch_rate
)
239 scm_async_clock
= scm_async_rate
= scm_switch_clock
;
242 scm_async_clock
= scm_async_rate
= 1 << 16;
246 scm_run_asyncs (scm_asyncs
);
249 if (asyncs_pending ())
267 #if 0 /* Thread switching code should probably reside here, but the
268 async switching code doesn't seem to work, so it's put in the
269 SCM_ASYNC_TICK macro instead. /mdj */
270 SCM_THREAD_SWITCHING_CODE
;
276 static void scm_deliver_signal
SCM_P ((int num
));
279 scm_deliver_signal (num
)
283 handler
= SCM_CDR (handler_var
);
284 if (handler
!= SCM_BOOL_F
)
285 scm_apply (handler
, SCM_MAKINUM (num
), scm_listofnull
);
289 scm_throw (symbol_signal
,
290 scm_listify (SCM_MAKINUM (num
), SCM_UNDEFINED
));
298 static int print_async
SCM_P ((SCM exp
, SCM port
, scm_print_state
*pstate
));
301 print_async (exp
, port
, pstate
)
304 scm_print_state
*pstate
;
306 scm_gen_puts (scm_regular_string
, "#<async ", port
);
307 scm_intprint(exp
, 16, port
);
308 scm_gen_putc('>', port
);
313 static SCM mark_async
SCM_P ((SCM obj
));
319 struct scm_async
* it
;
320 if (SCM_GC8MARKP (obj
))
322 SCM_SETGC8MARK (obj
);
323 it
= SCM_ASYNC (obj
);
328 static scm_sizet free_async
SCM_P ((SCM obj
));
334 struct scm_async
* it
;
335 it
= SCM_ASYNC (obj
);
336 scm_must_free ((char *)it
);
337 return (sizeof (*it
));
341 static scm_smobfuns async_smob
=
352 SCM_PROC(s_async
, "async", 1, 0, 0, scm_async
);
359 struct scm_async
* async
;
363 SCM_SETCDR (it
, SCM_EOL
);
364 async
= (struct scm_async
*)scm_must_malloc (sizeof (*async
), s_async
);
366 async
->thunk
= thunk
;
367 SCM_SETCDR (it
, (SCM
)async
);
368 SCM_SETCAR (it
, (SCM
)scm_tc16_async
);
373 SCM_PROC(s_system_async
, "system-async", 1, 0, 0, scm_system_async
);
376 scm_system_async (thunk
)
382 it
= scm_async (thunk
);
385 SCM_SETCAR (list
, it
);
386 SCM_SETCDR (list
, scm_asyncs
);
392 SCM_PROC(s_async_mark
, "async-mark", 1, 0, 0, scm_async_mark
);
398 struct scm_async
* it
;
399 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_async_mark
);
402 return SCM_UNSPECIFIED
;
406 SCM_PROC(s_system_async_mark
, "system-async-mark", 1, 0, 0, scm_system_async_mark
);
409 scm_system_async_mark (a
)
412 struct scm_async
* it
;
413 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_async_mark
);
417 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
420 return SCM_UNSPECIFIED
;
424 SCM_PROC(s_run_asyncs
, "run-asyncs", 1, 0, 0, scm_run_asyncs
);
427 scm_run_asyncs (list_of_a
)
435 while (pos
!= SCM_EOL
)
438 struct scm_async
* it
;
439 SCM_ASSERT (SCM_NIMP (pos
) && SCM_CONSP (pos
), pos
, SCM_ARG1
, s_run_asyncs
);
441 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_run_asyncs
);
447 scm_apply (it
->thunk
, SCM_EOL
, SCM_EOL
);
458 SCM_PROC(s_noop
, "noop", 0, 0, 1, scm_noop
);
464 return (SCM_NULLP (args
)
472 SCM_PROC(s_set_tick_rate
, "set-tick-rate", 1, 0, 0, scm_set_tick_rate
);
475 scm_set_tick_rate (n
)
479 SCM_ASSERT (SCM_INUMP (n
), n
, SCM_ARG1
, s_set_tick_rate
);
480 old_n
= scm_tick_rate
;
481 scm_desired_tick_rate
= SCM_INUM (n
);
482 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
484 return SCM_MAKINUM (old_n
);
490 SCM_PROC(s_set_switch_rate
, "set-switch-rate", 1, 0, 0, scm_set_switch_rate
);
493 scm_set_switch_rate (n
)
497 SCM_ASSERT (SCM_INUMP (n
), n
, SCM_ARG1
, s_set_switch_rate
);
498 old_n
= scm_switch_rate
;
499 scm_desired_switch_rate
= SCM_INUM (n
);
500 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
502 return SCM_MAKINUM (old_n
);
508 static SCM scm_sys_hup_async_thunk
SCM_P ((void));
511 scm_sys_hup_async_thunk ()
513 scm_deliver_signal (SCM_HUP_SIGNAL
);
518 static SCM scm_sys_int_async_thunk
SCM_P ((void));
521 scm_sys_int_async_thunk ()
523 scm_deliver_signal (SCM_INT_SIGNAL
);
528 static SCM scm_sys_fpe_async_thunk
SCM_P ((void));
531 scm_sys_fpe_async_thunk ()
533 scm_deliver_signal (SCM_FPE_SIGNAL
);
538 static SCM scm_sys_bus_async_thunk
SCM_P ((void));
541 scm_sys_bus_async_thunk ()
543 scm_deliver_signal (SCM_BUS_SIGNAL
);
548 static SCM scm_sys_segv_async_thunk
SCM_P ((void));
551 scm_sys_segv_async_thunk ()
553 scm_deliver_signal (SCM_SEGV_SIGNAL
);
558 static SCM scm_sys_alrm_async_thunk
SCM_P ((void));
561 scm_sys_alrm_async_thunk ()
563 scm_deliver_signal (SCM_ALRM_SIGNAL
);
568 static SCM scm_sys_gc_async_thunk
SCM_P ((void));
571 scm_sys_gc_async_thunk ()
573 scm_deliver_signal (SCM_GC_SIGNAL
);
578 static SCM scm_sys_tick_async_thunk
SCM_P ((void));
581 scm_sys_tick_async_thunk ()
583 scm_deliver_signal (SCM_TICK_SIGNAL
);
597 if (!scm_ints_disabled
)
599 /* For reasons of speed, the SCM_NEWCELL macro doesn't defer
600 interrupts. Instead, it first sets its argument to point to
601 the first cell in the list, and then advances the freelist
602 pointer to the next cell. Now, if this procedure is
603 interrupted, the only anomalous state possible is to have
604 both SCM_NEWCELL's argument and scm_freelist pointing to the
605 same cell. To deal with this case, we always throw away the
606 first cell in scm_freelist here.
608 At least, that's the theory. I'm not convinced that that's
609 the only anomalous path we need to worry about. */
610 SCM_NEWCELL (ignored
);
612 scm_system_async_mark (system_signal_asyncs
[SCM_SIG_ORD(n
)]);
618 SCM_PROC(s_unmask_signals
, "unmask-signals", 0, 0, 0, scm_unmask_signals
);
621 scm_unmask_signals ()
624 return SCM_UNSPECIFIED
;
628 SCM_PROC(s_mask_signals
, "mask-signals", 0, 0, 0, scm_mask_signals
);
634 return SCM_UNSPECIFIED
;
644 scm_tc16_async
= scm_newsmob (&async_smob
);
645 symbol_signal
= SCM_CAR (scm_sysintern ("signal", SCM_UNDEFINED
));
646 scm_permanent_object (symbol_signal
);
648 /* These are in the opposite order of delivery priortity.
650 * Error conditions are given low priority:
652 a_thunk
= scm_make_gsubr ("%hup-thunk", 0, 0, 0, scm_sys_hup_async_thunk
);
653 system_signal_asyncs
[SCM_SIG_ORD(SCM_HUP_SIGNAL
)] = scm_system_async (a_thunk
);
654 a_thunk
= scm_make_gsubr ("%int-thunk", 0, 0, 0, scm_sys_int_async_thunk
);
655 system_signal_asyncs
[SCM_SIG_ORD(SCM_INT_SIGNAL
)] = scm_system_async (a_thunk
);
656 a_thunk
= scm_make_gsubr ("%fpe-thunk", 0, 0, 0, scm_sys_fpe_async_thunk
);
657 system_signal_asyncs
[SCM_SIG_ORD(SCM_FPE_SIGNAL
)] = scm_system_async (a_thunk
);
658 a_thunk
= scm_make_gsubr ("%bus-thunk", 0, 0, 0, scm_sys_bus_async_thunk
);
659 system_signal_asyncs
[SCM_SIG_ORD(SCM_BUS_SIGNAL
)] = scm_system_async (a_thunk
);
660 a_thunk
= scm_make_gsubr ("%segv-thunk", 0, 0, 0, scm_sys_segv_async_thunk
);
661 system_signal_asyncs
[SCM_SIG_ORD(SCM_SEGV_SIGNAL
)] = scm_system_async (a_thunk
);
664 a_thunk
= scm_make_gsubr ("%gc-thunk", 0, 0, 0, scm_sys_gc_async_thunk
);
665 system_signal_asyncs
[SCM_SIG_ORD(SCM_GC_SIGNAL
)] = scm_system_async (a_thunk
);
667 /* Clock and PC driven conditions are given highest priority. */
668 a_thunk
= scm_make_gsubr ("%tick-thunk", 0, 0, 0, scm_sys_tick_async_thunk
);
669 system_signal_asyncs
[SCM_SIG_ORD(SCM_TICK_SIGNAL
)] = scm_system_async (a_thunk
);
670 a_thunk
= scm_make_gsubr ("%alrm-thunk", 0, 0, 0, scm_sys_alrm_async_thunk
);
671 system_signal_asyncs
[SCM_SIG_ORD(SCM_ALRM_SIGNAL
)] = scm_system_async (a_thunk
);
673 handler_var
= scm_sysintern ("signal-handler", SCM_UNDEFINED
);
674 SCM_SETCDR (handler_var
, SCM_BOOL_F
);
675 scm_permanent_object (handler_var
);