PreviousUpNext

15.4.1128  src/lib/std/src/nj/interprocess-signals-guts.pkg

## interprocess-signals-guts.pkg
#
# This is the internal view of the Signals package.

# Compiled by:
#     src/lib/std/src/standard-core.sublib


stipulate
    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.pkg
herein

    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.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext