* * stacks.c, stacks.h (scm_make_stack): Now takes arbitrary
[bpt/guile.git] / libguile / async.c
CommitLineData
0f2d19dd
JB
1/* Copyright (C) 1995,1996 Free Software Foundation, Inc.
2 *
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)
6 * any later version.
7 *
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.
12 *
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.
16 *
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
19 *
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.
25 *
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
28 *
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.
36 *
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.
40 */
41\f
42
43#include <stdio.h>
44#include <signal.h>
45#include "_scm.h"
20e6290e
JB
46#include "eval.h"
47#include "throw.h"
48#include "smob.h"
49
50#include "async.h"
0f2d19dd 51
95b88819
GH
52#ifdef HAVE_STRING_H
53#include <string.h>
54#endif
0f2d19dd
JB
55#ifdef HAVE_UNISTD_H
56#include <unistd.h>
57#endif
58
59
60\f
61/* {Asynchronous Events}
62 *
63 *
64 * Async == thunk + mark.
65 *
66 * Setting the mark guarantees future execution of the thunk. More
67 * than one set may be satisfied by a single execution.
68 *
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.
72 *
73 * If the clock reaches 0 when scm_mask_ints != 0, then reset the clock
74 * to 1.
75 *
76 * If the clock reaches 0 any other time, run marked asyncs.
77 *
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.
81 *
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.
84 *
85 */
86
87
0f2d19dd
JB
88
89unsigned int scm_async_clock = 20;
90static unsigned int scm_async_rate = 20;
91unsigned int scm_mask_ints = 1;
92
93static unsigned int scm_tick_clock = 0;
94static unsigned int scm_tick_rate = 0;
95static unsigned int scm_desired_tick_rate = 0;
96static unsigned int scm_switch_clock = 0;
97static unsigned int scm_switch_rate = 0;
98static unsigned int scm_desired_switch_rate = 0;
99
100static SCM system_signal_asyncs[SCM_NUM_SIGS];
101static SCM handler_var;
102static SCM symbol_signal;
103
104
105struct scm_async
106{
107 int got_it; /* needs to be delivered? */
108 SCM thunk; /* the handler. */
109};
110
111
112static long scm_tc16_async;
113
114#define SCM_ASYNCP(X) (scm_tc16_async == SCM_GCTYP16 (X))
115#define SCM_ASYNC(X) ((struct scm_async *)SCM_CDR (X))
116
117
118
119
120\f
121
1cc91f1b
JB
122static int asyncs_pending SCM_P ((void));
123
0f2d19dd
JB
124static int
125asyncs_pending ()
0f2d19dd
JB
126{
127 SCM pos;
128 pos = scm_asyncs;
129 while (pos != SCM_EOL)
130 {
131 SCM a;
132 struct scm_async * it;
133 a = SCM_CAR (pos);
134 it = SCM_ASYNC (a);
135 if (it->got_it)
136 return 1;
137 pos = SCM_CDR (pos);
138 }
139 return 0;
140}
141
142
1cc91f1b 143
0f2d19dd
JB
144void
145scm_async_click ()
0f2d19dd
JB
146{
147 int owe_switch;
148 int owe_tick;
149
150 if (!scm_switch_rate)
151 {
152 owe_switch = 0;
153 scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
154 scm_desired_switch_rate = 0;
155 }
156 else
157 {
158 owe_switch = (scm_async_rate >= scm_switch_clock);
159 if (owe_switch)
160 {
161 if (scm_desired_switch_rate)
162 {
163 scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
164 scm_desired_switch_rate = 0;
165 }
166 else
167 scm_switch_clock = scm_switch_rate;
168 }
169 else
170 {
171 if (scm_desired_switch_rate)
172 {
173 scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
174 scm_desired_switch_rate = 0;
175 }
176 else
177 scm_switch_clock -= scm_async_rate;
178 }
179 }
180
181 if (scm_mask_ints)
182 {
183 if (owe_switch)
184 scm_switch ();
185 scm_async_clock = 1;
186 return;;
187 }
188
189 if (!scm_tick_rate)
190 {
191 unsigned int r;
192 owe_tick = 0;
193 r = scm_desired_tick_rate;
194 if (r)
195 {
196 scm_desired_tick_rate = 0;
197 scm_tick_rate = r;
198 scm_tick_clock = r;
199 }
200 }
201 else
202 {
203 owe_tick = (scm_async_rate >= scm_tick_clock);
204 if (owe_tick)
205 {
206 scm_tick_clock = scm_tick_rate = scm_desired_tick_rate;
207 scm_desired_tick_rate = 0;
208 }
209 else
210 {
211 if (scm_desired_tick_rate)
212 {
213 scm_tick_clock = scm_tick_rate = scm_desired_tick_rate;
214 scm_desired_tick_rate = 0;
215 }
216 else
217 scm_tick_clock -= scm_async_rate;
218 }
219 }
220
221 if (owe_tick)
222 scm_async_mark (system_signal_asyncs[SCM_SIG_ORD(SCM_TICK_SIGNAL)]);
223
224 SCM_DEFER_INTS;
225 if (scm_tick_rate && scm_switch_rate)
226 {
227 scm_async_rate = min (scm_tick_clock, scm_switch_clock);
228 scm_async_clock = scm_async_rate;
229 }
230 else if (scm_tick_rate)
231 {
232 scm_async_clock = scm_async_rate = scm_tick_clock;
233 }
234 else if (scm_switch_rate)
235 {
236 scm_async_clock = scm_async_rate = scm_switch_clock;
237 }
238 else
239 scm_async_clock = scm_async_rate = 1 << 16;
240 SCM_ALLOW_INTS_ONLY;
241
242 tail:
243 scm_run_asyncs (scm_asyncs);
244
245 SCM_DEFER_INTS;
246 if (asyncs_pending ())
247 {
248 SCM_ALLOW_INTS_ONLY;
249 goto tail;
250 }
251 SCM_ALLOW_INTS;
252
253 if (owe_switch)
254 scm_switch ();
255}
256
257
258\f
259
1cc91f1b 260
0f2d19dd
JB
261void
262scm_switch ()
0f2d19dd
JB
263{}
264
265
1cc91f1b
JB
266
267static void scm_deliver_signal SCM_P ((int num));
268
0f2d19dd
JB
269static void
270scm_deliver_signal (num)
271 int num;
0f2d19dd
JB
272{
273 SCM handler;
274 handler = SCM_CDR (handler_var);
275 if (handler != SCM_BOOL_F)
276 scm_apply (handler, SCM_MAKINUM (num), scm_listofnull);
277 else
278 {
279 scm_mask_ints = 0;
280 scm_throw (symbol_signal,
281 scm_listify (SCM_MAKINUM (num), SCM_UNDEFINED));
282 }
283}
284
285
286\f
287
1cc91f1b
JB
288
289static int print_async SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
290
0f2d19dd 291static int
9882ea19 292print_async (exp, port, pstate)
0f2d19dd
JB
293 SCM exp;
294 SCM port;
9882ea19 295 scm_print_state *pstate;
0f2d19dd
JB
296{
297 scm_gen_puts (scm_regular_string, "#<async ", port);
298 scm_intprint(exp, 16, port);
299 scm_gen_putc('>', port);
300 return 1;
301}
302
1cc91f1b
JB
303
304static SCM mark_async SCM_P ((SCM obj));
305
0f2d19dd
JB
306static SCM
307mark_async (obj)
308 SCM obj;
0f2d19dd
JB
309{
310 struct scm_async * it;
311 if (SCM_GC8MARKP (obj))
312 return SCM_BOOL_F;
313 SCM_SETGC8MARK (obj);
314 it = SCM_ASYNC (obj);
315 return it->thunk;
316}
317
1cc91f1b
JB
318
319static scm_sizet free_async SCM_P ((SCM obj));
320
0f2d19dd 321static scm_sizet
1cc91f1b 322free_async (obj)
0f2d19dd 323 SCM obj;
0f2d19dd
JB
324{
325 struct scm_async * it;
326 it = SCM_ASYNC (obj);
327 scm_must_free ((char *)it);
328 return (sizeof (*it));
329}
330
331
332static scm_smobfuns async_smob =
333{
334 mark_async,
335 free_async,
336 print_async,
337 0
338};
339
340
341\f
342
343SCM_PROC(s_async, "async", 1, 0, 0, scm_async);
1cc91f1b 344
0f2d19dd
JB
345SCM
346scm_async (thunk)
347 SCM thunk;
0f2d19dd
JB
348{
349 SCM it;
350 struct scm_async * async;
351
352 SCM_NEWCELL (it);
353 SCM_DEFER_INTS;
354 SCM_SETCDR (it, SCM_EOL);
355 async = (struct scm_async *)scm_must_malloc (sizeof (*async), s_async);
356 async->got_it = 0;
357 async->thunk = thunk;
358 SCM_SETCDR (it, (SCM)async);
359 SCM_SETCAR (it, (SCM)scm_tc16_async);
360 SCM_ALLOW_INTS;
361 return it;
362}
363
364SCM_PROC(s_system_async, "system-async", 1, 0, 0, scm_system_async);
1cc91f1b 365
0f2d19dd
JB
366SCM
367scm_system_async (thunk)
368 SCM thunk;
0f2d19dd
JB
369{
370 SCM it;
371 SCM list;
372
373 it = scm_async (thunk);
374 SCM_NEWCELL (list);
375 SCM_DEFER_INTS;
376 SCM_SETCAR (list, it);
377 SCM_SETCDR (list, scm_asyncs);
378 scm_asyncs = list;
379 SCM_ALLOW_INTS;
380 return it;
381}
382
383SCM_PROC(s_async_mark, "async-mark", 1, 0, 0, scm_async_mark);
1cc91f1b 384
0f2d19dd
JB
385SCM
386scm_async_mark (a)
387 SCM a;
0f2d19dd
JB
388{
389 struct scm_async * it;
390 SCM_ASSERT (SCM_NIMP (a) && SCM_ASYNCP (a), a, SCM_ARG1, s_async_mark);
391 it = SCM_ASYNC (a);
392 it->got_it = 1;
393 return SCM_UNSPECIFIED;
394}
395
396
397SCM_PROC(s_system_async_mark, "system-async-mark", 1, 0, 0, scm_system_async_mark);
1cc91f1b 398
0f2d19dd
JB
399SCM
400scm_system_async_mark (a)
401 SCM a;
0f2d19dd
JB
402{
403 struct scm_async * it;
404 SCM_ASSERT (SCM_NIMP (a) && SCM_ASYNCP (a), a, SCM_ARG1, s_async_mark);
405 it = SCM_ASYNC (a);
406 SCM_REDEFER_INTS;
407 it->got_it = 1;
408 scm_async_rate = 1 + scm_async_rate - scm_async_clock;
409 scm_async_clock = 1;
410 SCM_REALLOW_INTS;
411 return SCM_UNSPECIFIED;
412}
413
414
415SCM_PROC(s_run_asyncs, "run-asyncs", 1, 0, 0, scm_run_asyncs);
1cc91f1b 416
0f2d19dd
JB
417SCM
418scm_run_asyncs (list_of_a)
419 SCM list_of_a;
0f2d19dd
JB
420{
421 SCM pos;
422
423 if (scm_mask_ints)
424 return SCM_BOOL_F;
425 pos = list_of_a;
426 while (pos != SCM_EOL)
427 {
428 SCM a;
429 struct scm_async * it;
430 SCM_ASSERT (SCM_NIMP (pos) && SCM_CONSP (pos), pos, SCM_ARG1, s_run_asyncs);
431 a = SCM_CAR (pos);
432 SCM_ASSERT (SCM_NIMP (a) && SCM_ASYNCP (a), a, SCM_ARG1, s_run_asyncs);
433 it = SCM_ASYNC (a);
434 scm_mask_ints = 1;
435 if (it->got_it)
436 {
437 it->got_it = 0;
438 scm_apply (it->thunk, SCM_EOL, SCM_EOL);
439 }
440 scm_mask_ints = 0;
441 pos = SCM_CDR (pos);
442 }
443 return SCM_BOOL_T;
444}
445
446\f
447
448
449SCM_PROC(s_noop, "noop", 0, 0, 1, scm_noop);
1cc91f1b 450
0f2d19dd
JB
451SCM
452scm_noop (args)
453 SCM args;
0f2d19dd
JB
454{
455 return (SCM_NULLP (args)
456 ? SCM_BOOL_F
457 : SCM_CAR (args));
458}
459
460
461\f
462
463SCM_PROC(s_set_tick_rate, "set-tick-rate", 1, 0, 0, scm_set_tick_rate);
1cc91f1b 464
0f2d19dd
JB
465SCM
466scm_set_tick_rate (n)
467 SCM n;
0f2d19dd
JB
468{
469 unsigned int old_n;
470 SCM_ASSERT (SCM_INUMP (n), n, SCM_ARG1, s_set_tick_rate);
471 old_n = scm_tick_rate;
472 scm_desired_tick_rate = SCM_INUM (n);
473 scm_async_rate = 1 + scm_async_rate - scm_async_clock;
474 scm_async_clock = 1;
475 return SCM_MAKINUM (old_n);
476}
477
478\f
479
480
481SCM_PROC(s_set_switch_rate, "set-switch-rate", 1, 0, 0, scm_set_switch_rate);
1cc91f1b 482
0f2d19dd
JB
483SCM
484scm_set_switch_rate (n)
485 SCM n;
0f2d19dd
JB
486{
487 unsigned int old_n;
488 SCM_ASSERT (SCM_INUMP (n), n, SCM_ARG1, s_set_switch_rate);
489 old_n = scm_switch_rate;
490 scm_desired_switch_rate = SCM_INUM (n);
491 scm_async_rate = 1 + scm_async_rate - scm_async_clock;
492 scm_async_clock = 1;
493 return SCM_MAKINUM (old_n);
494}
495
496\f
497
1cc91f1b
JB
498
499static SCM scm_sys_hup_async_thunk SCM_P ((void));
500
0f2d19dd
JB
501static SCM
502scm_sys_hup_async_thunk ()
0f2d19dd
JB
503{
504 scm_deliver_signal (SCM_HUP_SIGNAL);
505 return SCM_BOOL_F;
506}
507
1cc91f1b
JB
508
509static SCM scm_sys_int_async_thunk SCM_P ((void));
510
0f2d19dd
JB
511static SCM
512scm_sys_int_async_thunk ()
0f2d19dd
JB
513{
514 scm_deliver_signal (SCM_INT_SIGNAL);
515 return SCM_BOOL_F;
516}
517
1cc91f1b
JB
518
519static SCM scm_sys_fpe_async_thunk SCM_P ((void));
520
0f2d19dd
JB
521static SCM
522scm_sys_fpe_async_thunk ()
0f2d19dd
JB
523{
524 scm_deliver_signal (SCM_FPE_SIGNAL);
525 return SCM_BOOL_F;
526}
527
1cc91f1b
JB
528
529static SCM scm_sys_bus_async_thunk SCM_P ((void));
530
0f2d19dd
JB
531static SCM
532scm_sys_bus_async_thunk ()
0f2d19dd
JB
533{
534 scm_deliver_signal (SCM_BUS_SIGNAL);
535 return SCM_BOOL_F;
536}
537
1cc91f1b
JB
538
539static SCM scm_sys_segv_async_thunk SCM_P ((void));
540
0f2d19dd
JB
541static SCM
542scm_sys_segv_async_thunk ()
0f2d19dd
JB
543{
544 scm_deliver_signal (SCM_SEGV_SIGNAL);
545 return SCM_BOOL_F;
546}
547
1cc91f1b
JB
548
549static SCM scm_sys_alrm_async_thunk SCM_P ((void));
550
0f2d19dd
JB
551static SCM
552scm_sys_alrm_async_thunk ()
0f2d19dd
JB
553{
554 scm_deliver_signal (SCM_ALRM_SIGNAL);
555 return SCM_BOOL_F;
556}
557
1cc91f1b
JB
558
559static SCM scm_sys_gc_async_thunk SCM_P ((void));
560
0f2d19dd
JB
561static SCM
562scm_sys_gc_async_thunk ()
0f2d19dd
JB
563{
564 scm_deliver_signal (SCM_GC_SIGNAL);
565 return SCM_BOOL_F;
566}
567
1cc91f1b
JB
568
569static SCM scm_sys_tick_async_thunk SCM_P ((void));
570
0f2d19dd
JB
571static SCM
572scm_sys_tick_async_thunk ()
0f2d19dd
JB
573{
574 scm_deliver_signal (SCM_TICK_SIGNAL);
575 return SCM_BOOL_F;
576}
577
578
579
580\f
581
1cc91f1b 582
0f2d19dd
JB
583SCM
584scm_take_signal (n)
585 int n;
0f2d19dd
JB
586{
587 SCM ignored;
588 if (!scm_ints_disabled)
589 {
e4d24f3a
JB
590 /* For reasons of speed, the SCM_NEWCELL macro doesn't defer
591 interrupts. Instead, it first sets its argument to point to
592 the first cell in the list, and then advances the freelist
593 pointer to the next cell. Now, if this procedure is
594 interrupted, the only anomalous state possible is to have
595 both SCM_NEWCELL's argument and scm_freelist pointing to the
596 same cell. To deal with this case, we always throw away the
597 first cell in scm_freelist here.
598
599 At least, that's the theory. I'm not convinced that that's
600 the only anomalous path we need to worry about. */
601 SCM_NEWCELL (ignored);
0f2d19dd
JB
602 }
603 scm_system_async_mark (system_signal_asyncs[SCM_SIG_ORD(n)]);
604 return SCM_BOOL_F;
605}
606
607\f
608
609SCM_PROC(s_unmask_signals, "unmask-signals", 0, 0, 0, scm_unmask_signals);
1cc91f1b 610
0f2d19dd
JB
611SCM
612scm_unmask_signals ()
0f2d19dd
JB
613{
614 scm_mask_ints = 0;
615 return SCM_UNSPECIFIED;
616}
617
618
619SCM_PROC(s_mask_signals, "mask-signals", 0, 0, 0, scm_mask_signals);
1cc91f1b 620
0f2d19dd
JB
621SCM
622scm_mask_signals ()
0f2d19dd
JB
623{
624 scm_mask_ints = 1;
625 return SCM_UNSPECIFIED;
626}
627
628\f
629
1cc91f1b 630
0f2d19dd
JB
631void
632scm_init_async ()
0f2d19dd
JB
633{
634 SCM a_thunk;
635 scm_tc16_async = scm_newsmob (&async_smob);
ffa19a75 636 symbol_signal = SCM_CAR (scm_sysintern ("signal", SCM_UNDEFINED));
0f2d19dd
JB
637 scm_permanent_object (symbol_signal);
638
639 /* These are in the opposite order of delivery priortity.
640 *
641 * Error conditions are given low priority:
642 */
643 a_thunk = scm_make_gsubr ("%hup-thunk", 0, 0, 0, scm_sys_hup_async_thunk);
644 system_signal_asyncs[SCM_SIG_ORD(SCM_HUP_SIGNAL)] = scm_system_async (a_thunk);
645 a_thunk = scm_make_gsubr ("%int-thunk", 0, 0, 0, scm_sys_int_async_thunk);
646 system_signal_asyncs[SCM_SIG_ORD(SCM_INT_SIGNAL)] = scm_system_async (a_thunk);
647 a_thunk = scm_make_gsubr ("%fpe-thunk", 0, 0, 0, scm_sys_fpe_async_thunk);
648 system_signal_asyncs[SCM_SIG_ORD(SCM_FPE_SIGNAL)] = scm_system_async (a_thunk);
649 a_thunk = scm_make_gsubr ("%bus-thunk", 0, 0, 0, scm_sys_bus_async_thunk);
650 system_signal_asyncs[SCM_SIG_ORD(SCM_BUS_SIGNAL)] = scm_system_async (a_thunk);
651 a_thunk = scm_make_gsubr ("%segv-thunk", 0, 0, 0, scm_sys_segv_async_thunk);
652 system_signal_asyncs[SCM_SIG_ORD(SCM_SEGV_SIGNAL)] = scm_system_async (a_thunk);
653
654
655 a_thunk = scm_make_gsubr ("%gc-thunk", 0, 0, 0, scm_sys_gc_async_thunk);
656 system_signal_asyncs[SCM_SIG_ORD(SCM_GC_SIGNAL)] = scm_system_async (a_thunk);
657
658 /* Clock and PC driven conditions are given highest priority. */
659 a_thunk = scm_make_gsubr ("%tick-thunk", 0, 0, 0, scm_sys_tick_async_thunk);
660 system_signal_asyncs[SCM_SIG_ORD(SCM_TICK_SIGNAL)] = scm_system_async (a_thunk);
661 a_thunk = scm_make_gsubr ("%alrm-thunk", 0, 0, 0, scm_sys_alrm_async_thunk);
662 system_signal_asyncs[SCM_SIG_ORD(SCM_ALRM_SIGNAL)] = scm_system_async (a_thunk);
663
ffa19a75 664 handler_var = scm_sysintern ("signal-handler", SCM_UNDEFINED);
0f2d19dd
JB
665 SCM_SETCDR (handler_var, SCM_BOOL_F);
666 scm_permanent_object (handler_var);
667#include "async.x"
668}