## interprocess-signals-guts.pkg
#
# This is the internal view of the Signals package.
# Compiled by:
#
src/lib/std/src/standard-core.sublibstipulate
package bt = base_types; # base_types is from
src/lib/core/init/built-in.pkg package ci = mythryl_callable_c_library_interface; # mythryl_callable_c_library_interface is from
src/lib/std/src/unsafe/mythryl-callable-c-library-interface.pkg package ig = int_guts; # int_guts is from
src/lib/std/src/int-guts.pkg package sg = string_guts; # string_guts is from
src/lib/std/src/string-guts.pkg package rwv = rw_vector; # rw_vector is from
src/lib/std/src/rw-vector.pkgherein
package interprocess_signals_guts: api {
include api Interprocess_Signals; # Interprocess_Signals is from
src/lib/std/src/nj/interprocess-signals.api #
initialize_posix_interprocess_signal_handler_table: X -> Void;
clear_posix_interprocess_signal_handler_table: X -> Void;
reset_posix_interprocess_signal_handler_table: X -> Void;
}
{
# KEEP THIS CODE IN SYNC WITH signal_table__local[] in src/c/machine-dependent/interprocess-signals.c
Signal = SIGHUP # POSIX # 1 Hangup.
| SIGINT
# ANSI # 2 Interrupt.
| SIGQUIT
# POSIX # 3 Quit.
| SIGILL
# ANSI # 4 Illegal instruction
| SIGTRAP
# POSIX # 5 Trace trap
| SIGABRT
# ANSI # 6 Abort. On Linux == BSD4.2 SIGIOT.
| SIGBUS
# BSD 4.2 # 7 BUS error.
| SIGFPE
# ANSI # 8 Floating-point exception.
| SIGKILL
# POSIX # 9 Kill, unblockable.
| SIGUSR1
# POSIX # 10 User-defined signal 1.
| SIGSEGV
# ANSI # 11 Segmentation violation. (Typically due to use of an invalid C pointer.)
| SIGUSR2
# POSIX # 12 User-defined signal 2.
| SIGPIPE
# POSIX # 13 Broken pipe.
| SIGALRM
# POSIX # 14 Alarm. See also SIGVTALRM.
| SIGTERM
# POSIX # 15 Polite (catchable) request to terminate. http://en.wikipedia.org/wiki/SIGTERM
| SIGSTKFLT
# Linux # 16 Stack fault.
| SIGCHLD
# POSIX # 17 Child status has changed.
| SIGCONT
# POSIX # 18 Continue.
| SIGSTOP
# POSIX # 19 Stop, unblockable.
| SIGTSTP
# POSIX # 20 Keyboard stop.
| SIGTTIN
# POSIX # 21 Background read from TTY.
| SIGTTOU
# POSIX # 22 Backround write to TTY.
| SIGURG
# BSD 4.2 # 23 Urgent condition on socket.
| SIGXCPU
# BSD 4.2 # 24 CPU limit exceeded.
| SIGXFSZ
# BSD 4.2 # 25 File size limit exceeded.
| SIGVTALRM
# BSD 4.2 # 26 Alarm. See also SIGALRM.
| SIGPROF
# BSD 4.2 # 27 Profiling alarm clock.
| SIGWINCH
# BSD 4.3 # 28 Window size change.
| SIGIO
# BSD4.2 # 29 I/O now possible.
| SIGPWR
# SYS V # 30 Power failure restart.
| SIGSYS
# Linux # 31 Bad system call.
;
all_signals =
[ SIGHUP
, SIGINT
, SIGQUIT
, SIGILL
, SIGTRAP
, SIGABRT
, SIGBUS
, SIGFPE
, SIGKILL
, SIGUSR1
, SIGSEGV
, SIGUSR2
, SIGPIPE
, SIGALRM
, SIGTERM
, SIGSTKFLT
, SIGCHLD
, SIGCONT
, SIGSTOP
, SIGTSTP
, SIGTTIN
, SIGTTOU
, SIGURG
, SIGXCPU
, SIGXFSZ
, SIGVTALRM
, SIGPROF
, SIGWINCH
, SIGIO
, SIGPWR
, SIGSYS
];
fun signal_to_string SIGHUP => "SIGHUP";
signal_to_string SIGINT => "SIGINT";
signal_to_string SIGQUIT => "SIGQUIT";
signal_to_string SIGILL => "SIGILL";
signal_to_string SIGTRAP => "SIGTRAP";
signal_to_string SIGABRT => "SIGABRT";
signal_to_string SIGBUS => "SIGBUS";
signal_to_string SIGFPE => "SIGFPE";
signal_to_string SIGKILL => "SIGKILL";
signal_to_string SIGUSR1 => "SIGUSR1";
signal_to_string SIGSEGV => "SIGSEGV";
signal_to_string SIGUSR2 => "SIGUSR2";
signal_to_string SIGPIPE => "SIGPIPE";
signal_to_string SIGALRM => "SIGALRM";
signal_to_string SIGTERM => "SIGTERM";
signal_to_string SIGSTKFLT => "SIGSTKFLT";
signal_to_string SIGCHLD => "SIGCHLD";
signal_to_string SIGCONT => "SIGCONT";
signal_to_string SIGSTOP => "SIGSTOP";
signal_to_string SIGTSTP => "SIGTSTP";
signal_to_string SIGTTIN => "SIGTTIN";
signal_to_string SIGTTOU => "SIGTTOU";
signal_to_string SIGURG => "SIGURG";
signal_to_string SIGXCPU => "SIGXCPU";
signal_to_string SIGXFSZ => "SIGXFSZ";
signal_to_string SIGVTALRM => "SIGVTALRM";
signal_to_string SIGPROF => "SIGPROF";
signal_to_string SIGWINCH => "SIGWINCH";
signal_to_string SIGIO => "SIGIO";
signal_to_string SIGPWR => "SIGPWR";
signal_to_string SIGSYS => "SIGSYS";
end;
fun signal_to_int SIGHUP => 1;
signal_to_int SIGINT => 2;
signal_to_int SIGQUIT => 3;
signal_to_int SIGILL => 4;
signal_to_int SIGTRAP => 5;
signal_to_int SIGABRT => 6;
signal_to_int SIGBUS => 7;
signal_to_int SIGFPE => 8;
signal_to_int SIGKILL => 9;
signal_to_int SIGUSR1 => 10;
signal_to_int SIGSEGV => 11;
signal_to_int SIGUSR2 => 12;
signal_to_int SIGPIPE => 13;
signal_to_int SIGALRM => 14;
signal_to_int SIGTERM => 15;
signal_to_int SIGSTKFLT => 16;
signal_to_int SIGCHLD => 17;
signal_to_int SIGCONT => 18;
signal_to_int SIGSTOP => 19;
signal_to_int SIGTSTP => 20;
signal_to_int SIGTTIN => 21;
signal_to_int SIGTTOU => 22;
signal_to_int SIGURG => 23;
signal_to_int SIGXCPU => 24;
signal_to_int SIGXFSZ => 25;
signal_to_int SIGVTALRM => 26;
signal_to_int SIGPROF => 27;
signal_to_int SIGWINCH => 28;
signal_to_int SIGIO => 29;
signal_to_int SIGPWR => 30;
signal_to_int SIGSYS => 31;
end;
max_signal = 31;
signal_count = 31;
fun int_to_signal 1 => SIGHUP ;
int_to_signal 2 => SIGINT ;
int_to_signal 3 => SIGQUIT ;
int_to_signal 4 => SIGILL ;
int_to_signal 5 => SIGTRAP ;
int_to_signal 6 => SIGABRT ;
int_to_signal 7 => SIGBUS ;
int_to_signal 8 => SIGFPE ;
int_to_signal 9 => SIGKILL ;
int_to_signal 10 => SIGUSR1 ;
int_to_signal 11 => SIGSEGV ;
int_to_signal 12 => SIGUSR2 ;
int_to_signal 13 => SIGPIPE ;
int_to_signal 14 => SIGALRM ;
int_to_signal 15 => SIGTERM ;
int_to_signal 16 => SIGSTKFLT;
int_to_signal 17 => SIGCHLD ;
int_to_signal 18 => SIGCONT ;
int_to_signal 19 => SIGSTOP ;
int_to_signal 20 => SIGTSTP ;
int_to_signal 21 => SIGTTIN ;
int_to_signal 22 => SIGTTOU ;
int_to_signal 23 => SIGURG ;
int_to_signal 24 => SIGXCPU ;
int_to_signal 25 => SIGXFSZ ;
int_to_signal 26 => SIGVTALRM;
int_to_signal 27 => SIGPROF ;
int_to_signal 28 => SIGWINCH ;
int_to_signal 29 => SIGIO ;
int_to_signal 30 => SIGPWR ;
int_to_signal 31 => SIGSYS ;
int_to_signal _ => raise exception DIE "No such signal";
end;
Signal_Action # WARNING! This definition must be kept synced to that in src/c/h/system-dependent-signal-stuff.h
#
= IGNORE
| DEFAULT
| HANDLER (Signal, Int, bt::Fate( Void ))
->
bt::Fate( Void )
;
fun cfun fun_name
=
ci::find_c_function { lib_name => "signal", fun_name }; # signal lives in src/c/lib/signal/
#
###############################################################
# The functions in this package are specific to the calling
# posix thread -- for example pause() exists specifically to
# pause the calling thread -- so our usual mechanism of
# executing syscalls in a separate hostthread makes no sense here.
#
# Consequently I'm not taking the time and effort to switch it
# over from using find_c_function() to using find_c_function'().
# -- 2012-04-21 CrT
Signal_Info
=
{ signal: Signal,
mask: Int,
signal_action: Signal_Action
};
signal_table = REF (rwv::from_list []): Ref( rwv::Rw_Vector( Null_Or( Signal_Info ) ) ); # Set by reset_posix_interprocess_signal_handler_table() via reset_list()
# debug def in src/c/lib/heap/debug.c
debug = ci::find_c_function { lib_name => "heap", fun_name => "debug" } : String -> Void; # Print a string to the debug stream.
#
###############################################################
# This call should specifically be executed immediately and
# in the current posix thread so our usual mechanism of
# executing syscalls in a separate hostthread makes no sense here.
#
# Consequently I'm not taking the time and effort to switch it
# over from using find_c_function() to using find_c_function'().
# -- 2012-04-21 CrT
fun set_info (signal, info)
=
rwv::set (*signal_table, (signal_to_int signal), THE info);
fun get_info (signal: Signal)
=
{ sig = signal_to_int signal;
#
case (rwv::get (*signal_table, sig))
#
THE info => info;
#
NULL => {
debug (sg::cat [ "\n*** Internal error: No signal_table entry for signal ",
signal_to_string signal,
" ***\n"
]
);
raise exception null_or::NULL_OR;
};
esac;
};
fun reset_list ()
=
signal_table := rwv::make_rw_vector(max_signal + 1, NULL);
# The states are defined as:
#
signal_state_ignore = 0;
signal_state_default = 1;
signal_state_enabled = 2;
# These run-time functions deal with the
# state of a signal in the system:
#
get_signal_state' = cfun "get_signal_state" : Int -> Int ; # get_signal_state def in src/c/lib/signal/get-signal-state.c
set_signal_state' = cfun "set_signal_state" : (Int /*signal*/, Int /*state*/) -> Void; # set_signal_state def in src/c/lib/signal/set-signal-state.c
fun get_signal_state signal
=
get_signal_state' (signal_to_int signal);
fun set_signal_state (signal, state)
=
set_signal_state' ((signal_to_int signal), state);
set_log_if_on = cfun "set_log_if_on" : Bool -> Void; # set_log_if_on def in src/c/lib/signal/set-log-if-on.c
# Re/sets the log_if_on var in src/c/main/error-reporting.c
# which dis/ables logging by the C-level log_if() fn.
# See also: log::debugging in
src/lib/std/src/log.pkg # Following fn gets scheduled to be called
# at::SHUTDOWN_PHASE_7_CLEAR_POSIX_INTERPROCESS_SIGNAL_HANDLER_TABLE
# in
src/lib/std/src/nj/interprocess-signals.pkg #
fun clear_posix_interprocess_signal_handler_table _ # Clear the posix-signal handler-table:
=
rwv::map_in_place (\\ _ = NULL) *signal_table; # Set all slots to NULL.
# Following fn gets scheduled to be called
# at::STARTUP_PHASE_6_INITIALIZE_POSIX_INTERPROCESS_SIGNAL_HANDLER_TABLE
# in
src/lib/std/src/nj/interprocess-signals.pkg # It is also called in wrap_for_export() in
src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg # and at linktime in this file.
# #
fun initialize_posix_interprocess_signal_handler_table _ # Initialize the signal table to the inherited process dictionary
=
{
reset_list ();
#
apply initialize_posix_signal all_signals;
}
where
fun initialize_posix_signal signal
=
{ state = get_signal_state signal;
#
fun set_state st
=
set_info (signal, { signal_action=>st, mask=>0, signal } );
if (state == signal_state_ignore) set_state IGNORE;
elif (state == signal_state_default) set_state DEFAULT;
else /* state = enabledSigState */ raise exception DIE "unexpected signal handler";
fi;
};
end;
# Following fn gets scheduled to be called
# at::STARTUP_PHASE_7_RESET_POSIX_INTERPROCESS_SIGNAL_HANDLER_TABLE
# in
src/lib/std/src/nj/interprocess-signals.pkg # Reset the signal dictionary to agree with the signal table
#
fun reset_posix_interprocess_signal_handler_table _
=
{ old_sig_table = *signal_table;
#
fun copy signal
=
{ sig = signal_to_int signal;
#
case (rwv::get (old_sig_table, sig))
#
THE info
=>
{ set_info (signal, info);
#
case info.signal_action
#
IGNORE => set_signal_state (signal, signal_state_ignore);
DEFAULT => set_signal_state (signal, signal_state_default);
HANDLER _ => set_signal_state (signal, signal_state_enabled);
esac;
};
NULL => ();
esac
except
_ = ();
};
# NOTE: we should probably notify the user that old signal handlers
# are being lost, but there is no good way to do this right now.
reset_list ();
list::apply copy all_signals;
};
# Signal masking:
#
Signal_Mask
= MASK_ALL
| MASK List( Signal )
;
stipulate
# Run-time system API:
# NULL -- empty mask
# THE[] -- mask all signals
# THE l -- mask the signals in l
get_signal_mask' = cfun "get_signal_mask": Void -> Null_Or( List(Int) ) ; # get_signal_mask is from src/c/lib/signal/get-signal-mask.c
set_signal_mask' = cfun "set_signal_mask": Null_Or( List(Int) ) -> Void; # set_signal_mask is from src/c/lib/signal/setsigmask.c
fun get_signal_mask ()
=
case (get_signal_mask' ())
#
NULL => NULL;
THE list => THE (map int_to_signal list);
esac;
fun set_signal_mask mask
=
case mask
#
NULL => set_signal_mask' NULL;
THE list => set_signal_mask' (THE (map signal_to_int list));
esac;
# Sort a list of signals, dropping duplicates:
#
fun sort_signals MASK_ALL
=>
all_signals;
sort_signals (MASK l)
=>
list::fold_forward insert [] l
where
fun insert (signal: Signal, []) # A simple insertion sort to eliminate duplicates.
=>
[ signal ];
insert (id, id' ! rest)
=>
if (signal_to_int id < signal_to_int id')
#
id ! id' ! rest;
else
if (id == id') id' ! rest;
else id' ! insert (id, rest);
fi;
fi;
end;
end;
end;
# Map a list of signals into the format
# expected by the runtime system API:
#
fun make_mask (masked, n_masked)
=
if (n_masked == 0 ) NULL;
elif (n_masked == signal_count) THE [];
else THE masked;
fi;
#
fun is_masked (signal: Signal) # Is the signal masked?
=
(get_info signal).mask > 0;
herein
fun mask_signals mask
=
compute_new_mask (signals, all_signals, [], 0, 0)
where
#
signals = sort_signals mask;
# Function for incrementing a signal mask.
fun increment_mask (signal: Signal)
=
{
(get_info signal)
->
{ signal_action, mask, signal };
set_info (signal, { signal_action, mask=>mask+1, signal } );
};
# Scan over the sorted mask list and the list of all signals.
#
# Record which signals are masked
# and how many new signals are masked.
fun compute_new_mask ([], _, _, _, 0)
=>
list::apply increment_mask signals; # No signals are masked, so we only update the local state.
compute_new_mask ([], [], masked, n_masked, _)
=>
{ # NOTE: we must update the OS's view of the mask before we change
# our own to avoid a race condition!
set_signal_mask (make_mask (masked, n_masked));
list::apply increment_mask signals;
};
compute_new_mask ([], s2 ! r2, masked, n_masked, n_new)
=>
if (is_masked s2) compute_new_mask ([], r2, s2 ! masked, n_masked+1, n_new);
else compute_new_mask ([], r2, masked, n_masked, n_new);
fi;
compute_new_mask ( id1 ! r1,
id2 ! r2,
masked,
n_masked,
n_new
)
=>
if (id1 == id2)
#
n_new = if (is_masked id1) n_new;
else n_new + 1;
fi;
compute_new_mask (r1, r2, id1 ! masked, n_masked+1, n_new);
else
if (is_masked id2) compute_new_mask (id1 ! r1, r2, id2 ! masked, n_masked+1, n_new);
else compute_new_mask (id1 ! r1, r2, masked, n_masked, n_new);
fi;
fi;
compute_new_mask (_ ! _, [], _, _, _)
=>
raise exception DIE "compute_new_mask: bogus mask (impossible)";
end;
end;
fun unmask_signals mask
=
compute_new_mask (signals, all_signals, [], 0, 0)
where
#
signals = sort_signals mask;
# Function for decrementing a signal mask.
#
fun decrement_mask (signal: Signal)
=
{
(get_info signal)
->
{ signal_action, mask, signal };
if (mask > 0)
#
set_info (signal, { signal_action, mask=>mask - 1, signal } );
fi;
};
# Return TRUE if decrementing this
# signal's count will unmask it.
#
fun is_unmasked (signal: Signal)
=
(get_info signal).mask <= 1;
# Scan over the sorted mask list
# and the list of all signals.
#
# Record which signals are masked and
# how many new signals are unmasked:
#
fun compute_new_mask ([], _, _, _, 0)
=>
list::apply decrement_mask signals; # No signals are unmasked, so we only update the local state.
compute_new_mask ([], [], masked, n_masked, _)
=>
{ # NB: To avoid a race condition we must
# update our local view of the mask
# before we change the OS's view.
list::apply decrement_mask signals;
set_signal_mask (make_mask (masked, n_masked));
};
compute_new_mask ([], s2 ! r2, masked, n_masked, n_new)
=>
if (is_masked s2) compute_new_mask ([], r2, s2 ! masked, n_masked+1, n_new);
else compute_new_mask ([], r2, masked, n_masked, n_new);
fi;
compute_new_mask ( id1 ! r1,
id2 ! r2,
masked,
n_masked,
n_new
)
=>
if (id1 == id2)
#
if (is_unmasked id1) compute_new_mask ( r1, r2, masked, n_masked, n_new+1);
else compute_new_mask ( r1, r2, id1 ! masked, n_masked+1, n_new ); # still masked
fi;
else
if (is_masked id2) compute_new_mask (id1 ! r1, r2, id2 ! masked, n_masked+1, n_new );
else compute_new_mask (id1 ! r1, r2, masked, n_masked, n_new );
fi;
fi;
compute_new_mask (_ ! _, [], _, _, _)
=>
raise exception DIE "unmaskSignals: bogus mask (impossible)";
end;
end;
fun masked_signals () # Return the set of masked signals.
=
case (get_signal_mask ())
#
NULL => MASK [];
THE [] => MASK_ALL;
THE l => MASK l;
esac;
end;
# Set the handler for a signal,
# returning the previous action:
#
fun set_signal_handler (signal, signal_action)
=
{ mask_signals MASK_ALL;
#
(get_info signal)
->
{ signal_action => old_action, mask, ... };
case (signal_action, old_action)
#
(IGNORE, IGNORE) => ();
(DEFAULT, DEFAULT) => ();
(HANDLER _, HANDLER _)
=>
set_info (signal, { signal_action, mask, signal } );
(IGNORE, _)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_ignore);
};
(DEFAULT, _)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_default);
};
(HANDLER _, _)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_enabled);
};
esac;
unmask_signals MASK_ALL;
old_action;
};
# If a signal is not being ignored, then set the handler.
#
# This returns the previous handler (if IGNORE, then
# the current handler is still IGNORE).
fun override_signal_handler (signal, signal_action) # override_signal_handler is called in
src/lib/core/internal/make-mythryld-executable.pkg = # override_signal_handler is called in
src/lib/std/safely.pkg { mask_signals MASK_ALL;
#
(get_info signal)
->
{ signal_action => old_action, mask, ... };
case (old_action, signal_action)
#
(IGNORE, _) => ();
(DEFAULT, DEFAULT) => ();
(HANDLER _, HANDLER _)
=>
set_info(signal, { signal_action, mask, signal } );
(_, IGNORE)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_ignore);
};
(_, DEFAULT)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_default);
};
(_, HANDLER _)
=>
{ set_info (signal, { signal_action, mask, signal } );
#
set_signal_state (signal, signal_state_enabled);
};
esac;
unmask_signals MASK_ALL;
old_action;
};
# Get the current action for the given signal:
#
fun get_signal_handler (signal: Signal)
=
(get_info signal).signal_action;
# Sleep until the next signal.
#
# If called when signals are masked,
# then signals will still be masked
# when pause returns.
#
pause = cfun "pause" : Void -> Void; # pause def in src/c/lib/signal/pause.c
signal_is_supported_by_host_os' = cfun "signal_is_supported_by_host_os" : Int -> Bool; # signal_is_supported_by_host_os def in src/c/lib/signal/signal-is-supported-by-host-os.c
fun signal_is_supported_by_host_os signal
=
signal_is_supported_by_host_os' (signal_to_int signal);
# These two are really only intended for use in
src/lib/std/src/nj/interprocess-signals-unit-test.pkg #
ascii_signal_name_to_portable_signal_id = cfun "ascii_signal_name_to_portable_signal_id": String -> Int; # ascii_signal_name_to_portable_signal_id is from src/c/lib/signal/ascii-signal-name-to-portable-signal-id.c
maximum_valid_portable_signal_id = cfun "maximum_valid_portable_signal_id": Void -> Int; # maximum_valid_portable_signal_id is from src/c/lib/signal/maximum-valid-portable-signal-id.c
# Here is the Mythryl handler that gets
# invoked by the C run-time system. The
# sequence of events is:
#
# o Posix signal gets initially noted by c_signal_handler in
#
# src/c/machine-dependent/interprocess-signals.c
#
# which merely increments the seen_count field for that signal.
#
# o This flag eventually gets noticed in
#
# src/c/main/run-mythryl-code-and-runtime-eventloop.c
#
# which sets the saved Mythryl state to "return" to us.
#
# The signal handler function should return promptly:
#
# src/c/main/run-mythryl-code-and-runtime-eventloop.c
#
# has done
#
# hostthread->mythryl_handler_for_interprocess_signal_is_running = TRUE;
#
# which will inhibit any further signal handling until we return and the
# REQUEST_RETURN_FROM_SIGNAL_HANDLER clause does the matching
#
# hostthread->mythryl_handler_for_interprocess_signal_is_running = FALSE;
#
# If our signal handler fn returns 'resume_fate', processing will pick up
# where it was interrupted by the call to the signal handler.
#
# Alternatively it may return any other fate desired, in
# which case processing will instead resume with it.
#
fun root_mythryl_handler_for_interprocess_signals
(
which_signal: Int, # SIGALRM or such -- ID number of POSIX signal being handled. (This is the portable signal id, not the host-OS signal id.)
count: Int, # Number of times c_signal_handler has seen this signal since we last handled it here.
resume_fate # Fate to resume once signal handling is complete.
)
=
case (rwv::get (*signal_table, which_signal))
#
THE { signal_action => HANDLER handler, mask=>0, signal }
=>
handler (signal, count, resume_fate);
info => { signal_action
=
case info
#
NULL => "NULL";
THE { signal_action => IGNORE, ... } => "IGNORE";
THE { signal_action => DEFAULT, ... } => "DEFAULT";
THE { signal_action => HANDLER _, mask, ... }
=>
cat ["HANDLER (mask=", ig::to_string mask, "!=0)"];
esac;
raise exception DIE (cat ["inconsistent state ", signal_action, " for signal ", ig::to_string which_signal]);
};
esac;
# Install our root posix-signal handler:
/* */ my _ =
runtime::posix_interprocess_signal_handler_refcell__global
:=
root_mythryl_handler_for_interprocess_signals;
# Initialize the signal list and table:
/* */ my _ =
initialize_posix_interprocess_signal_handler_table ();
}; # package interprocess_signals_guts
end; # stipulate
## COPYRIGHT (c) 1995 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.