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.
89 unsigned int scm_async_clock
= 20;
90 static unsigned int scm_async_rate
= 20;
91 unsigned int scm_mask_ints
= 1;
93 static unsigned int scm_tick_clock
= 0;
94 static unsigned int scm_tick_rate
= 0;
95 static unsigned int scm_desired_tick_rate
= 0;
96 static unsigned int scm_switch_clock
= 0;
97 static unsigned int scm_switch_rate
= 0;
98 static unsigned int scm_desired_switch_rate
= 0;
100 static SCM system_signal_asyncs
[SCM_NUM_SIGS
];
101 static SCM handler_var
;
102 static SCM symbol_signal
;
107 int got_it
; /* needs to be delivered? */
108 SCM thunk
; /* the handler. */
112 static long scm_tc16_async
;
114 #define SCM_ASYNCP(X) (scm_tc16_async == SCM_GCTYP16 (X))
115 #define SCM_ASYNC(X) ((struct scm_async *)SCM_CDR (X))
122 static int asyncs_pending
SCM_P ((void));
129 while (pos
!= SCM_EOL
)
132 struct scm_async
* it
;
150 if (!scm_switch_rate
)
153 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
154 scm_desired_switch_rate
= 0;
158 owe_switch
= (scm_async_rate
>= scm_switch_clock
);
161 if (scm_desired_switch_rate
)
163 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
164 scm_desired_switch_rate
= 0;
167 scm_switch_clock
= scm_switch_rate
;
171 if (scm_desired_switch_rate
)
173 scm_switch_clock
= scm_switch_rate
= scm_desired_switch_rate
;
174 scm_desired_switch_rate
= 0;
177 scm_switch_clock
-= scm_async_rate
;
193 r
= scm_desired_tick_rate
;
196 scm_desired_tick_rate
= 0;
203 owe_tick
= (scm_async_rate
>= scm_tick_clock
);
206 scm_tick_clock
= scm_tick_rate
= scm_desired_tick_rate
;
207 scm_desired_tick_rate
= 0;
211 if (scm_desired_tick_rate
)
213 scm_tick_clock
= scm_tick_rate
= scm_desired_tick_rate
;
214 scm_desired_tick_rate
= 0;
217 scm_tick_clock
-= scm_async_rate
;
222 scm_async_mark (system_signal_asyncs
[SCM_SIG_ORD(SCM_TICK_SIGNAL
)]);
225 if (scm_tick_rate
&& scm_switch_rate
)
227 scm_async_rate
= min (scm_tick_clock
, scm_switch_clock
);
228 scm_async_clock
= scm_async_rate
;
230 else if (scm_tick_rate
)
232 scm_async_clock
= scm_async_rate
= scm_tick_clock
;
234 else if (scm_switch_rate
)
236 scm_async_clock
= scm_async_rate
= scm_switch_clock
;
239 scm_async_clock
= scm_async_rate
= 1 << 16;
243 scm_run_asyncs (scm_asyncs
);
246 if (asyncs_pending ())
264 #if 0 /* Thread switching code should probably reside here, but the
265 async switching code doesn't seem to work, so it's put in the
266 SCM_ASYNC_TICK macro instead. /mdj */
267 SCM_THREAD_SWITCHING_CODE
;
273 static void scm_deliver_signal
SCM_P ((int num
));
276 scm_deliver_signal (num
)
280 handler
= SCM_CDR (handler_var
);
281 if (handler
!= SCM_BOOL_F
)
282 scm_apply (handler
, SCM_MAKINUM (num
), scm_listofnull
);
286 scm_throw (symbol_signal
,
287 scm_listify (SCM_MAKINUM (num
), SCM_UNDEFINED
));
295 static int print_async
SCM_P ((SCM exp
, SCM port
, scm_print_state
*pstate
));
298 print_async (exp
, port
, pstate
)
301 scm_print_state
*pstate
;
303 scm_gen_puts (scm_regular_string
, "#<async ", port
);
304 scm_intprint(exp
, 16, port
);
305 scm_gen_putc('>', port
);
310 static SCM mark_async
SCM_P ((SCM obj
));
316 struct scm_async
* it
;
317 if (SCM_GC8MARKP (obj
))
319 SCM_SETGC8MARK (obj
);
320 it
= SCM_ASYNC (obj
);
325 static scm_sizet free_async
SCM_P ((SCM obj
));
331 struct scm_async
* it
;
332 it
= SCM_ASYNC (obj
);
333 scm_must_free ((char *)it
);
334 return (sizeof (*it
));
338 static scm_smobfuns async_smob
=
349 SCM_PROC(s_async
, "async", 1, 0, 0, scm_async
);
356 struct scm_async
* async
;
360 SCM_SETCDR (it
, SCM_EOL
);
361 async
= (struct scm_async
*)scm_must_malloc (sizeof (*async
), s_async
);
363 async
->thunk
= thunk
;
364 SCM_SETCDR (it
, (SCM
)async
);
365 SCM_SETCAR (it
, (SCM
)scm_tc16_async
);
370 SCM_PROC(s_system_async
, "system-async", 1, 0, 0, scm_system_async
);
373 scm_system_async (thunk
)
379 it
= scm_async (thunk
);
382 SCM_SETCAR (list
, it
);
383 SCM_SETCDR (list
, scm_asyncs
);
389 SCM_PROC(s_async_mark
, "async-mark", 1, 0, 0, scm_async_mark
);
395 struct scm_async
* it
;
396 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_async_mark
);
399 return SCM_UNSPECIFIED
;
403 SCM_PROC(s_system_async_mark
, "system-async-mark", 1, 0, 0, scm_system_async_mark
);
406 scm_system_async_mark (a
)
409 struct scm_async
* it
;
410 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_async_mark
);
414 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
417 return SCM_UNSPECIFIED
;
421 SCM_PROC(s_run_asyncs
, "run-asyncs", 1, 0, 0, scm_run_asyncs
);
424 scm_run_asyncs (list_of_a
)
432 while (pos
!= SCM_EOL
)
435 struct scm_async
* it
;
436 SCM_ASSERT (SCM_NIMP (pos
) && SCM_CONSP (pos
), pos
, SCM_ARG1
, s_run_asyncs
);
438 SCM_ASSERT (SCM_NIMP (a
) && SCM_ASYNCP (a
), a
, SCM_ARG1
, s_run_asyncs
);
444 scm_apply (it
->thunk
, SCM_EOL
, SCM_EOL
);
455 SCM_PROC(s_noop
, "noop", 0, 0, 1, scm_noop
);
461 return (SCM_NULLP (args
)
469 SCM_PROC(s_set_tick_rate
, "set-tick-rate", 1, 0, 0, scm_set_tick_rate
);
472 scm_set_tick_rate (n
)
476 SCM_ASSERT (SCM_INUMP (n
), n
, SCM_ARG1
, s_set_tick_rate
);
477 old_n
= scm_tick_rate
;
478 scm_desired_tick_rate
= SCM_INUM (n
);
479 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
481 return SCM_MAKINUM (old_n
);
487 SCM_PROC(s_set_switch_rate
, "set-switch-rate", 1, 0, 0, scm_set_switch_rate
);
490 scm_set_switch_rate (n
)
494 SCM_ASSERT (SCM_INUMP (n
), n
, SCM_ARG1
, s_set_switch_rate
);
495 old_n
= scm_switch_rate
;
496 scm_desired_switch_rate
= SCM_INUM (n
);
497 scm_async_rate
= 1 + scm_async_rate
- scm_async_clock
;
499 return SCM_MAKINUM (old_n
);
505 static SCM scm_sys_hup_async_thunk
SCM_P ((void));
508 scm_sys_hup_async_thunk ()
510 scm_deliver_signal (SCM_HUP_SIGNAL
);
515 static SCM scm_sys_int_async_thunk
SCM_P ((void));
518 scm_sys_int_async_thunk ()
520 scm_deliver_signal (SCM_INT_SIGNAL
);
525 static SCM scm_sys_fpe_async_thunk
SCM_P ((void));
528 scm_sys_fpe_async_thunk ()
530 scm_deliver_signal (SCM_FPE_SIGNAL
);
535 static SCM scm_sys_bus_async_thunk
SCM_P ((void));
538 scm_sys_bus_async_thunk ()
540 scm_deliver_signal (SCM_BUS_SIGNAL
);
545 static SCM scm_sys_segv_async_thunk
SCM_P ((void));
548 scm_sys_segv_async_thunk ()
550 scm_deliver_signal (SCM_SEGV_SIGNAL
);
555 static SCM scm_sys_alrm_async_thunk
SCM_P ((void));
558 scm_sys_alrm_async_thunk ()
560 scm_deliver_signal (SCM_ALRM_SIGNAL
);
565 static SCM scm_sys_gc_async_thunk
SCM_P ((void));
568 scm_sys_gc_async_thunk ()
570 scm_deliver_signal (SCM_GC_SIGNAL
);
575 static SCM scm_sys_tick_async_thunk
SCM_P ((void));
578 scm_sys_tick_async_thunk ()
580 scm_deliver_signal (SCM_TICK_SIGNAL
);
594 if (!scm_ints_disabled
)
596 /* For reasons of speed, the SCM_NEWCELL macro doesn't defer
597 interrupts. Instead, it first sets its argument to point to
598 the first cell in the list, and then advances the freelist
599 pointer to the next cell. Now, if this procedure is
600 interrupted, the only anomalous state possible is to have
601 both SCM_NEWCELL's argument and scm_freelist pointing to the
602 same cell. To deal with this case, we always throw away the
603 first cell in scm_freelist here.
605 At least, that's the theory. I'm not convinced that that's
606 the only anomalous path we need to worry about. */
607 SCM_NEWCELL (ignored
);
609 scm_system_async_mark (system_signal_asyncs
[SCM_SIG_ORD(n
)]);
615 SCM_PROC(s_unmask_signals
, "unmask-signals", 0, 0, 0, scm_unmask_signals
);
618 scm_unmask_signals ()
621 return SCM_UNSPECIFIED
;
625 SCM_PROC(s_mask_signals
, "mask-signals", 0, 0, 0, scm_mask_signals
);
631 return SCM_UNSPECIFIED
;
641 scm_tc16_async
= scm_newsmob (&async_smob
);
642 symbol_signal
= SCM_CAR (scm_sysintern ("signal", SCM_UNDEFINED
));
643 scm_permanent_object (symbol_signal
);
645 /* These are in the opposite order of delivery priortity.
647 * Error conditions are given low priority:
649 a_thunk
= scm_make_gsubr ("%hup-thunk", 0, 0, 0, scm_sys_hup_async_thunk
);
650 system_signal_asyncs
[SCM_SIG_ORD(SCM_HUP_SIGNAL
)] = scm_system_async (a_thunk
);
651 a_thunk
= scm_make_gsubr ("%int-thunk", 0, 0, 0, scm_sys_int_async_thunk
);
652 system_signal_asyncs
[SCM_SIG_ORD(SCM_INT_SIGNAL
)] = scm_system_async (a_thunk
);
653 a_thunk
= scm_make_gsubr ("%fpe-thunk", 0, 0, 0, scm_sys_fpe_async_thunk
);
654 system_signal_asyncs
[SCM_SIG_ORD(SCM_FPE_SIGNAL
)] = scm_system_async (a_thunk
);
655 a_thunk
= scm_make_gsubr ("%bus-thunk", 0, 0, 0, scm_sys_bus_async_thunk
);
656 system_signal_asyncs
[SCM_SIG_ORD(SCM_BUS_SIGNAL
)] = scm_system_async (a_thunk
);
657 a_thunk
= scm_make_gsubr ("%segv-thunk", 0, 0, 0, scm_sys_segv_async_thunk
);
658 system_signal_asyncs
[SCM_SIG_ORD(SCM_SEGV_SIGNAL
)] = scm_system_async (a_thunk
);
661 a_thunk
= scm_make_gsubr ("%gc-thunk", 0, 0, 0, scm_sys_gc_async_thunk
);
662 system_signal_asyncs
[SCM_SIG_ORD(SCM_GC_SIGNAL
)] = scm_system_async (a_thunk
);
664 /* Clock and PC driven conditions are given highest priority. */
665 a_thunk
= scm_make_gsubr ("%tick-thunk", 0, 0, 0, scm_sys_tick_async_thunk
);
666 system_signal_asyncs
[SCM_SIG_ORD(SCM_TICK_SIGNAL
)] = scm_system_async (a_thunk
);
667 a_thunk
= scm_make_gsubr ("%alrm-thunk", 0, 0, 0, scm_sys_alrm_async_thunk
);
668 system_signal_asyncs
[SCM_SIG_ORD(SCM_ALRM_SIGNAL
)] = scm_system_async (a_thunk
);
670 handler_var
= scm_sysintern ("signal-handler", SCM_UNDEFINED
);
671 SCM_SETCDR (handler_var
, SCM_BOOL_F
);
672 scm_permanent_object (handler_var
);