2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1997
4 \section[PosixProcPrim]{Haskell 1.3 POSIX Process Primitives}
10 module PosixProcPrim (
17 #ifndef cygwin32_TARGET_OS
23 #ifndef cygwin32_TARGET_OS
30 floatingPointException,
36 getGroupProcessStatus,
52 queryStoppedChildFlag,
57 segmentationViolation,
65 #ifndef cygwin32_TARGET_OS
101 import Foreign ( makeStablePtr, StablePtr, deRefStablePtr )
102 import Addr ( nullAddr )
106 import CString ( unvectorize, packStringIO,
107 allocChars, freeze, vectorize,
111 import System(ExitCode(..))
112 import PosixProcEnv (getProcessID)
114 forkProcess :: IO (Maybe ProcessID)
118 -1 -> syserr "forkProcess"
120 _ -> return (Just pid)
122 executeFile :: FilePath -- Command
123 -> Bool -- Search PATH?
124 -> [String] -- Arguments
125 -> Maybe [(String, String)] -- Environment
127 executeFile path search args Nothing = do
128 prog <- packStringIO path
129 argv <- vectorize (basename path:args)
131 _casm_ ``execvp(%0,(char **)%1);'' prog argv
133 _casm_ ``execv(%0,(char **)%1);'' prog argv
137 executeFile path search args (Just env) = do
138 prog <- packStringIO path
139 argv <- vectorize (basename path:args)
140 envp <- vectorize (map (\ (name, val) -> name ++ ('=' : val)) env)
142 _casm_ `` execvpe(%0,(char **)%1,(char **)%2);'' prog argv envp
144 _casm_ `` execve(%0,(char **)%1,(char **)%2);'' prog argv envp
148 data ProcessStatus = Exited ExitCode
151 deriving (Eq, Ord, Show)
153 getProcessStatus :: Bool -> Bool -> ProcessID -> IO (Maybe ProcessStatus)
154 getProcessStatus block stopped pid = do
155 wstat <- allocWords 1
156 pid <-_casm_ ``%r = waitpid(%0, (int *)%1, %2);'' pid wstat
157 (waitOptions block stopped)
159 -1 -> syserr "getProcessStatus"
161 _ -> do ps <- decipherWaitStatus wstat
164 getGroupProcessStatus :: Bool
167 -> IO (Maybe (ProcessID, ProcessStatus))
168 getGroupProcessStatus block stopped pgid = do
169 wstat <- allocWords 1
170 pid <-_casm_ ``%r = waitpid(%0, (int *)%1, %2);'' (-pgid) wstat
171 (waitOptions block stopped)
173 -1 -> syserr "getGroupProcessStatus"
175 _ -> do ps <- decipherWaitStatus wstat
176 return (Just (pid, ps))
178 getAnyProcessStatus :: Bool -> Bool -> IO (Maybe (ProcessID, ProcessStatus))
179 getAnyProcessStatus block stopped =
180 getGroupProcessStatus block stopped 1 `catch`
181 \ err -> syserr "getAnyProcessStatus"
183 exitImmediately :: ExitCode -> IO ()
184 exitImmediately exitcode = do
185 _casm_ ``_exit(%0);'' (exitcode2Int exitcode)
186 syserr "exitImmediately"
188 exitcode2Int ExitSuccess = 0
189 exitcode2Int (ExitFailure n) = n
191 getEnvironment :: IO [(String, String)]
193 --WAS: env <- unvectorize ``environ'' 0
194 -- does not work too well, since the lit-lit
195 -- is turned into an Addr that is only evaluated
196 -- once (environ is changed to point the most
197 -- current env. block after the addition of new entries).
198 envp <- _casm_ `` %r=environ; ''
199 env <- unvectorize (envp::Addr) 0
200 return (map (split "") env)
202 split :: String -> String -> (String, String)
203 split x [] = error ("PosixProcPrim.getEnvironment:no `='? in: "++reverse x)
204 split x ('=' : xs) = (reverse x, xs)
205 split x (c:cs) = split (c:x) cs
207 setEnvironment :: [(String, String)] -> IO ()
208 setEnvironment pairs = do
209 env <- vectorize (map (\ (var,val) -> var ++ ('=' : val)) pairs)
210 nonzero_error (_casm_ ``%r = setenviron((char **)%0);'' env)
213 getEnvVar :: String -> IO String
215 str <- packStringIO name
216 str <- _ccall_ getenv str
218 then ioError (IOError Nothing NoSuchThing "getEnvVar" "no such environment variable")
221 setEnvVar :: String -> String -> IO ()
222 setEnvVar name value = do
223 str <- packStringIO (name ++ ('=' : value))
224 nonzero_error (_casm_ ``%r = _setenv(%0);'' str) "setEnvVar"
226 removeEnvVar :: String -> IO ()
227 removeEnvVar name = do
228 str <- packStringIO name
229 nonzero_error (_ccall_ delenv str) "removeEnvVar"
236 backgroundRead, sigTTIN :: Signal
237 backgroundRead = ``SIGTTIN''
238 sigTTIN = ``SIGTTIN''
240 backgroundWrite, sigTTOU :: Signal
241 backgroundWrite = ``SIGTTOU''
242 sigTTOU = ``SIGTTOU''
244 #ifndef cygwin32_TARGET_OS
245 continueProcess, sigCONT :: Signal
246 continueProcess = ``SIGCONT''
247 sigCONT = ``SIGCONT''
250 floatingPointException, sigFPE :: Signal
251 floatingPointException = ``SIGFPE''
254 illegalInstruction, sigILL :: Signal
255 illegalInstruction = ``SIGILL''
258 internalAbort, sigABRT ::Signal
259 internalAbort = ``SIGABRT''
260 sigABRT = ``SIGABRT''
262 keyboardSignal, sigINT :: Signal
263 keyboardSignal = ``SIGINT''
266 keyboardStop, sigTSTP :: Signal
267 keyboardStop = ``SIGTSTP''
268 sigTSTP = ``SIGTSTP''
270 keyboardTermination, sigQUIT :: Signal
271 keyboardTermination = ``SIGQUIT''
272 sigQUIT = ``SIGQUIT''
274 killProcess, sigKILL :: Signal
275 killProcess = ``SIGKILL''
276 sigKILL = ``SIGKILL''
278 lostConnection, sigHUP :: Signal
279 lostConnection = ``SIGHUP''
282 openEndedPipe, sigPIPE :: Signal
283 openEndedPipe = ``SIGPIPE''
284 sigPIPE = ``SIGPIPE''
286 processStatusChanged, sigCHLD :: Signal
287 processStatusChanged = ``SIGCHLD''
288 sigCHLD = ``SIGCHLD''
290 realTimeAlarm, sigALRM :: Signal
291 realTimeAlarm = ``SIGALRM''
292 sigALRM = ``SIGALRM''
294 segmentationViolation, sigSEGV :: Signal
295 segmentationViolation = ``SIGSEGV''
296 sigSEGV = ``SIGSEGV''
298 softwareStop, sigSTOP :: Signal
299 softwareStop = ``SIGSTOP''
300 sigSTOP = ``SIGSTOP''
302 softwareTermination, sigTERM :: Signal
303 softwareTermination = ``SIGTERM''
304 sigTERM = ``SIGTERM''
306 userDefinedSignal1, sigUSR1 :: Signal
307 userDefinedSignal1 = ``SIGUSR1''
308 sigUSR1 = ``SIGUSR1''
310 userDefinedSignal2, sigUSR2 :: Signal
311 userDefinedSignal2 = ``SIGUSR2''
312 sigUSR2 = ``SIGUSR2''
314 signalProcess :: Signal -> ProcessID -> IO ()
315 signalProcess int pid =
316 nonzero_error (_ccall_ kill pid int) "signalProcess"
318 raiseSignal :: Signal -> IO ()
319 raiseSignal int = getProcessID >>= signalProcess int
321 signalProcessGroup :: Signal -> ProcessGroupID -> IO ()
322 signalProcessGroup int pgid = signalProcess int (-pgid)
324 setStoppedChildFlag :: Bool -> IO Bool
325 setStoppedChildFlag b = do
326 rc <- _casm_ ``%r = nocldstop; nocldstop = %0;'' (x::Int)
327 return (rc == (0::Int))
329 x = case b of {True -> 0; False -> 1}
331 queryStoppedChildFlag :: IO Bool
332 queryStoppedChildFlag = do
333 rc <- _casm_ ``%r = nocldstop;''
334 return (rc == (0::Int))
336 data Handler = Default
340 type SignalSet = ByteArray Int
343 sigSetSize = ``sizeof(sigset_t)''
345 emptySignalSet :: SignalSet
346 emptySignalSet = unsafePerformPrimIO $ do
347 bytes <- allocChars sigSetSize
348 _casm_ ``(void) sigemptyset((sigset_t *)%0);'' bytes
351 fullSignalSet :: SignalSet
352 fullSignalSet = unsafePerformPrimIO $ do
353 bytes <- allocChars sigSetSize
354 _casm_ ``(void) sigfillset((sigset_t *)%0);'' bytes
357 addSignal :: Signal -> SignalSet -> SignalSet
358 addSignal int oldset = unsafePerformPrimIO $ do
359 bytes <- allocChars sigSetSize
360 _ccall_ stg_sigaddset bytes oldset int
363 inSignalSet :: Signal -> SignalSet -> Bool
364 inSignalSet int sigset = unsafePerformPrimIO $ do
365 rc <- _casm_ ``%r = sigismember((sigset_t *)%0, %1);'' sigset int
366 return (rc == (1::Int))
368 deleteSignal :: Signal -> SignalSet -> SignalSet
369 deleteSignal int oldset = unsafePerformPrimIO $ do
370 bytes <- allocChars sigSetSize
371 _ccall_ stg_sigdelset bytes oldset int
374 installHandler :: Signal
376 -> Maybe SignalSet -- other signals to block
377 -> IO Handler -- old handler
379 #ifdef __PARALLEL_HASKELL__
380 installHandler = ioError (userError "installHandler: not available for Parallel Haskell")
382 installHandler int handler maybe_mask = (
384 Default -> _ccall_ stg_sig_default int mask
385 Ignore -> _ccall_ stg_sig_ignore int mask
387 sptr <- makeStablePtr (ioToPrimIO m)
388 _ccall_ stg_sig_catch int sptr mask
391 if rc >= (0::Int) then do
392 osptr <- _casm_ ``%r = (StgStablePtr) (%0);'' rc
393 m <- deRefStablePtr osptr
395 else if rc == ``STG_SIG_DFL'' then
397 else if rc == ``STG_SIG_IGN'' then
400 syserr "installHandler"
402 mask = case maybe_mask of
403 Nothing -> emptySignalSet
406 #endif {-!__PARALLEL_HASKELL__-}
408 getSignalMask :: IO SignalSet
410 bytes <- allocChars sigSetSize
411 rc <- _casm_ ``%r = sigprocmask(0, NULL, (sigset_t *)%0);'' bytes
414 else syserr "getSignalMask"
416 sigProcMask :: String -> Int -> SignalSet -> IO SignalSet
417 sigProcMask name how sigset = do
418 bytes <- allocChars sigSetSize
419 rc <- _casm_ ``%r = sigprocmask(%0, (sigset_t *)%1, (sigset_t *)%2);''
425 setSignalMask :: SignalSet -> IO SignalSet
426 setSignalMask = sigProcMask "setSignalMask" ``SIG_SETMASK''
428 blockSignals :: SignalSet -> IO SignalSet
429 blockSignals = sigProcMask "blockSignals" ``SIG_BLOCK''
431 unBlockSignals :: SignalSet -> IO SignalSet
432 unBlockSignals = sigProcMask "unBlockSignals" ``SIG_UNBLOCK''
434 getPendingSignals :: IO SignalSet
435 getPendingSignals = do
436 bytes <- allocChars sigSetSize
437 rc <- _casm_ ``%r = sigpending((sigset_t *)%0);'' bytes
440 else syserr "getPendingSignals"
442 #ifndef cygwin32_TARGET_OS
443 awaitSignal :: Maybe SignalSet -> IO ()
444 awaitSignal maybe_sigset = do
447 if err == interruptedOperation
449 else syserr "awaitSignal"
451 pause :: Maybe SignalSet -> IO ()
454 Nothing -> _casm_ ``(void) pause();''
455 Just sigset -> _casm_ ``(void) sigsuspend((sigset_t *)%0);'' sigset
458 scheduleAlarm :: Int -> IO Int
459 scheduleAlarm (I# secs#) =
460 _ccall_ alarm (W# (int2Word# secs#)) >>= \ (W# w#) ->
461 return (I# (word2Int# w#))
463 sleep :: Int -> IO ()
465 sleep (I# secs#) = do
466 _ccall_ sleep (W# (int2Word# secs#))
470 Local utility functions
474 -- Get the trailing component of a path
476 basename :: String -> String
479 | c == '/' = basename cs
480 | otherwise = c : basename cs
482 -- Convert wait options to appropriate set of flags
484 waitOptions :: Bool -> Bool -> Int
486 waitOptions False False = ``WNOHANG''
487 waitOptions False True = ``(WNOHANG|WUNTRACED)''
488 waitOptions True False = 0
489 waitOptions True True = ``WUNTRACED''
491 -- Turn a (ptr to a) wait status into a ProcessStatus
493 decipherWaitStatus :: MutableByteArray s x -> IO ProcessStatus
494 decipherWaitStatus wstat = do
495 exited <- _casm_ ``%r = WIFEXITED(*(int *)%0);'' wstat
496 if exited /= (0::Int)
498 exitstatus <- _casm_ ``%r = WEXITSTATUS(*(int *)%0);'' wstat
499 if exitstatus == (0::Int)
500 then return (Exited ExitSuccess)
501 else return (Exited (ExitFailure exitstatus))
503 signalled <- _casm_ ``%r = WIFSIGNALED(*(int *)%0);'' wstat
504 if signalled /= (0::Int)
506 termsig <- _casm_ ``%r = WTERMSIG(*(int *)%0);'' wstat
507 return (Terminated termsig)
509 stopsig <-_casm_ ``%r = WSTOPSIG(*(int *)%0);'' wstat
510 return (Stopped stopsig)