1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
|
-----------------------------------------------------------------------------
-- |
-- Module : System.Posix.Signals
-- Copyright : (c) The University of Glasgow 2002
-- License : BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer : libraries@haskell.org
-- Stability : provisional
-- Portability : non-portable (requires POSIX)
--
-- POSIX signal support
--
-----------------------------------------------------------------------------
#include "HsBaseConfig.h"
module System.Posix.Signals (
#ifndef mingw32_HOST_OS
-- * The Signal type
Signal,
-- * Specific signals
nullSignal,
internalAbort, sigABRT,
realTimeAlarm, sigALRM,
busError, sigBUS,
processStatusChanged, sigCHLD,
continueProcess, sigCONT,
floatingPointException, sigFPE,
lostConnection, sigHUP,
illegalInstruction, sigILL,
keyboardSignal, sigINT,
killProcess, sigKILL,
openEndedPipe, sigPIPE,
keyboardTermination, sigQUIT,
segmentationViolation, sigSEGV,
softwareStop, sigSTOP,
softwareTermination, sigTERM,
keyboardStop, sigTSTP,
backgroundRead, sigTTIN,
backgroundWrite, sigTTOU,
userDefinedSignal1, sigUSR1,
userDefinedSignal2, sigUSR2,
#if CONST_SIGPOLL != -1
pollableEvent, sigPOLL,
#endif
profilingTimerExpired, sigPROF,
badSystemCall, sigSYS,
breakpointTrap, sigTRAP,
urgentDataAvailable, sigURG,
virtualTimerExpired, sigVTALRM,
cpuTimeLimitExceeded, sigXCPU,
fileSizeLimitExceeded, sigXFSZ,
-- * Sending signals
raiseSignal,
signalProcess,
signalProcessGroup,
#ifdef __GLASGOW_HASKELL__
-- * Handling signals
Handler(..),
installHandler,
#endif
-- * Signal sets
SignalSet,
emptySignalSet, fullSignalSet,
addSignal, deleteSignal, inSignalSet,
-- * The process signal mask
getSignalMask, setSignalMask, blockSignals, unblockSignals,
-- * The alarm timer
scheduleAlarm,
-- * Waiting for signals
getPendingSignals,
#ifndef cygwin32_HOST_OS
awaitSignal,
#endif
#ifdef __GLASGOW_HASKELL__
-- * The @NOCLDSTOP@ flag
setStoppedChildFlag, queryStoppedChildFlag,
#endif
-- MISSING FUNCTIONALITY:
-- sigaction(), (inc. the sigaction structure + flags etc.)
-- the siginfo structure
-- sigaltstack()
-- sighold, sigignore, sigpause, sigrelse, sigset
-- siginterrupt
#endif
) where
import Prelude -- necessary to get dependencies right
#ifdef __GLASGOW_HASKELL__
#include "Signals.h"
#endif
import Foreign
import Foreign.C
import System.IO.Unsafe
import System.Posix.Types
import System.Posix.Internals
#ifndef mingw32_HOST_OS
-- WHOLE FILE...
-- -----------------------------------------------------------------------------
-- Specific signals
type Signal = CInt
nullSignal :: Signal
nullSignal = 0
sigABRT = CONST_SIGABRT :: CInt
sigALRM = CONST_SIGALRM :: CInt
sigBUS = CONST_SIGBUS :: CInt
sigCHLD = CONST_SIGCHLD :: CInt
sigCONT = CONST_SIGCONT :: CInt
sigFPE = CONST_SIGFPE :: CInt
sigHUP = CONST_SIGHUP :: CInt
sigILL = CONST_SIGILL :: CInt
sigINT = CONST_SIGINT :: CInt
sigKILL = CONST_SIGKILL :: CInt
sigPIPE = CONST_SIGPIPE :: CInt
sigQUIT = CONST_SIGQUIT :: CInt
sigSEGV = CONST_SIGSEGV :: CInt
sigSTOP = CONST_SIGSTOP :: CInt
sigTERM = CONST_SIGTERM :: CInt
sigTSTP = CONST_SIGTSTP :: CInt
sigTTIN = CONST_SIGTTIN :: CInt
sigTTOU = CONST_SIGTTOU :: CInt
sigUSR1 = CONST_SIGUSR1 :: CInt
sigUSR2 = CONST_SIGUSR2 :: CInt
sigPOLL = CONST_SIGPOLL :: CInt
sigPROF = CONST_SIGPROF :: CInt
sigSYS = CONST_SIGSYS :: CInt
sigTRAP = CONST_SIGTRAP :: CInt
sigURG = CONST_SIGURG :: CInt
sigVTALRM = CONST_SIGVTALRM :: CInt
sigXCPU = CONST_SIGXCPU :: CInt
sigXFSZ = CONST_SIGXFSZ :: CInt
internalAbort ::Signal
internalAbort = sigABRT
realTimeAlarm :: Signal
realTimeAlarm = sigALRM
busError :: Signal
busError = sigBUS
processStatusChanged :: Signal
processStatusChanged = sigCHLD
continueProcess :: Signal
continueProcess = sigCONT
floatingPointException :: Signal
floatingPointException = sigFPE
lostConnection :: Signal
lostConnection = sigHUP
illegalInstruction :: Signal
illegalInstruction = sigILL
keyboardSignal :: Signal
keyboardSignal = sigINT
killProcess :: Signal
killProcess = sigKILL
openEndedPipe :: Signal
openEndedPipe = sigPIPE
keyboardTermination :: Signal
keyboardTermination = sigQUIT
segmentationViolation :: Signal
segmentationViolation = sigSEGV
softwareStop :: Signal
softwareStop = sigSTOP
softwareTermination :: Signal
softwareTermination = sigTERM
keyboardStop :: Signal
keyboardStop = sigTSTP
backgroundRead :: Signal
backgroundRead = sigTTIN
backgroundWrite :: Signal
backgroundWrite = sigTTOU
userDefinedSignal1 :: Signal
userDefinedSignal1 = sigUSR1
userDefinedSignal2 :: Signal
userDefinedSignal2 = sigUSR2
#if CONST_SIGPOLL != -1
pollableEvent :: Signal
pollableEvent = sigPOLL
#endif
profilingTimerExpired :: Signal
profilingTimerExpired = sigPROF
badSystemCall :: Signal
badSystemCall = sigSYS
breakpointTrap :: Signal
breakpointTrap = sigTRAP
urgentDataAvailable :: Signal
urgentDataAvailable = sigURG
virtualTimerExpired :: Signal
virtualTimerExpired = sigVTALRM
cpuTimeLimitExceeded :: Signal
cpuTimeLimitExceeded = sigXCPU
fileSizeLimitExceeded :: Signal
fileSizeLimitExceeded = sigXFSZ
-- -----------------------------------------------------------------------------
-- Signal-related functions
signalProcess :: Signal -> ProcessID -> IO ()
signalProcess sig pid
= throwErrnoIfMinus1_ "signalProcess" (c_kill (fromIntegral pid) sig)
foreign import ccall unsafe "kill"
c_kill :: CPid -> CInt -> IO CInt
signalProcessGroup :: Signal -> ProcessGroupID -> IO ()
signalProcessGroup sig pgid
= throwErrnoIfMinus1_ "signalProcessGroup" (c_killpg (fromIntegral pgid) sig)
foreign import ccall unsafe "killpg"
c_killpg :: CPid -> CInt -> IO CInt
raiseSignal :: Signal -> IO ()
raiseSignal sig = throwErrnoIfMinus1_ "raiseSignal" (c_raise sig)
#if defined(__GLASGOW_HASKELL__) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS))
foreign import ccall unsafe "genericRaise"
c_raise :: CInt -> IO CInt
#else
foreign import ccall unsafe "raise"
c_raise :: CInt -> IO CInt
#endif
#ifdef __GLASGOW_HASKELL__
data Handler = Default
| Ignore
-- not yet: | Hold
| Catch (IO ())
| CatchOnce (IO ())
installHandler :: Signal
-> Handler
-> Maybe SignalSet -- other signals to block
-> IO Handler -- old handler
#ifdef __PARALLEL_HASKELL__
installHandler =
error "installHandler: not available for Parallel Haskell"
#else
installHandler int handler maybe_mask = do
case maybe_mask of
Nothing -> install' nullPtr
Just (SignalSet x) -> withForeignPtr x $ install'
where
install' mask =
alloca $ \p_sp -> do
rc <- case handler of
Default -> stg_sig_install int STG_SIG_DFL p_sp mask
Ignore -> stg_sig_install int STG_SIG_IGN p_sp mask
Catch m -> hinstall m p_sp mask int STG_SIG_HAN
CatchOnce m -> hinstall m p_sp mask int STG_SIG_RST
case rc of
STG_SIG_DFL -> return Default
STG_SIG_IGN -> return Ignore
STG_SIG_ERR -> throwErrno "installHandler"
STG_SIG_HAN -> do
m <- peekHandler p_sp
return (Catch m)
STG_SIG_RST -> do
m <- peekHandler p_sp
return (CatchOnce m)
_other ->
error "internal error: System.Posix.Signals.installHandler"
hinstall m p_sp mask int reset = do
sptr <- newStablePtr m
poke p_sp sptr
stg_sig_install int reset p_sp mask
peekHandler p_sp = do
osptr <- peek p_sp
deRefStablePtr osptr
foreign import ccall unsafe
stg_sig_install
:: CInt -- sig no.
-> CInt -- action code (STG_SIG_HAN etc.)
-> Ptr (StablePtr (IO ())) -- (in, out) Haskell handler
-> Ptr CSigset -- (in, out) blocked
-> IO CInt -- (ret) action code
#endif /* !__PARALLEL_HASKELL__ */
#endif /* __GLASGOW_HASKELL__ */
-- -----------------------------------------------------------------------------
-- Alarms
scheduleAlarm :: Int -> IO Int
scheduleAlarm secs = do
r <- c_alarm (fromIntegral secs)
return (fromIntegral r)
foreign import ccall unsafe "alarm"
c_alarm :: CUInt -> IO CUInt
#ifdef __GLASGOW_HASKELL__
-- -----------------------------------------------------------------------------
-- The NOCLDSTOP flag
foreign import ccall "&nocldstop" nocldstop :: Ptr Int
-- | Tells the system whether or not to set the @SA_NOCLDSTOP@ flag when
-- installing new signal handlers.
setStoppedChildFlag :: Bool -> IO Bool
setStoppedChildFlag b = do
rc <- peek nocldstop
poke nocldstop $ fromEnum (not b)
return (rc == (0::Int))
-- | Queries the current state of the stopped child flag.
queryStoppedChildFlag :: IO Bool
queryStoppedChildFlag = do
rc <- peek nocldstop
return (rc == (0::Int))
#endif /* __GLASGOW_HASKELL__ */
-- -----------------------------------------------------------------------------
-- Manipulating signal sets
newtype SignalSet = SignalSet (ForeignPtr CSigset)
emptySignalSet :: SignalSet
emptySignalSet = unsafePerformIO $ do
fp <- mallocForeignPtrBytes sizeof_sigset_t
throwErrnoIfMinus1_ "emptySignalSet" (withForeignPtr fp $ c_sigemptyset)
return (SignalSet fp)
fullSignalSet :: SignalSet
fullSignalSet = unsafePerformIO $ do
fp <- mallocForeignPtrBytes sizeof_sigset_t
throwErrnoIfMinus1_ "fullSignalSet" (withForeignPtr fp $ c_sigfillset)
return (SignalSet fp)
infixr `addSignal`, `deleteSignal`
addSignal :: Signal -> SignalSet -> SignalSet
addSignal sig (SignalSet fp1) = unsafePerformIO $ do
fp2 <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp1 $ \p1 ->
withForeignPtr fp2 $ \p2 -> do
copyBytes p2 p1 sizeof_sigset_t
throwErrnoIfMinus1_ "addSignal" (c_sigaddset p2 sig)
return (SignalSet fp2)
deleteSignal :: Signal -> SignalSet -> SignalSet
deleteSignal sig (SignalSet fp1) = unsafePerformIO $ do
fp2 <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp1 $ \p1 ->
withForeignPtr fp2 $ \p2 -> do
copyBytes p2 p1 sizeof_sigset_t
throwErrnoIfMinus1_ "deleteSignal" (c_sigdelset p2 sig)
return (SignalSet fp2)
inSignalSet :: Signal -> SignalSet -> Bool
inSignalSet sig (SignalSet fp) = unsafePerformIO $
withForeignPtr fp $ \p -> do
r <- throwErrnoIfMinus1 "inSignalSet" (c_sigismember p sig)
return (r /= 0)
getSignalMask :: IO SignalSet
getSignalMask = do
fp <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp $ \p ->
throwErrnoIfMinus1_ "getSignalMask" (c_sigprocmask 0 nullPtr p)
return (SignalSet fp)
sigProcMask :: String -> CInt -> SignalSet -> IO ()
sigProcMask fn how (SignalSet set) =
withForeignPtr set $ \p_set ->
throwErrnoIfMinus1_ fn (c_sigprocmask how p_set nullPtr)
setSignalMask :: SignalSet -> IO ()
setSignalMask set = sigProcMask "setSignalMask" (CONST_SIG_SETMASK :: CInt) set
blockSignals :: SignalSet -> IO ()
blockSignals set = sigProcMask "blockSignals" (CONST_SIG_BLOCK :: CInt) set
unblockSignals :: SignalSet -> IO ()
unblockSignals set = sigProcMask "unblockSignals" (CONST_SIG_UNBLOCK :: CInt) set
getPendingSignals :: IO SignalSet
getPendingSignals = do
fp <- mallocForeignPtrBytes sizeof_sigset_t
withForeignPtr fp $ \p ->
throwErrnoIfMinus1_ "getPendingSignals" (c_sigpending p)
return (SignalSet fp)
#ifndef cygwin32_HOST_OS
awaitSignal :: Maybe SignalSet -> IO ()
awaitSignal maybe_sigset = do
fp <- case maybe_sigset of
Nothing -> do SignalSet fp <- getSignalMask; return fp
Just (SignalSet fp) -> return fp
withForeignPtr fp $ \p -> do
c_sigsuspend p
return ()
-- ignore the return value; according to the docs it can only ever be
-- (-1) with errno set to EINTR.
foreign import ccall unsafe "sigsuspend"
c_sigsuspend :: Ptr CSigset -> IO CInt
#endif
#ifdef __HUGS__
foreign import ccall unsafe "sigdelset"
c_sigdelset :: Ptr CSigset -> CInt -> IO CInt
foreign import ccall unsafe "sigfillset"
c_sigfillset :: Ptr CSigset -> IO CInt
foreign import ccall unsafe "sigismember"
c_sigismember :: Ptr CSigset -> CInt -> IO CInt
#else
foreign import ccall unsafe "__hscore_sigdelset"
c_sigdelset :: Ptr CSigset -> CInt -> IO CInt
foreign import ccall unsafe "__hscore_sigfillset"
c_sigfillset :: Ptr CSigset -> IO CInt
foreign import ccall unsafe "__hscore_sigismember"
c_sigismember :: Ptr CSigset -> CInt -> IO CInt
#endif /* __HUGS__ */
foreign import ccall unsafe "sigpending"
c_sigpending :: Ptr CSigset -> IO CInt
#endif /* mingw32_HOST_OS */
|