1 (* Copyright (C
) 2015 Matthew Fluet
.
2 * Copyright (C
) 1999-2006, 2008 Henry Cejtin
, Matthew Fluet
, Suresh
3 * Jagannathan
, and Stephen Weeks
.
4 * Copyright (C
) 1997-2000 NEC Research Institute
.
6 * MLton is released under a BSD
-style license
.
7 * See the file MLton
-LICENSE for details
.
10 structure MLtonSignal
: MLTON_SIGNAL_EXTRA
=
14 structure Prim
= PrimitiveFFI
.Posix
.Signal
15 structure Error
= PosixError
16 structure SysCall
= Error
.SysCall
17 val restart
= SysCall
.restartFlag
32 type pre_sig_set
= Word8.word array
33 type sig_set
= Word8.word vector
34 fun newSigSet (): (pre_sig_set
* (unit
-> sig_set
)) =
36 val sslen
= C_Size
.toInt Prim
.sigSetLen
37 val ss
= Array
.array (sslen
, 0wx0
: Word8.word)
39 (ss
, fn () => Array
.vector ss
)
46 val (ss
, finish
) = newSigSet ()
47 val () = SysCall
.simple (fn () => Prim
.sigfillset ss
)
48 val () = List.app (fn s
=> SysCall
.simple
49 (fn () => Prim
.sigdelset (ss
, toRep s
)))
57 val (ss
, finish
) = newSigSet ()
58 val () = SysCall
.simple (fn () => Prim
.sigemptyset ss
)
59 val () = List.app (fn s
=> SysCall
.simple
60 (fn () => Prim
.sigaddset (ss
, toRep s
)))
67 fun isMember (ss
, s
) =
68 SysCall
.simpleResult (fn () => Prim
.sigismember (ss
, toRep s
)) <> C_Int
.zero
71 fun make (how
: how
) (ss
: t
) =
73 val (oss
, finish
) = newSigSet ()
74 val () = SysCall
.simpleRestart (fn () => Prim
.sigprocmask (how
, ss
, oss
))
79 val block
= ignore
o make Prim
.SIG_BLOCK
80 val unblock
= ignore
o make Prim
.SIG_UNBLOCK
81 val setBlocked
= ignore
o make Prim
.SIG_SETMASK
82 fun getBlocked () = make Prim
.SIG_BLOCK none
90 | Handler
of MLtonThread
.Runnable
.t
-> MLtonThread
.Runnable
.t
95 datatype handler
= datatype Handler
.t
98 val r
= ref C_Int
.zero
100 fun initHandler (s
: signal
): Handler
.t
=
102 ({clear
= false, restart
= false, errVal
= C_Int
.fromInt ~
1}, fn () =>
103 {return
= Prim
.isDefault (toRep s
, r
),
104 post
= fn _
=> if !r
<> C_Int
.zero
then Default
else Ignore
,
105 handlers
= [(Error
.inval
, fn () => InvalidSignal
)]})
108 val (getHandler
, setHandler
, handlers
) =
110 val handlers
= Array
.tabulate (C_Int
.toInt Prim
.NSIG
, initHandler
o fromInt
)
113 (Cleaner
.atLoadWorld
, fn () =>
114 Array
.modifyi (initHandler
o fromInt
o #
1) handlers
)
116 (fn s
: t
=> Array
.sub (handlers
, toInt s
),
117 fn (s
: t
, h
) => if Primitive
.MLton
.Profile
.isOn
andalso s
= prof
119 else Array
.update (handlers
, toInt s
, h
),
123 val gcHandler
= ref Ignore
130 Handler _
=> (fromInt s
)::sigs
131 | _
=> sigs
) [] handlers
)
137 val default
= Default
140 val isDefault
= fn Default
=> true | _
=> false
141 val isIgnore
= fn Ignore
=> true | _
=> false
144 (* This
let is used so that Thread
.setHandler is only used
if
145 * Handler
.handler is used
. This prevents threads from being part
149 (* As far
as C is concerned
, there is only one signal handler
.
150 * As soon
as possible after a C signal is received
, this signal
151 * handler walks over the array
of all SML handlers
, and invokes any
152 * one for which a C signal has been received
.
154 * Any exceptions raised by a signal handler will be caught by
155 * the topLevelHandler
, which is installed
in thread
.sml
.
158 PosixError
.SysCall
.blocker
:=
160 val m
= Mask
.getBlocked ()
161 val () = Mask
.block (handled ())
163 fn () => Mask
.setBlocked m
167 MLtonThread
.setSignalHandler
170 val mask
= Mask
.getBlocked ()
171 val () = Mask
.block (handled ())
174 Handler f
=> if Prim
.isPendingGC () <> C_Int
.zero
183 if Prim
.isPending (repFromInt s
) <> C_Int
.zero
186 | _
=> fs
) fs handlers
187 val () = Prim
.resetPending ()
188 val () = Mask
.setBlocked mask
190 List.foldl (fn (f
, t
) => f t
) t fs
196 fun simple (f
: unit
-> unit
) = handler (fn t
=> (f (); t
))
199 val setHandler
= fn (s
, h
) =>
200 case (getHandler s
, h
) of
201 (InvalidSignal
, _
) => raiseInval ()
202 |
(_
, InvalidSignal
) => raiseInval ()
203 |
(Default
, Default
) => ()
205 (setHandler (s
, Default
)
206 ; SysCall
.simpleRestart (fn () => Prim
.default (toRep s
)))
207 |
(Handler _
, Handler _
) =>
211 ; SysCall
.simpleRestart (fn () => Prim
.handlee (toRep s
)))
212 |
(Ignore
, Ignore
) => ()
214 (setHandler (s
, Ignore
)
215 ; SysCall
.simpleRestart (fn () => Prim
.ignore (toRep s
)))
219 ; MLtonThread
.switchToSignalHandler ())
223 ; gcHandler
:= Handler
.simple f
)