lib: move pseudo-toplevel methods from Object
[nit.git] / lib / signals.nit
index 91015da..002ff89 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Module to manage standard C signals
+# ANSI C signal handling
+#
+# Common usage imply 5 steps:
+#
+# 1. Implement the `SignalHandler` interface
+# 2. `redef receive_signal_unsafe` to handle `sigsegv`
+# 3. `redef receive_signal` to handle other signals safely
+# 4, Notify what signals to handle with `handle_signal`
+# 5. If using the safe handler method, routinely call `check_signals`
+#
+# Usage example:
+#
+# ~~~~
+# class MyReceiver
+#      super SignalHandler
+#
+#      redef fun receive_signal(signal)
+#      do
+#              print "received safely {signal}"
+#              if signal == sigalarm then print "Alarm!"
+#      end
+#      redef fun receive_signal_unsafe( signal ) do print "received unsafely {signal}"
+# end
+#
+# var r = new MyReceiver
+#
+# # Handle `sigsegv` signal unsafely (the only way for this one)
+# r.handle_signal(sigsegv, false)
+#
+# # Handle `sigint` and `sigalarm` safely
+# r.handle_signal(sigint, true)
+# r.handle_signal(sigalarm, true)
+#
+# # Ask system to receive a `sigalarm` signal in 1 second
+# set_alarm(1)
+#
+# loop
+#      # Check signals and callback `receive_signal`
+#      var hit = check_signals
+#
+#      if hit then break
+# end
+# ~~~~
 module signals
 
 `{
@@ -22,6 +64,11 @@ module signals
        #define _POSIX_SOURCE 1
        #include <signal.h>
        #include <stdio.h>
+       #include <unistd.h>
+
+       /*
+       */
+       void (*nit_SignalHandler_receive_signal)(void* self, long signal);
 
        /*
                Structure to manage each possible signals
@@ -30,9 +77,9 @@ module signals
        */
        struct nit_signals_ent {
                char raised; /* !=0 if has been raised */
-               SignalHandler handler; /* instance to receive call */
+               void* handler; /* instance to receive call */
                char safely; /* if !=0 then manage signal safely, otherwise react when raised */
-       } nit_signals_list[32] = {0x0};
+       } nit_signals_list[32] = {{0}};
 
        /* Receiver to all signals
                If unsafe, it calls directly the Nit receiver,
@@ -45,7 +92,7 @@ module signals
                        if (nit_signals_list[sig].safely) {
                                nit_signals_list[sig].raised += 1;
                        } else {
-                               SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
+                               nit_SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
                        }
                }
        }
@@ -61,16 +108,15 @@ interface SignalHandler
        #
        #     class MyReceiver
        #         super SignalHandler
-       #     
+       #
        #         redef fun receive_signal(signal) do print "received safely {signal}"
        #     end
-       #     
+       #
        #     var r = new MyReceiver
        #     r.handle_signal(sigint, true) # will call back when "check_signals" is called
        #     # ...
        #     check_signals # if a signal was received, it will invoke `r.receive_signal`
-       fun receive_signal(signal: Int) `{
-       `}
+       fun receive_signal(signal: Int) do end
 
        # Called immediatly on receiving an unsafe signal (should be redefed by subclasses)
        #
@@ -82,23 +128,20 @@ interface SignalHandler
        #
        #     class MyReceiver
        #         super SignalHandler
-       #     
+       #
        #         redef fun receive_signal_unsafe(signal) do print "received unsafely {signal}"
        #     end
-       #     
+       #
        #     var r = new MyReceiver
        #     r.handle_signal(sigsegv, false) # `r.receive_signal_unsafe` will be invoked on sigsegv
-       fun receive_signal_unsafe(signal: Int) `{
-       `}
+       fun receive_signal_unsafe(signal: Int) do end
 
        # Set the receiver as the handler of the signal
        #
        # If `safely`, receiver will be called when `check_signals` in invoked
        # otherwise the receiver is invoked when the signal is raised, it may
        # crash the Nit system but is unavoidable for unstoppable signals.
-       fun handle_signal(signal: Int, safely: Bool) import
-               receive_signal `{
-               SignalHandler last_handler;
+       fun handle_signal(signal: Int, safely: Bool) import receive_signal `{
                if (signal < 32 && signal >=0) {
                        struct sigaction act;
                        sigemptyset(&act.sa_mask);
@@ -107,20 +150,26 @@ interface SignalHandler
 
                        sigaction(signal, &act, NULL);
 
-                       last_handler = nit_signals_list[signal].handler;
+               #ifdef SignalHandler_decr_ref
+                       SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
                        if (last_handler != NULL)
                                SignalHandler_decr_ref(last_handler);
+               #endif
+
+                       nit_signals_list[signal].handler = self;
 
-                       nit_signals_list[signal].handler = recv;
-                       SignalHandler_incr_ref(recv);
+               #ifdef SignalHandler_incr_ref
+                       SignalHandler_incr_ref(self);
+               #endif
 
                        nit_signals_list[signal].safely = safely;
+
+                       nit_SignalHandler_receive_signal = SignalHandler_receive_signal;
                }
        `}
 
        # Set to ignore the signal
        fun ignore_signal(signal: Int) `{
-               SignalHandler last_handler;
                if (signal < 32 && signal >=0) {
                        struct sigaction act;
                        sigemptyset(&act.sa_mask);
@@ -128,15 +177,16 @@ interface SignalHandler
                        act.sa_handler = SIG_IGN;
                        sigaction(signal, &act, NULL);
 
-                       last_handler = nit_signals_list[signal].handler;
+               #ifdef SignalHandler_decr_ref
+                       SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
                        if (last_handler != NULL)
                                SignalHandler_decr_ref(last_handler);
+               #endif
                }
        `}
 
        # Set default action for the signal
        fun default_signal(signal: Int) `{
-               SignalHandler last_handler;
                if (signal < 32 && signal >=0) {
                        struct sigaction act;
                        sigemptyset(&act.sa_mask);
@@ -144,36 +194,36 @@ interface SignalHandler
                        act.sa_handler = SIG_DFL;
                        sigaction(signal, &act, NULL);
 
-                       last_handler = nit_signals_list[signal].handler;
+               #ifdef SignalHandler_decr_ref
+                       SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
                        if (last_handler != NULL)
                                SignalHandler_decr_ref(last_handler);
+               #endif
                }
        `}
 end
 
-redef interface Object
-
-       # Check signals for safe operation
-       # will callback receiver of raised signals
-       # can callback any instance of SignalHandler, not just this one
-       protected fun check_signals: Bool is extern import SignalHandler.receive_signal `{
-               int sig;
-               int raised_something = 0;
-
-               for (sig = 0; sig < 32; sig ++)
-                       if (nit_signals_list[sig].raised) {
-                               nit_signals_list[sig].raised = 0;
-                               raised_something = 1;
-                               SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
-                       }
+# Check signals for safe operation
+# will callback receiver of raised signals
+# can callback any instance of SignalHandler, not just this one
+fun check_signals: Bool is extern import SignalHandler.receive_signal `{
+       int sig;
+       int raised_something = 0;
+
+       for (sig = 0; sig < 32; sig ++)
+               if (nit_signals_list[sig].raised) {
+                       nit_signals_list[sig].raised = 0;
+                       raised_something = 1;
+                       SignalHandler handler = (SignalHandler)nit_signals_list[sig].handler;
+                       SignalHandler_receive_signal(handler, sig);
+               }
 
-               return raised_something;
-       `}
+       return raised_something;
+`}
 
-       # Set alarm signal
-       # can callback any instance of SignalHandler, not just this one
-       protected fun set_alarm(sec: Int) `{ alarm(sec); `}
-end
+# Set alarm signal
+# can callback any instance of SignalHandler, not just this one
+fun set_alarm(sec: Int) `{ alarm(sec); `}
 
 redef class Process
        # Send a signal to the process
@@ -181,88 +231,88 @@ redef class Process
 
        # Send the kill signal to the process
        fun kill do signal(sigkill)
-       
+
        # Native implementation of `signal`
        private fun native_kill(pid, signal: Int) `{ kill(pid, signal); `}
 end
 
 # Hang up detected on controlling terminal or death of controlling process
-protected fun sighup: Int do return 1
+fun sighup: Int do return 1
 
 # Issued if the user sends an interrupt signal
-protected fun sigint: Int do return 2
+fun sigint: Int do return 2
 
 # Issued if the user sends a quit signal
-protected fun sigquit: Int do return 3
+fun sigquit: Int do return 3
 
 # Issued if the user attempts to execute an illegal, malformed, unknown, or privileged instruction
-protected fun sigill: Int do return 4
+fun sigill: Int do return 4
 
 # Issued when an exception occurs: a condition that a debugger has requested to be informed of
-protected fun sigtrap: Int do return 5
+fun sigtrap: Int do return 5
 
 # This signal is sent to a process to tell it to abort, i. e. to terminate
-protected fun sigabrt: Int do return 6
+fun sigabrt: Int do return 6
 
 # This signal is sent to a process when it causes a bus error
-protected fun sigbus: Int do return 7
+fun sigbus: Int do return 7
 
 # Issued if an illegal mathematical operation is attempted
-protected fun sigfpe: Int do return 8
+fun sigfpe: Int do return 8
 
 # If a process gets this signal it must quit immediately and will not perform any clean-up operations
-protected fun sigkill: Int do return 9
+fun sigkill: Int do return 9
 
 # Sent to a process to indicate user-defined conditions
-protected fun sigusr1: Int do return 10
+fun sigusr1: Int do return 10
 
 # Sent to a process when it makes an invalid virtual memory reference, or segmentation fault
-protected fun sigsegv: Int do return 11
+fun sigsegv: Int do return 11
 
 # Sent to a process to indicate user-defined conditions
-protected fun sigusr2: Int do return 12
+fun sigusr2: Int do return 12
 
 # Sent to a process when it attempts to write to a pipe without a process connected to the other end
-protected fun sigpipe: Int do return 13
+fun sigpipe: Int do return 13
 
 # Alarm Clock signal
-protected fun sigalarm: Int do return 14
+fun sigalarm: Int do return 14
 
 # Software termination signal
-protected fun sigterm: Int do return 15
+fun sigterm: Int do return 15
 
 # Sent to a process when a child process terminates or is interrupted
-protected fun sigchild: Int do return 17
+fun sigchild: Int do return 17
 
 # Tell the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal
-protected fun sigcont: Int do return 18
+fun sigcont: Int do return 18
 
 # Tell the operating system to stop a process
-protected fun sigstop: Int do return 19
+fun sigstop: Int do return 19
 
 # Sent to a process by its terminal to request it to stop temporarily
-protected fun sigtstp: Int do return 20
+fun sigtstp: Int do return 20
 
 # Sent to a process when a socket has urgent or out-of-band data available to read
-protected fun sigurg: Int do return 23
+fun sigurg: Int do return 23
 
 # Sent to a process when it has used the CPU for a duration that exceeds a user-settable value
-protected fun sigxcpu: Int do return 24
+fun sigxcpu: Int do return 24
 
 # Sent to a process when it grows a file larger than the maximum allowed size
-protected fun sigxfsz: Int do return 25
+fun sigxfsz: Int do return 25
 
 # Virtual timer expired
-protected fun sigvtalrm: Int do return 26
+fun sigvtalrm: Int do return 26
 
 # Profiling timer expired
-protected fun sigprof: Int do return 27
+fun sigprof: Int do return 27
 
-# Sent to a process when its controlling terminal changes its window size 
-protected fun sigwinch: Int do return 28
+# Sent to a process when its controlling terminal changes its window size
+fun sigwinch: Int do return 28
 
 # Sent to a process when the system experiences a power failure
-protected fun sigpwr: Int do return 30
+fun sigpwr: Int do return 30
 
 # Sent to a process when it passes a bad argument to a system call
-protected fun sigsys: Int do return 31
+fun sigsys: Int do return 31