1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1989-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23/*
24 * VERSION	$Id: handlers.c,v 1.9 2012/10/17 10:05:20 jschimpf Exp $
25 */
26
27/*
28 *
29 * Builtins to set up and manipulate handler tables
30 *
31 */
32
33#include "config.h"
34
35#include <errno.h>
36#include <signal.h>
37
38#ifdef HAVE_STRING_H
39#include <string.h>
40#else
41extern char	*strcpy();
42#endif
43
44#include <stdio.h>	/* for sprintf() */
45#include <stdlib.h>	/* for exit() */
46
47#include "sepia.h"
48#include "types.h"
49#include "embed.h"
50#include "mem.h"
51#include "error.h"
52#include "dict.h"
53#include "emu_export.h"
54#include "ec_io.h"
55#include "module.h"
56#include "property.h"
57#include "os_support.h"
58
59
60#define MAX_HANDLER_ARITY 4
61
62/*
63 * Define sig_action_t in a portable way
64 */
65
66#ifdef HAVE_SIGACTION
67typedef struct sigaction sig_action_t;
68#else
69#  ifdef HAVE_SIGVEC	/* first try VEC because ACTION does not match STACK */
70typedef struct sigvec sig_action_t;
71#define sa_handler sv_handler
72#define sa_mask sv_mask
73#define sa_flags sv_flags
74#  else
75typedef struct {
76	RETSIGTYPE (*sa_handler)(int);
77	int sa_mask;
78	int sa_flags;
79} sig_action_t;
80#  endif
81#endif
82
83
84/* SA_INTERRUPT is System V (pre-R4)
85 * SVR4 has SA_RESTART instead, meaning the opposite
86 */
87# ifndef SA_INTERRUPT
88#  define SA_INTERRUPT 0
89# endif
90
91
92/*
93 * Signal blocking and unblocking
94 * We maintain a mask sig_block_mask_ to block all interrupts
95 * whose handler might enqueue signals or post events - this is
96 * to implement exclusive access to these queue data structures.
97 */
98
99#ifdef HAVE_SIGPROCMASK
100
101#define If_Have_Sig_Masks(Decl) Decl;
102#define Empty_Sig_Mask(Mask) (void) sigemptyset(&(Mask));
103#define Save_Sig_Mask(Mask) \
104	(void) sigprocmask(SIG_SETMASK, (sigset_t *) 0, &(Mask));
105#define Restore_Sig_Mask(Mask) \
106	(void) sigprocmask(SIG_SETMASK, &(Mask), (sigset_t *) 0);
107#define Block_Signal(i) { \
108	sigset_t mask; \
109	sigemptyset(&mask); \
110	sigaddset(&mask, i); \
111	sigprocmask(SIG_BLOCK, &mask, (sigset_t *) 0); }
112#define Unblock_Signal(i) { \
113	sigset_t mask; \
114	sigemptyset(&mask); \
115	sigaddset(&mask, i); \
116	sigprocmask(SIG_UNBLOCK, &mask, (sigset_t *) 0); }
117
118#define Init_Block_Mask() Empty_Sig_Mask(sig_block_mask_)
119#define	Add_To_Block_Mask(i) sigaddset(&sig_block_mask_, i);
120#define	Del_From_Block_Mask(i) sigdelset(&sig_block_mask_, i);
121#define Block_Signals(OldMask) \
122	(void) sigprocmask(SIG_BLOCK, &sig_block_mask_, &(OldMask));
123
124#else
125#ifdef HAVE_SIGVEC
126
127typedef int sigset_t;
128
129#ifndef sigmask
130# define sigmask(n)      (1 << ((n) - 1))
131#endif
132
133#define If_Have_Sig_Masks(Decl) Decl;
134#define Empty_Sig_Mask(Mask) (Mask) = 0;
135#define Save_Sig_Mask(Mask) (Mask) = sigblock(0);
136#define Restore_Sig_Mask(Mask) (void) sigsetmask(Mask);
137#define Block_Signal(i) \
138	(void) sigblock(sigmask(i));
139#define Unblock_Signal(i) \
140	(void) sigsetmask(sigblock(0) & ~sigmask(i));
141
142#define Init_Block_Mask() Empty_Sig_Mask(sig_block_mask_)
143#define	Add_To_Block_Mask(i) sig_block_mask_ |= sigmask(i);
144#define	Del_From_Block_Mask(i) sig_block_mask_ &= ~sigmask(i);
145#define Block_Signals(OldMask) OldMask = sigblock(sig_block_mask_);
146
147#else
148
149#define If_Have_Sig_Masks(Decl)
150#define Empty_Sig_Mask(Mask) // (Mask) = 0;
151#define Save_Sig_Mask(Mask)
152#define Restore_Sig_Mask(Mask)
153#define Block_Signal(i)
154#define Unblock_Signal(i)
155
156#define Init_Block_Mask()
157#define	Add_To_Block_Mask(i)
158#define	Del_From_Block_Mask(i)
159#define Block_Signals(OldMask)
160
161#endif
162#endif
163
164#define Unblock_Signals() Restore_Sig_Mask(initial_sig_mask_)
165
166If_Have_Sig_Masks(static sigset_t initial_sig_mask_)	/* normal execution sigmask */
167If_Have_Sig_Masks(static sigset_t sig_block_mask_)	/* what to block on handler invoc */
168
169static int	spurious = 0;	/* counts nesting of fatal signals */
170
171
172/*
173 * The signal that flags C stack overflow must be executed on a different
174 * stack, else the handler can't be called. This stack must be big enough
175 * to call an emulator and execute the handler (which should call reset/0).
176 */
177
178#ifdef HAVE_SIGALTSTACK
179static char		signal_stack[SIGSTKSZ];
180static stack_t		sigstack_descr;
181#else
182# ifdef HAVE_SIGSTACK
183# ifndef SV_ONSTACK
184#  define SV_ONSTACK 1
185# endif
186# define SIGSTACK_SIZE	4096
187static char		signal_stack[SIGSTACK_SIZE];
188static struct sigstack	sigstack_descr;
189# endif
190#endif
191
192
193#ifdef SIGBUS
194#define IsSIGBUS(n) ((n) == SIGBUS)
195#else
196#define IsSIGBUS(n) 0
197#endif
198#ifdef SIGQUIT
199#define IsSIGQUIT(n) ((n) == SIGQUIT)
200#else
201#define IsSIGQUIT(n) 0
202#endif
203
204#define FatalSignal(n) \
205	((n)==SIGILL || (n)==SIGSEGV || IsSIGBUS(n) || IsSIGQUIT(n))
206
207
208/*
209 * EXTERN declarations
210 */
211
212extern pri	*true_proc_,
213		*fail_proc_;
214
215extern void		halt_session(void);
216
217
218/*
219 * GLOBAL variable definitions
220 */
221
222/* Error handlers */
223pri	**error_handler_;
224pri	**default_error_handler_;
225
226/*
227 * Interrupt handlers
228 * There is a flag array and a handler array.
229 * The latter is only valid if the flag is IH_HANDLE_ASYNC.
230 */
231int	*interrupt_handler_flags_ = 0;
232pri	**interrupt_handler_ = 0;
233dident	*interrupt_name_ = 0;
234int	ec_sigalrm;	/* normally SIGALRM, but also defined on Windows */
235int	ec_sigio;	/* normally SIGIO, but also defined on Windows */
236
237static dident	d_event_, d_throw_, d_internal_, d_defers_;
238static type	kernel_tag_;
239static int	user_error = USER_ERROR;
240
241
242int	p_reset(void);
243
244static int
245	p_pause(void),
246        p_get_event_handler(value vn, type tn, value vh, type th, value vm, type tm),
247	p_define_error(value valm, type tagm, value vale, type tage),
248	p_get_interrupt_handler(value vn, type tn, value vh, type th, value vm, type tm),
249	p_interrupt_id_det(value vnum, type tnum, value vname, type tname),
250	p_post_events(value v, type t),
251	p_set_error_handler(value vn, type tn, value vp, type tp, value vm, type tm),
252	p_reset_error_handler(value vn, type tn),
253	p_set_default_error_handler(value vn, type tn, value vp, type tp, value vm, type tm),
254	p_set_interrupt_handler(value vn, type tn, value vp, type tp, value vm, type tm),
255	p_valid_error(value vn, type tn);
256static int
257	_set_error_array(pri **arr, word n, dident w, value vm, type tm);
258
259#ifdef SA_SIGINFO
260static RETSIGTYPE _break(int, siginfo_t*, void *);
261#else
262static RETSIGTYPE _break(int);
263#endif
264
265/* Profiling handler is defined in emu.c */
266#if defined(__GNUC__) && defined(HAVE_UCONTEXTGREGS)
267extern RETSIGTYPE sigprof_handler(int, siginfo_t*, void *);
268#else
269extern RETSIGTYPE sigprof_handler(int);
270#endif
271
272#define Check_Error_Number(v,t)				\
273	Check_Integer(t)				\
274	if ( (v).nint < 1				\
275		|| (v).nint >= MAX_ERRORS		\
276		|| !ErrorMessage[(v).nint] )		\
277	    { Bip_Error(RANGE_ERROR) }
278
279#define Check_Interrupt_Number(v,t)			\
280    Check_Integer(t)					\
281    if((v).nint <= 0 || (v).nint >= NSIG)		\
282	{ Bip_Error(RANGE_ERROR) }
283
284
285/*----------------------------------------------------------------------
286 * Signal handling
287 *
288 * In a standalone eclipse, we try to catch all signals
289 * and handle them in Prolog, if possible.
290 *
291 * When interrupts (except fatal ones) are disabled by Disable_Int,
292 * we delay them by putting them into the delayed_interrupt_ queue
293 * and reconsider them in delayed_break() which is invoked by Enable_Int.
294 *
295 * Signals that are required to be handled "synchronously" (ie. handler
296 * was set to event/1, indicated by the IH_POST_EVENT flag)
297 * are done by (eventually) posting an event with the signal's Prolog name,
298 * e.g. 'alrm' for SIGALRM.
299 *
300 * Asynchronous signal handling is normally done via a recursive engine
301 * by calling it_emulc(). However, this is not possible while the
302 * emulator registers are not exported (EXPORTED flag). In that case,
303 * we post the signal number (integer) as an event, and the handler
304 * will then be executed by the original engine. The DEL_IRQ_POSTED
305 * flag is set to indicate that there is an async signal in the queue.
306 *----------------------------------------------------------------------*/
307
308#define NBDELAY	32
309
310static int _enqueue_irq(int n), _dequeue_irq(void);
311static int delayed_interrupt_[NBDELAY];
312static int first_delayed_ = 0, next_delayed_ = 0;
313
314If_Have_Sig_Masks(static sigset_t mask_before_blocking_)
315
316void
317block_signals(void)
318{
319    Block_Signals(mask_before_blocking_);
320}
321
322void
323unblock_signals(void)
324{
325    Restore_Sig_Mask(mask_before_blocking_);
326}
327
328
329static void
330_handle_fatal(int n)
331{
332    if (spurious > 1)
333    {
334	exit(-1);		/* we keep everything blocked */
335    }
336    else if (spurious++ == 1)
337    {
338	value v1;
339	v1.nint = -1;
340	(void) p_exit(v1, tint);
341    }
342    first_delayed_ = next_delayed_ = 0;
343    /*
344     * In the development system
345     * signals will be unblocked upon reinit (handlers_init())
346     */
347    ec_panic("Fatal signal caught",
348	(VM_FLAGS & EXPORTED)? "protected code": "emulator");
349}
350
351
352static void
353_handle_async(int n, int polling)		 /* may be 0 */
354{
355    /* not InterruptsDisabled! */
356
357#if defined(SIGIO) || defined(SIGPOLL)
358#if !defined(SIGIO)
359    if (n == SIGPOLL)
360#else
361#if !defined(SIGPOLL)
362    if (n == SIGIO)
363#else
364    if (n == SIGIO || n == SIGPOLL)
365#endif
366#endif
367    {
368	msg_trigger();
369	if (!(interrupt_handler_flags_
370	     && (interrupt_handler_flags_[n] == IH_HANDLE_ASYNC
371	      || interrupt_handler_flags_[n] == IH_POST_EVENT)))
372	{
373	    return;
374	}
375    }
376#endif
377
378    if (FatalSignal(n))
379    {
380	if (spurious > 0		/* already tried unsuccessfully */
381	    || !(VM_FLAGS & EXPORTED))	/* can't get a recursive engine */
382	{
383	    _handle_fatal(n);
384	}
385	spurious = 1;			/* first attempt to handle */
386	/* invoke Prolog handler below */
387    }
388    else if (interrupt_handler_flags_[n] == IH_HANDLE_ASYNC)
389    {
390	if (!(VM_FLAGS & EXPORTED))	/* can't get a recursive engine */
391	{
392	    if (ec_post_event_int(n) != PSUCCEED)
393		(void) write(2,"\nEvent queue overflow - signal lost\n",36);
394	    return;
395	}
396	/* else invoke Prolog handler below */
397
398    }
399    else if (interrupt_handler_flags_[n] == IH_POST_EVENT)
400    {
401	if (ec_post_event_int(n) != PSUCCEED)
402	    (void) write(2,"\nEvent queue overflow - signal lost\n",36);
403	return;
404    }
405    else if (interrupt_handler_flags_[n] == IH_ABORT
406	 ||  interrupt_handler_flags_[n] == IH_THROW)
407    {
408	if (polling) {
409	    pword exit_tag;
410	    Make_Atom(&exit_tag, interrupt_handler_flags_[n] == IH_ABORT ?
411				    d_.abort : interrupt_name_[n]);
412	    (void) longjmp_throw(exit_tag.val, exit_tag.tag);
413	} else {
414	    /* We are in signal handler or timer thread, i.e. it is not
415	     * safe to abort here. Post, and handle later via polling */
416	    if (ec_post_event_int(n) != PSUCCEED)
417		(void) write(2,"\nEvent queue overflow - signal lost\n",36);
418	}
419	return;
420    }
421    else
422    {
423	(void) write(2,"\nUnexpected interrupt type in handle_async()\n",45);
424	return;
425    }
426
427    /*
428     * Invoke the Prolog handler for signal n
429     */
430    {
431	int i;
432	value v1, v2;
433	v1.nint = n;
434	i = it_emulc(v1, tint);
435	if (FatalSignal(n))
436	    spurious--;
437	if (i == PTHROW)
438	{
439	    if (!ec_options.parallel_worker || g_emu_.nesting_level > 1)
440		longjmp(*g_emu_.it_buf, PTHROW);
441	    else if (!IsRecursionFrame(BTop(B.args)))
442	    {
443		pword event;
444		Make_Atom(&event, d_.abort);
445		(void) ec_post_event(event);
446	    }
447	    /* else ignore the THROW, we are in an idle worker */
448	}
449    }
450}
451
452
453#ifdef SA_SIGINFO
454static RETSIGTYPE
455_break(int n, siginfo_t *si, void *dummy)
456#else
457static RETSIGTYPE
458_break(int n)
459#endif
460{
461    /* signal n should be blocked on handler invocation */
462
463#if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC)
464    signal(n,_break);	/* restore signal catcher to _break	*/
465#endif
466
467#ifdef SA_SIGINFO
468    if (FatalSignal(n) && si) {
469	char buf[128];
470	sprintf(buf, "Fatal signal (signal=%d, si_code=%d, si_addr=%08x)\n",
471			n, si->si_code, si->si_addr);
472	write(2, buf, strlen(buf));
473    }
474#endif
475
476    if (InterruptsDisabled)
477    {
478	if (FatalSignal(n))
479	{
480	    _handle_fatal(n);
481	}
482	else				/* not fatal, delay it */
483	{
484	    (void) _enqueue_irq(n);	/* incl. Set_Interrupts_Pending */
485	}
486	return;
487    }
488
489    Unblock_Signal(n);
490    _handle_async(n, 0);
491}
492
493
494void
495delayed_break(void)
496{
497    int n;
498    int saved_errno = errno;	/* to avoid unexpected side effects */
499
500    while (InterruptsPending && (n = _dequeue_irq()) != -1)
501    {
502	_handle_async(n, 0);
503    }
504    errno = saved_errno;
505}
506
507
508/*
509 * This is called from asynchronous points in the emulator to allow
510 * handling urgent events.
511 */
512void
513ec_handle_async(void)		/* !InterruptsDisabled && EXPORTED */
514{
515    int n;
516    while ((n = next_urgent_event()) != -1)
517    {
518	_handle_async(n, 1);
519    }
520}
521
522
523static int
524_dequeue_irq(void)
525{
526    int n;
527    If_Have_Sig_Masks(sigset_t saved_mask)
528
529    Block_Signals(saved_mask);
530    if (first_delayed_ != next_delayed_)	/* empty? */
531    {
532	n = delayed_interrupt_[first_delayed_];	/* no: get one	*/
533	first_delayed_ = (first_delayed_ + 1) % NBDELAY;
534	if (first_delayed_ == next_delayed_)	/* last one? */
535	{
536	    Clr_Interrupts_Pending();
537	}
538    }
539    else
540    {
541	n = -1;
542	Clr_Interrupts_Pending();
543    }
544    Restore_Sig_Mask(saved_mask);
545    return n;
546}
547
548static int
549_enqueue_irq(int n)		/* must not be interrupted */
550{
551    int i = (next_delayed_ + 1) % NBDELAY;
552
553    if (i == first_delayed_)	/* queue full ? */
554    {
555	(void) write(2,"\nInterrupt queue overflow - signal lost\n",40);
556	/* Some machines cannot continue after a signal, they would
557	   loop infinitely with queue overflow */
558	_handle_fatal(n);
559	/*NOTREACHED*/
560    }
561    delayed_interrupt_[next_delayed_] = n;
562    next_delayed_ = i;		/* enter in queue */
563
564    Set_Interrupts_Pending();
565    return 0;
566}
567
568
569/*
570 * Handler used for message passing
571 * This handler can be used for SIGIO/SIGPOLL when these signals are
572 * not needed otherwise. It is not used anymore because we need to
573 * handle SIGIO synchronously in order to implement socket events.
574 */
575
576RETSIGTYPE
577sigmsg_handler(int n)
578{
579    if (InterruptsDisabled )
580    {
581	(void) _enqueue_irq(n);
582    }
583    else
584    {
585	Unblock_Signal(n);
586	msg_trigger();
587	return;
588    }
589}
590
591
592static int
593_install_int_handler(int i, int how)
594{
595    int res;
596    sig_action_t action;
597
598#ifndef SIGIO
599    if (i == ec_sigio)
600    {
601	Succeed_;	/* this is a fake signal number, do nothing */
602    }
603#endif
604#ifndef SIGALRM
605    if (i == ec_sigalrm)
606    {
607	Succeed_;	/* this is a fake signal number, do nothing */
608    }
609#endif
610
611    Empty_Sig_Mask(action.sa_mask);
612    action.sa_flags = SA_INTERRUPT;
613
614    switch(how)
615    {
616    case IH_HANDLE_ASYNC:
617#if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC)
618	Bip_Error(UNIMPLEMENTED);	/* e.g. Windows... */
619#else
620	if (i == SIGSEGV)
621	{
622	    /* try to run the SIGSEGV handler on its own stack */
623#ifdef HAVE_SIGALTSTACK
624	    sigstack_descr.ss_sp = signal_stack;
625	    sigstack_descr.ss_size = SIGSTKSZ;
626	    sigstack_descr.ss_flags = 0;
627	    (void) sigaltstack(&sigstack_descr, (stack_t *) 0);
628	    /* We may need SA_SIGINFO for more sophisticated SEGV handling */
629	    action.sa_flags = SA_ONSTACK | SA_INTERRUPT;
630#else
631#  ifdef HAVE_SIGSTACK
632	    sigstack_descr.ss_sp = signal_stack + SIGSTACK_SIZE;
633	    sigstack_descr.ss_onstack = 0;
634	    (void) sigstack(&sigstack_descr, (struct sigstack*)0);
635	    action.sa_flags = SA_ONSTACK;
636#  endif
637#endif
638	}
639#ifdef SA_SIGINFO
640	if (FatalSignal(i)) {
641	    action.sa_flags |= SA_SIGINFO;
642	}
643#endif
644	Add_To_Block_Mask(i);
645#ifdef SA_SIGINFO
646	action.sa_sigaction = _break;
647#else
648	action.sa_handler = _break;
649#endif
650#endif
651	break;
652
653    case IH_UNCHANGED:
654	/* We can't change back from something else to this one */
655	Succeed_;
656
657    case IH_SYSTEM_DFL:
658	Del_From_Block_Mask(i);
659	action.sa_handler = SIG_DFL;
660	break;
661
662    case IH_IGNORE:
663	Del_From_Block_Mask(i);
664	action.sa_handler = SIG_IGN;
665	break;
666
667    case IH_THROW:
668    case IH_ABORT:
669    case IH_POST_EVENT:
670	Add_To_Block_Mask(i);
671#ifdef SA_SIGINFO
672	action.sa_flags |= SA_SIGINFO;
673	action.sa_sigaction = _break;
674#else
675	action.sa_handler = _break;
676#endif
677	break;
678
679    case IH_HALT:
680	Add_To_Block_Mask(i);
681	action.sa_handler = (RETSIGTYPE(*)(int)) halt_session;
682	break;
683
684    case IH_ECLIPSE_DFL:
685	/*
686	 * This sets handlers that are needed to implement internal
687	 * Eclipse functionality like timers, profiler etc
688	 */
689	switch(i)
690	{
691#ifdef SIGPROF
692	case SIGPROF:
693	    Del_From_Block_Mask(i);
694#if defined(__GNUC__) && defined(HAVE_UCONTEXTGREGS)
695	    action.sa_flags |= SA_SIGINFO;
696	    action.sa_sigaction = sigprof_handler;
697#else
698	    action.sa_handler = sigprof_handler;
699#endif
700	    break;
701#endif
702#if defined(SIGIO)
703	case SIGIO:
704	    Add_To_Block_Mask(i);
705	    action.sa_handler = sigmsg_handler;
706	    break;
707#endif
708#if defined(SIGPOLL) && (!defined(SIGIO) || SIGPOLL != SIGIO)
709	case SIGPOLL:
710	    Add_To_Block_Mask(i);
711	    action.sa_handler = sigmsg_handler;
712	    break;
713#endif
714	default:
715	    Del_From_Block_Mask(i);
716	    Succeed_;
717	}
718	break;
719    }
720
721#ifdef HAVE_SIGACTION
722    res = sigaction(i, &action, (struct sigaction *) 0);
723#else
724#ifdef HAVE_SIGVEC
725    res = sigvec(i, &action, (struct sigvec *) 0);
726#else
727    res = ( signal(i, action.sa_handler) == SIG_ERR ? -1 : 0 );
728#endif
729#endif
730
731    if (res == -1  &&  action.sa_handler != SIG_IGN)
732    {
733	Set_Errno;
734	Bip_Error(SYS_ERROR);
735    }
736    errno = 0;	/* something couldn't be ignored, silently accept */
737    Succeed_;
738}
739
740
741/*
742 * Reset all signal handlers that are set to Eclipse-specific
743 * handling, because we are about to shut down Eclipse.
744 * Additionally, ignore SIGPIPE, because it might be raised
745 * during cleanup of the Eclipse streams.
746 */
747
748void
749handlers_fini()
750{
751    int i;
752
753    for(i = 1; i < NSIG; i++)
754    {
755	if (InterruptName[i] != D_UNKNOWN)
756	{
757	    switch (interrupt_handler_flags_[i])
758	    {
759	    case IH_ECLIPSE_DFL:
760	    case IH_POST_EVENT:
761	    case IH_THROW:
762	    case IH_ABORT:
763	    case IH_HANDLE_ASYNC:
764		(void) _install_int_handler(i, IH_SYSTEM_DFL);
765		break;
766
767	    case IH_UNCHANGED:
768	    case IH_SYSTEM_DFL:
769	    case IH_IGNORE:
770	    default:
771		break;
772	    }
773	}
774    }
775#ifdef SIGPIPE
776    (void) _install_int_handler(SIGPIPE, IH_IGNORE);
777#endif
778}
779
780
781/* Given tagged integer or atom, return signal number (or negative error code) */
782int ec_signalnum(value vsig, type tsig)
783{
784    if (IsInteger(tsig)) {
785	if (vsig.nint > 0 && vsig.nint < NSIG && interrupt_name_[vsig.nint] != D_UNKNOWN)
786	    return (int) vsig.nint;
787	return RANGE_ERROR;
788
789    } else if IsAtom(tsig) {
790	int i;
791	for (i = 1; i < NSIG; i++)
792	    if (interrupt_name_[i] == vsig.did)
793		return i;
794	return RANGE_ERROR;
795
796    } else if (IsBignum(tsig)) {
797	return RANGE_ERROR;
798    } else if IsRef(tsig) {
799	return INSTANTIATION_FAULT;
800    }
801    return TYPE_ERROR;
802}
803
804
805static int
806p_interrupt_id_det(value vnum, type tnum, value vname, type tname)
807{
808    if (IsInteger(tnum))
809    {
810	dident int_did;
811	if (vnum.nint <= 0 || vnum.nint >= NSIG) {
812	    Fail_;
813	}
814	if ((int_did = interrupt_name_[vnum.nint]) != D_UNKNOWN)
815	{
816	    Return_Unify_Atom(vname, tname, int_did);
817	} else {
818	    Return_Unify_Atom(vname, tname, d_.eocl);
819	}
820    }
821    else if (IsAtom(tname))
822    {
823	int i;
824	for (i = 1; i < NSIG; i++)
825	{
826	    if (interrupt_name_[i] == vname.did)
827	    {
828		Return_Unify_Integer(vnum, tnum, i);
829	    }
830	}
831    }
832    Fail_;
833}
834
835
836/*
837 *		define_error(+Message, -ErrorNumber)
838 *
839 */
840
841static int
842p_define_error(value valm, type tagm, value vale, type tage)
843{
844	int m;
845
846	Check_String(tagm);
847	Check_Ref(tage);
848
849	m = user_error++;
850	if(m >=  MAX_ERRORS)
851	{
852	    Bip_Error(RANGE_ERROR);
853	}
854	ErrorMessage[m] = (char *) hg_alloc((int)StringLength(valm)+1);
855	(void) strcpy(ErrorMessage[m], StringStart(valm));
856	error_handler_[m] = qualified_procedure(d_.error_handler,
857		d_.kernel_sepia, d_.kernel_sepia, kernel_tag_);
858	Return_Unify_Integer(vale, tage, m);
859}
860
861/*
862 * The handler array entries are considered qualified references
863 * from sepia_kernel. If no exported handler exists, we create one.
864 */
865static pri *
866_kernel_ref_export_proc(dident pdid, dident mod, type mod_tag)
867{
868    pri *pd = visible_procedure(pdid, mod, mod_tag, 0);
869    if (!pd  ||  PriScope(pd) == LOCAL)
870    {
871	int err;
872	Get_Bip_Error(err);	/* reset error code from visible_procedure() */
873	pd = export_procedure(pdid, mod, mod_tag);
874	if (!pd)
875	    return 0;
876    }
877    return qualified_procedure(pdid, PriHomeModule(pd),
878    				d_.kernel_sepia, kernel_tag_);
879}
880
881/*
882 * setting a handler for an existing error code
883 * p_set_error_handler(vn,tn,vp,tp)	FUNCTION
884 * (vn,tn) defines the error code
885 * (vp,tp) defines a handler
886 */
887
888/*ARGSUSED*/
889static int
890p_set_error_handler(value vn, type tn, value vp, type tp, value vm, type tm)
891{
892    dident	pdid;
893    int		err, defers = 0;
894
895    Error_If_Ref(tn);
896    Check_Module(tm, vm);
897    if (IsStructure(tp)  &&  vp.ptr->val.did == d_defers_)
898    {
899	++vp.ptr;
900	Dereference_(vp.ptr);
901	tp.all = vp.ptr->tag.all;
902	vp.all = vp.ptr->val.all;
903	defers = 1;
904    }
905    Get_Proc_Did(vp, tp, pdid);
906
907    if (IsNumber(tn))
908    {
909	if (defers)
910	    { Bip_Error(UNIMPLEMENTED); }
911	Check_Error_Number(vn, tn)
912	return _set_error_array(error_handler_, vn.nint, pdid, vm, tm);
913    }
914    else if (IsAtom(tn))
915    {
916	pri *proc;
917	pword *prop;
918
919	if (DidArity(pdid) > MAX_HANDLER_ARITY)
920	{
921	    Bip_Error(RANGE_ERROR)
922	}
923	proc = _kernel_ref_export_proc(pdid, vm.did, tm);
924	if (!proc)
925	{
926	    Get_Bip_Error(err);
927	    Bip_Error(err);
928	}
929
930	a_mutex_lock(&PropertyLock);
931	prop = get_property(vn.did, EVENT_PROP);
932	if (!prop)
933	    prop = set_property(vn.did, EVENT_PROP);
934	prop->tag.kernel = TPROC | (defers? EVENT_DEFERS: 0);
935	prop->val.ptr = (pword *) proc;
936	a_mutex_unlock(&PropertyLock);
937	Succeed_;
938    }
939    else
940    {
941	Bip_Error(TYPE_ERROR);
942    }
943}
944
945/* post events from a list into the event queue */
946static int
947p_post_events(value v, type t)
948{
949    if (IsList(t))
950    {
951	pword *cdr = v.ptr;
952	for(;;)
953	{
954	    int res;
955	    pword *car = cdr++;
956	    Dereference_(car);
957	    if (IsInteger(car->tag)) {
958		Bip_Error(TYPE_ERROR);
959	    }
960	    /* Integers aren't allowed, let ec_post_event type check rest */
961	    res = ec_post_event(*car);
962	    if (res != PSUCCEED)
963	    {
964		Bip_Error(res);
965	    }
966	    Dereference_(cdr);
967	    if (IsRef(cdr->tag))
968	    {
969		Bip_Error(INSTANTIATION_FAULT);
970	    }
971	    else if (IsNil(cdr->tag))
972		break;
973	    else if (IsList(cdr->tag))
974		cdr = cdr->val.ptr;
975	    else
976	    {
977		Bip_Error(TYPE_ERROR);
978	    }
979	}
980	Succeed_;
981    }
982    Check_Nil(t);
983}
984
985static int
986p_set_default_error_handler(value vn, type tn, value vp, type tp, value vm, type tm)
987{
988    dident	pdid;
989    Check_Error_Number(vn, tn)
990    Check_Module(tm, vm);
991    Get_Proc_Did(vp, tp, pdid);
992    return _set_error_array(default_error_handler_, vn.nint, pdid, vm, tm);
993}
994
995/*ARGSUSED*/
996static int
997_set_error_array(pri **arr, word n, dident w, value vm, type tm)
998{
999    pri		*proc;
1000    int		err;
1001
1002    if(DidArity(w) > MAX_HANDLER_ARITY && (n < -(DEBUG_CALL_EVENT) || n > -(DEBUG_REDO_EVENT)))
1003    {
1004        Bip_Error(RANGE_ERROR)
1005    }
1006    if(w == d_.true0)
1007    {
1008	arr[n] = true_proc_;
1009	Succeed_;
1010    } else if(w == d_.fail) {
1011	arr[n] = fail_proc_;
1012	Succeed_;
1013    } /* else */
1014    proc = _kernel_ref_export_proc(w, vm.did, tm);
1015    if(!proc)
1016    {
1017	Get_Bip_Error(err);
1018	Bip_Error(err);
1019    }
1020    /* disallow tools here */
1021    arr[n] = proc;
1022    Succeed_;
1023}
1024
1025static int
1026p_reset_error_handler(value vn, type tn)
1027{
1028    Error_If_Ref(tn);
1029    if (IsInteger(tn))
1030    {
1031	Check_Error_Number(vn,tn)
1032	error_handler_[vn.nint] = default_error_handler_[vn.nint];
1033	Succeed_;
1034    }
1035    else if IsAtom(tn)
1036    {
1037	int err = erase_property(vn.did, EVENT_PROP);
1038	if (err < 0)
1039	{
1040	    Bip_Error(err);
1041	}
1042	Succeed_;
1043    }
1044    else
1045    {
1046	Bip_Error(TYPE_ERROR);
1047    }
1048}
1049
1050
1051static int
1052p_set_interrupt_handler(value vn, type tn, value vp, type tp, value vm, type tm)
1053{
1054    dident w;
1055    pri *proc = 0;
1056    int sig, err, how;
1057
1058    Check_Module(tm, vm);
1059    sig = ec_signalnum(vn, tn);
1060    if (sig < 0) { Bip_Error(sig); }
1061    Get_Proc_Did(vp, tp, w);
1062    if(DidArity(w) > 1)
1063    {
1064        Bip_Error(RANGE_ERROR)
1065    }
1066    if (w == d_.default0)
1067	how = IH_SYSTEM_DFL;
1068    else if (w == d_internal_)
1069	how = IH_ECLIPSE_DFL;
1070    else if (w == d_.true0)
1071	how = IH_IGNORE;
1072    else if (w == d_event_)
1073	how = IH_POST_EVENT;
1074    else if (w == d_throw_)
1075	how = IH_THROW;
1076    else if (w == d_.abort)
1077	how = IH_ABORT;
1078    else if (w == d_.halt)
1079	how = IH_HALT;
1080    else
1081    {
1082	how = IH_HANDLE_ASYNC;
1083	proc = _kernel_ref_export_proc(w, vm.did, tm);
1084	if(!proc)
1085	{
1086	    Get_Bip_Error(err);
1087	    Bip_Error(err);
1088	}
1089    }
1090    err = _install_int_handler(sig, how);
1091    Return_If_Error(err);
1092    if (err == PSUCCEED)        /* do nothing for PFAIL */
1093    {
1094        interrupt_handler_flags_[sig] = how;
1095        interrupt_handler_[sig] = proc;
1096    }
1097    Succeed_;
1098}
1099
1100
1101static p_pause(void)
1102{
1103#ifdef SIGSTOP
1104    reset_ttys_and_buffers();
1105    (void) kill(0, SIGSTOP);
1106    Succeed_;
1107#else
1108#ifdef SIGSUSP
1109    reset_ttys_and_buffers();
1110    (void) kill(0, SIGSUSP);
1111    Succeed_;
1112#else
1113    Bip_Error(NOT_AVAILABLE);
1114#endif
1115#endif
1116}
1117
1118
1119/*ARGSUSED*/
1120static int
1121p_get_interrupt_handler(value vn, type tn, value vh, type th, value vm, type tm)
1122{
1123    dident	wdid, module;
1124    pri		*proc;
1125    pword	*pw = TG;
1126    int		sig;
1127    Prepare_Requests;
1128
1129    sig = ec_signalnum(vn, tn);
1130    if (sig < 0) { Bip_Error(sig); }
1131    if (!IsRef(th)) {
1132	Check_Structure(th);
1133	if (vh.ptr->val.did != d_.quotient) {Bip_Error(TYPE_ERROR); }
1134	Check_Output_Atom_Or_Nil(vh.ptr[1].val, vh.ptr[1].tag);
1135	Check_Output_Integer(vh.ptr[2].tag);
1136    }
1137    Check_Output_Atom_Or_Nil(vm, tm);
1138
1139    switch(interrupt_handler_flags_[sig])
1140    {
1141    case IH_UNCHANGED:
1142	Fail_;
1143    case IH_SYSTEM_DFL:
1144	wdid = d_.default0;
1145	module = d_.kernel_sepia;
1146	break;
1147    case IH_ECLIPSE_DFL:
1148	wdid = d_internal_;
1149	module = d_.kernel_sepia;
1150	break;
1151    case IH_IGNORE:
1152	wdid = d_.true0;
1153	module = d_.kernel_sepia;
1154	break;
1155    case IH_POST_EVENT:
1156	wdid = d_event_;
1157	module = d_.kernel_sepia;
1158	break;
1159    case IH_THROW:
1160	wdid = d_throw_;
1161	module = d_.kernel_sepia;
1162	break;
1163    case IH_ABORT:
1164	wdid = d_.abort;
1165	module = d_.kernel_sepia;
1166	break;
1167    case IH_HALT:
1168	wdid = d_.halt;
1169	module = d_.kernel_sepia;
1170	break;
1171    case IH_HANDLE_ASYNC:
1172	proc = interrupt_handler_[sig];
1173	wdid = PriDid(proc);
1174	module = PriHomeModule(proc);
1175	break;
1176    default:
1177	Bip_Error(RANGE_ERROR);
1178    }
1179    pw = TG;
1180    Push_Struct_Frame(d_.quotient);
1181    Make_Atom(&pw[1], add_dict(wdid, 0));
1182    Make_Integer(&pw[2], DidArity(wdid));
1183    Request_Unify_Structure(vh, th, pw);
1184    Request_Unify_Atom(vm, tm, module);
1185    Return_Unify;
1186}
1187
1188
1189int
1190p_reset(void)
1191{
1192
1193    (void) ec_outfs(current_err_, "Aborting execution....\n");
1194    ec_flush(current_err_);
1195    ec_panic("reset/0 called",0);
1196}
1197
1198
1199static int
1200p_get_event_handler(value vn, type tn, value vh, type th, value vm, type tm)
1201{
1202    pri *proc;
1203    pword *prop, *pw;
1204    Prepare_Requests;
1205
1206    Error_If_Ref(tn);
1207    if (!IsRef(th)) {
1208	Check_Structure(th);
1209	if (vh.ptr->val.did != d_.quotient) {Bip_Error(TYPE_ERROR); }
1210	Check_Output_Atom_Or_Nil(vh.ptr[1].val, vh.ptr[1].tag);
1211	Check_Output_Integer(vh.ptr[2].tag);
1212    }
1213    Check_Output_Atom_Or_Nil(vm, tm);
1214    if (IsAtom(tn))
1215    {
1216      a_mutex_lock(&PropertyLock);
1217      prop = get_property(vn.did, EVENT_PROP);
1218      a_mutex_unlock(&PropertyLock);
1219      if (!prop) Fail_;
1220      proc = (pri *) prop->val.ptr;
1221    }
1222    else if (IsInteger(tn))
1223    {
1224      Check_Error_Number(vn,tn);
1225      proc = error_handler_[vn.nint];
1226      if(proc == (pri *) 0)
1227	proc = error_handler_[0];
1228    }
1229    else
1230    {
1231      Bip_Error(TYPE_ERROR)
1232    }
1233    pw = TG;
1234    Push_Struct_Frame(d_.quotient);
1235    Make_Atom(&pw[1], add_dict(PriDid(proc), 0));
1236    Make_Integer(&pw[2], DidArity(PriDid(proc)));
1237    Request_Unify_Structure(vh, th, pw);
1238    Request_Unify_Atom(vm, tm, PriHomeModule(proc));
1239    Return_Unify;
1240}
1241
1242
1243/* The following builtins use the global error variable ! */
1244
1245#undef Bip_Error
1246#define Bip_Error(N) Bip_Error_Fail(N)
1247
1248static int
1249p_valid_error(value vn, type tn)
1250{
1251    Check_Error_Number(vn,tn);
1252    Succeed_;
1253}
1254
1255/* undo redefiinition of Bip_Error() */
1256#undef Bip_Error
1257#define Bip_Error(N) return(N);
1258
1259
1260void
1261handlers_init(int flags)
1262{
1263    register int i;
1264
1265    first_delayed_ = next_delayed_ = 0;
1266
1267    d_event_ = in_dict("event",1);
1268    d_throw_ = in_dict("throw",1);
1269    d_defers_ = in_dict("defers",1);
1270    d_internal_ = in_dict("internal",0);
1271    kernel_tag_.kernel = ModuleTag(d_.kernel_sepia);
1272
1273    if (flags & INIT_SHARED)
1274    {
1275	ErrorHandler =
1276	    (pri **) hg_alloc(MAX_ERRORS * sizeof(pri *));
1277	DefaultErrorHandler =
1278	    (pri **) hg_alloc(MAX_ERRORS * sizeof(pri *));
1279	DefaultErrorHandler[0] = ErrorHandler[0] =
1280	    DidPtr(in_dict("boot_error", 2))->procedure;
1281	for(i = 1; i < MAX_ERRORS; i++)
1282	{
1283	    ErrorHandler[i] = (pri *) 0;
1284	    DefaultErrorHandler[i] = (pri *) 0;
1285	}
1286
1287	InterruptHandler =
1288	    (pri **) hg_alloc(NSIG * sizeof(pri *));
1289	InterruptHandlerFlags =
1290	    (int *) hg_alloc(NSIG * sizeof(int));
1291	InterruptName =
1292	    (dident *) hg_alloc(NSIG * sizeof(dident));
1293
1294	for(i = 0; i < NSIG; i++)
1295	{
1296	    InterruptHandler[i] = (pri *) 0;
1297	    InterruptHandlerFlags[i] = IH_UNCHANGED;
1298	    InterruptName[i] = D_UNKNOWN;
1299	}
1300
1301	/*
1302	 * Assign the prolog names to the signals
1303	 */
1304
1305	/* 0 is a pseudo-signal used for parallel abort */
1306	InterruptHandlerFlags[0] = IH_POST_EVENT;
1307
1308#ifdef SIGHUP
1309	InterruptName[SIGHUP] = in_dict("hup", 0);
1310#endif
1311	InterruptName[SIGINT] = in_dict("int", 0);
1312#ifdef SIGQUIT
1313	InterruptName[SIGQUIT] = in_dict("quit", 0);
1314#endif
1315	InterruptName[SIGILL] = in_dict("ill", 0);
1316#ifdef SIGTRAP
1317	InterruptName[SIGTRAP] = in_dict("trap", 0);
1318#endif
1319	InterruptName[SIGABRT] = in_dict("abrt", 0);
1320#ifdef SIGEMT
1321	InterruptName[SIGEMT] = in_dict("emt", 0);
1322#endif
1323	InterruptName[SIGFPE] = in_dict("fpe", 0);
1324#ifdef SIGKILL
1325	InterruptName[SIGKILL] = in_dict("kill", 0);
1326#endif
1327#ifdef SIGBUS
1328	InterruptName[SIGBUS] = in_dict("bus", 0);
1329#endif
1330	InterruptName[SIGSEGV] = in_dict("segv", 0);
1331#ifdef SIGSYS
1332	InterruptName[SIGSYS] = in_dict("sys", 0);
1333#endif
1334#ifdef SIGPIPE
1335	InterruptName[SIGPIPE] = in_dict("pipe", 0);
1336#endif
1337#ifdef SIGALRM
1338	ec_sigalrm = SIGALRM;
1339	InterruptName[SIGALRM] = in_dict("alrm", 0);
1340#else
1341	ec_sigalrm = 0;	/* will be properly assigned below */
1342#endif
1343	InterruptName[SIGTERM] = in_dict("term", 0);
1344#ifdef SIGUSR1
1345	InterruptName[SIGUSR1] = in_dict("usr1", 0);
1346#endif
1347#ifdef SIGUSR2
1348	InterruptName[SIGUSR2] = in_dict("usr2", 0);
1349#endif
1350#ifdef SIGCHLD
1351	InterruptName[SIGCHLD] = in_dict("chld", 0);
1352#endif
1353#ifdef SIGCLD
1354	InterruptName[SIGCLD] = in_dict("chld", 0);	/* old name for CHLD */
1355#endif
1356#ifdef SIGWINCH
1357	InterruptName[SIGWINCH] = in_dict("winch", 0);
1358#endif
1359#ifdef SIGURG
1360	InterruptName[SIGURG] = in_dict("urg", 0);
1361#endif
1362#ifdef SIGSUSP
1363	InterruptName[SIGSUSP] = in_dict("susp", 0);
1364#endif
1365#ifdef SIGSTOP
1366	InterruptName[SIGSTOP] = in_dict("stop", 0);
1367#endif
1368#ifdef SIGTSTP
1369	InterruptName[SIGTSTP] = in_dict("tstp", 0);
1370#endif
1371#ifdef SIGCONT
1372	InterruptName[SIGCONT] = in_dict("cont", 0);
1373#endif
1374#ifdef SIGTTIN
1375	InterruptName[SIGTTIN] = in_dict("ttin", 0);
1376#endif
1377#ifdef SIGTTOU
1378	InterruptName[SIGTTOU] = in_dict("ttou", 0);
1379#endif
1380#ifdef SIGVTALRM
1381	InterruptName[SIGVTALRM] = in_dict("vtalrm", 0);
1382#endif
1383#ifdef SIGPROF
1384	InterruptName[SIGPROF] = in_dict("prof", 0);
1385#endif
1386#ifdef SIGXCPU
1387	InterruptName[SIGXCPU] = in_dict("xcpu", 0);
1388#endif
1389#ifdef SIGXFSZ
1390	InterruptName[SIGXFSZ] = in_dict("xfsz", 0);
1391#endif
1392#ifdef SIGPWR
1393	InterruptName[SIGPWR] = in_dict("pwr", 0);
1394#endif
1395#ifdef SIGIOT
1396	InterruptName[SIGIOT] = in_dict("iot", 0);
1397#endif
1398#ifdef SIGWAITING
1399	InterruptName[SIGWAITING] = in_dict("waiting", 0);
1400#endif
1401#ifdef SIGLWP
1402	InterruptName[SIGLWP] = in_dict("lwp", 0);
1403#endif
1404#ifdef SIGPOLL
1405	InterruptName[SIGPOLL] = in_dict("poll", 0);
1406#endif
1407#ifdef SIGIO
1408	ec_sigio = SIGIO;
1409	InterruptName[SIGIO] = in_dict("io", 0);	/* after POLL */
1410#else
1411	ec_sigio = 0;		/* will be properly assigned below */
1412#endif
1413#ifdef SIGLOST
1414	InterruptName[SIGLOST] = in_dict("lost", 0);
1415#endif
1416#ifdef SIGQUIT
1417	InterruptName[SIGQUIT] = in_dict("quit", 0);
1418#endif
1419#ifdef SIGPHONE
1420	InterruptName[SIGPHONE] = in_dict("phone", 0);
1421#endif
1422
1423	/*
1424	 * If we didn't have SIGALRM defined, find a free number and fake it
1425	 * (use 14 of possible). We use it for our timer implementation.
1426	 */
1427#ifndef SIGALRM
1428	for(i = 14; i < NSIG; i++)
1429	{
1430	    if (InterruptName[i] == D_UNKNOWN)
1431	    {
1432		ec_sigalrm = i;
1433		InterruptName[i] = in_dict("alrm", 0);
1434		InterruptHandlerFlags[i] = IH_POST_EVENT;
1435		break;
1436	    }
1437	}
1438	if (!ec_sigalrm)
1439	    ec_panic("Couldn't find a pseudo-signal number for SIGALRM", "handlers_init()");
1440#endif
1441#ifndef SIGIO
1442	for(i = 1; i < NSIG; i++)
1443	{
1444	    if (InterruptName[i] == D_UNKNOWN)
1445	    {
1446		ec_sigio = i;
1447		InterruptName[i] = in_dict("io", 0);
1448		InterruptHandlerFlags[i] = IH_POST_EVENT;
1449		break;
1450	    }
1451	}
1452	if (!ec_sigio)
1453	    ec_panic("Couldn't find a pseudo-signal number for SIGIO", "handlers_init()");
1454#endif
1455    }
1456    if (flags & INIT_PRIVATE)	/* handler arrays already exist */
1457    {
1458	/* get a private copy of the array pointers */
1459	error_handler_ = ErrorHandler;
1460	default_error_handler_ = DefaultErrorHandler;
1461	interrupt_handler_ = InterruptHandler;
1462	interrupt_handler_flags_ = InterruptHandlerFlags;
1463	interrupt_name_ = InterruptName;
1464    }
1465    /*
1466     * event builtins
1467     */
1468    if (flags & INIT_SHARED)
1469    {
1470	(void) local_built_in(in_dict("post_events",1),
1471				p_post_events,			B_SAFE);
1472	(void) built_in(in_dict("pause",0),	p_pause,	B_SAFE);
1473	(void) built_in(in_dict("define_error", 2),
1474				p_define_error,		B_UNSAFE|U_SIMPLE);
1475	(void) built_in(in_dict("reset_error_handler", 1),
1476				p_reset_error_handler,		B_SAFE);
1477	(void) built_in(in_dict("reset_event_handler", 1),
1478				p_reset_error_handler,		B_SAFE);
1479
1480	(void) local_built_in(d_.reset,		p_reset,	B_SAFE);
1481	(void) exported_built_in(in_dict("set_error_handler_", 3),
1482				p_set_error_handler,		B_SAFE);
1483	(void) exported_built_in(in_dict("set_default_error_handler_", 3),
1484				p_set_default_error_handler,	B_SAFE);
1485	(void) exported_built_in(in_dict("set_interrupt_handler_body", 3),
1486				p_set_interrupt_handler,	B_SAFE);
1487	local_built_in(in_dict("get_event_handler", 3),
1488				p_get_event_handler,	B_UNSAFE|U_GROUND)
1489	    -> mode = BoundArg(2, NONVAR) | BoundArg(3, CONSTANT);
1490	built_in(in_dict("get_interrupt_handler", 3),
1491				p_get_interrupt_handler, B_UNSAFE|U_GROUND)
1492	    -> mode = BoundArg(2, NONVAR) | BoundArg(3, CONSTANT);
1493	(void) local_built_in(in_dict("valid_error", 1),
1494				p_valid_error,		B_SAFE);
1495	local_built_in(in_dict("interrupt_id_det", 2),
1496				p_interrupt_id_det,	B_UNSAFE|U_GROUND)
1497	    -> mode = BoundArg(1, NONVAR) | BoundArg(2, NONVAR);
1498    }
1499
1500
1501    /* This must be done before we install _break() as a handler */
1502    irq_lock_init(delayed_break);
1503
1504    if (flags & INIT_PROCESS)
1505    {
1506	Init_Block_Mask();
1507	Save_Sig_Mask(initial_sig_mask_);
1508    }
1509    else		/* on reset signals may need to be unblocked  */
1510    {
1511	Restore_Sig_Mask(initial_sig_mask_);
1512    }
1513    spurious = 0;	/* reset fatal signal nesting indicator */
1514
1515    errno = 0;		/*  we may have ignored some return values ... */
1516
1517    user_error = USER_ERROR;
1518}
1519
1520
1521