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