1(*
2    Title:      Signal structure and signature.
3    Author:     David Matthews
4    Copyright   David Matthews 2000, 2008, 2019-20
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10    
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15    
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19*)
20
21(**
22Although the `Posix` structure in the Standard Basis Library provides functions
23which send signals to a process there is no standard method of handling signals. The
24`Signal` structure has been added to Poly/ML to allow signals to be blocked or
25handled.
26**)
27signature SIGNAL =
28sig
29    datatype sig_handle = SIG_DFL | SIG_IGN | SIG_HANDLE of int->unit
30    val signal: int * sig_handle -> sig_handle
31end;
32
33structure Signal: SIGNAL =
34struct
35    datatype sig_handle = SIG_DFL | SIG_IGN | SIG_HANDLE of int->unit
36    local
37        val setHandler = RunCall.rtsCallFull2 "PolySetSignalHandler"
38    in
39        fun signal(s, cmd) =
40        let
41            val c =
42                case cmd of
43                    SIG_DFL => 0
44                |   SIG_IGN => 1
45                |   SIG_HANDLE f => RunCall.unsafeCast f
46        in
47            case setHandler(s, c) of
48                0 => SIG_DFL
49            |   1 => SIG_IGN
50            |   f => SIG_HANDLE(RunCall.unsafeCast f)
51        end
52    end
53    
54    local
55        datatype sigHandle = SigHandle of (int->unit) * int | WeakMarker
56        val waitForSig = RunCall.rtsCallFull0 "PolyWaitForSignal"
57        open Thread
58
59        fun sigThread(): unit =
60        let
61            (* This call to the RTS returns either a pair of a signal
62               and a handler or a flag indicating that some wek reference
63               has been set to NONE.  These aren't logically related but
64               it's convenient to use a single thread for both. *)
65            val nextSig: sigHandle = waitForSig()
66
67            (* When we get a WeakMarker message we need to broadcast
68               on this condition variable. *)
69            fun broadCastWeak haveLock () =
70            (
71                if haveLock then () else Mutex.lock Weak.weakLock;
72                ConditionVar.broadcast Weak.weakSignal;
73                Mutex.unlock Weak.weakLock
74            )
75                
76        in
77            case nextSig of
78                SigHandle (handler, signal) => (handler signal handle _ => ())
79            |   WeakMarker =>
80                    (* If the lock is free we can do the broadcast now but
81                       to avoid waiting and being unable to handle any signals
82                       we fork off a thread if we can't. *)
83                    if Mutex.trylock Weak.weakLock
84                    then broadCastWeak true ()
85                    else (Thread.fork(broadCastWeak false, []); ());
86            sigThread() (* Forever. *)
87        end
88        
89        fun forkThread() =
90            (Thread.fork(sigThread, []); ()) handle Thread _ => print "Unable to create signal thread\n"
91
92    in
93        (* Run this thread now and also start one each time we start up. *)
94        val _ = forkThread()
95        val _ = LibrarySupport.addOnEntry forkThread
96    end
97end;
98(**
99The `Signal.signal` function takes as its arguments a signal number and an
100action and returns the previous action. The action may be `SIG_DFL`,
101indicating the default action, `SIG_IGN`, indicating that the signal should be
102ignored (blocked) or `SIG_HANDLE`, which allows a handler function to be installed.
103
104Signals are represented as integers using the normal Unix signal numbering. In
105the Unix implementations of Poly/ML the type `Posix.Signal.signal` is the same as `int`
106so the constants from `Posix.Signal` can be used as arguments to `Signal.signal`.
107
108The default action depends on the signal. For some signals it is to ignore the
109signal, for others the process is killed. See the signal man page in Unix for a list
110of the default actions.
111
112A handler function installed using `SIG_HANDLE` is run as a separate thread
113some time after a signal arrives. 
114
115Some signals are used internally by Poly/ML.  In particular `SIGVTALRM` is used
116by the profiling mechanism.
117
118The Signal structure is provided in the Windows implementation but only the 
119console interrupt signal (2) has effect.
120
121**)
122