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 fail (IOError Nothing NoSuchThing
219 "getEnvVar" "no such environment variable")
222 setEnvVar :: String -> String -> IO ()
223 setEnvVar name value = do
224 str <- packStringIO (name ++ ('=' : value))
225 nonzero_error (_casm_ ``%r = _setenv(%0);'' str) "setEnvVar"
227 removeEnvVar :: String -> IO ()
228 removeEnvVar name = do
229 str <- packStringIO name
230 nonzero_error (_ccall_ delenv str) "removeEnvVar"
237 backgroundRead, sigTTIN :: Signal
238 backgroundRead = ``SIGTTIN''
239 sigTTIN = ``SIGTTIN''
241 backgroundWrite, sigTTOU :: Signal
242 backgroundWrite = ``SIGTTOU''
243 sigTTOU = ``SIGTTOU''
245 #ifndef cygwin32_TARGET_OS
246 continueProcess, sigCONT :: Signal
247 continueProcess = ``SIGCONT''
248 sigCONT = ``SIGCONT''
251 floatingPointException, sigFPE :: Signal
252 floatingPointException = ``SIGFPE''
255 illegalInstruction, sigILL :: Signal
256 illegalInstruction = ``SIGILL''
259 internalAbort, sigABRT ::Signal
260 internalAbort = ``SIGABRT''
261 sigABRT = ``SIGABRT''
263 keyboardSignal, sigINT :: Signal
264 keyboardSignal = ``SIGINT''
267 keyboardStop, sigTSTP :: Signal
268 keyboardStop = ``SIGTSTP''
269 sigTSTP = ``SIGTSTP''
271 keyboardTermination, sigQUIT :: Signal
272 keyboardTermination = ``SIGQUIT''
273 sigQUIT = ``SIGQUIT''
275 killProcess, sigKILL :: Signal
276 killProcess = ``SIGKILL''
277 sigKILL = ``SIGKILL''
279 lostConnection, sigHUP :: Signal
280 lostConnection = ``SIGHUP''
283 openEndedPipe, sigPIPE :: Signal
284 openEndedPipe = ``SIGPIPE''
285 sigPIPE = ``SIGPIPE''
287 processStatusChanged, sigCHLD :: Signal
288 processStatusChanged = ``SIGCHLD''
289 sigCHLD = ``SIGCHLD''
291 realTimeAlarm, sigALRM :: Signal
292 realTimeAlarm = ``SIGALRM''
293 sigALRM = ``SIGALRM''
295 segmentationViolation, sigSEGV :: Signal
296 segmentationViolation = ``SIGSEGV''
297 sigSEGV = ``SIGSEGV''
299 softwareStop, sigSTOP :: Signal
300 softwareStop = ``SIGSTOP''
301 sigSTOP = ``SIGSTOP''
303 softwareTermination, sigTERM :: Signal
304 softwareTermination = ``SIGTERM''
305 sigTERM = ``SIGTERM''
307 userDefinedSignal1, sigUSR1 :: Signal
308 userDefinedSignal1 = ``SIGUSR1''
309 sigUSR1 = ``SIGUSR1''
311 userDefinedSignal2, sigUSR2 :: Signal
312 userDefinedSignal2 = ``SIGUSR2''
313 sigUSR2 = ``SIGUSR2''
315 signalProcess :: Signal -> ProcessID -> IO ()
316 signalProcess int pid =
317 nonzero_error (_ccall_ kill pid int) "signalProcess"
319 raiseSignal :: Signal -> IO ()
320 raiseSignal int = getProcessID >>= signalProcess int
322 signalProcessGroup :: Signal -> ProcessGroupID -> IO ()
323 signalProcessGroup int pgid = signalProcess int (-pgid)
325 setStoppedChildFlag :: Bool -> IO Bool
326 setStoppedChildFlag b = do
327 rc <- _casm_ ``%r = nocldstop; nocldstop = %0;'' x
330 x = case b of {True -> 0; False -> 1}
332 queryStoppedChildFlag :: IO Bool
333 queryStoppedChildFlag = do
334 rc <- _casm_ ``%r = nocldstop;''
337 data Handler = Default
341 type SignalSet = ByteArray Int
344 sigSetSize = ``sizeof(sigset_t)''
346 emptySignalSet :: SignalSet
347 emptySignalSet = unsafePerformPrimIO $ do
348 bytes <- allocChars sigSetSize
349 _casm_ ``(void) sigemptyset((sigset_t *)%0);'' bytes
352 fullSignalSet :: SignalSet
353 fullSignalSet = unsafePerformPrimIO $ do
354 bytes <- allocChars sigSetSize
355 _casm_ ``(void) sigfillset((sigset_t *)%0);'' bytes
358 addSignal :: Signal -> SignalSet -> SignalSet
359 addSignal int oldset = unsafePerformPrimIO $ do
360 bytes <- allocChars sigSetSize
361 _casm_ ``*(sigset_t *)%0 = *(sigset_t *)%1;
362 (void) sigaddset((sigset_t *)%0, %2);''
366 inSignalSet :: Signal -> SignalSet -> Bool
367 inSignalSet int sigset = unsafePerformPrimIO $ do
368 rc <- _casm_ ``%r = sigismember((sigset_t *)%0, %1);'' sigset int
371 deleteSignal :: Signal -> SignalSet -> SignalSet
372 deleteSignal int oldset = unsafePerformPrimIO $ do
373 bytes <- allocChars sigSetSize
374 _casm_ ``*(sigset_t *)%0 = *(sigset_t *)%1;
375 (void) sigdelset((sigset_t *)%0, %2);''
379 installHandler :: Signal
381 -> Maybe SignalSet -- other signals to block
382 -> IO Handler -- old handler
384 #ifdef __PARALLEL_HASKELL__
385 installHandler = fail (userError "installHandler: not available for Parallel Haskell")
387 installHandler int handler maybe_mask = (
389 Default -> _ccall_ stg_sig_default int mask
390 Ignore -> _ccall_ stg_sig_ignore int mask
392 sptr <- makeStablePtr (ioToPrimIO m)
393 _ccall_ stg_sig_catch int sptr mask
397 osptr <- _casm_ ``%r = (StgStablePtr) (%0);'' rc
398 m <- deRefStablePtr osptr
400 else if rc == ``STG_SIG_DFL'' then
402 else if rc == ``STG_SIG_IGN'' then
405 syserr "installHandler"
407 mask = case maybe_mask of
408 Nothing -> emptySignalSet
411 #endif {-!__PARALLEL_HASKELL__-}
413 getSignalMask :: IO SignalSet
415 bytes <- allocChars sigSetSize
416 rc <- _casm_ ``%r = sigprocmask(0, NULL, (sigset_t *)%0);'' bytes
419 else syserr "getSignalMask"
421 sigProcMask :: String -> Int -> SignalSet -> IO SignalSet
422 sigProcMask name how sigset = do
423 bytes <- allocChars sigSetSize
424 rc <- _casm_ ``%r = sigprocmask(%0, (sigset_t *)%1, (sigset_t *)%2);''
430 setSignalMask :: SignalSet -> IO SignalSet
431 setSignalMask = sigProcMask "setSignalMask" ``SIG_SETMASK''
433 blockSignals :: SignalSet -> IO SignalSet
434 blockSignals = sigProcMask "blockSignals" ``SIG_BLOCK''
436 unBlockSignals :: SignalSet -> IO SignalSet
437 unBlockSignals = sigProcMask "unBlockSignals" ``SIG_UNBLOCK''
439 getPendingSignals :: IO SignalSet
440 getPendingSignals = do
441 bytes <- allocChars sigSetSize
442 rc <- _casm_ ``%r = sigpending((sigset_t *)%0);'' bytes
445 else syserr "getPendingSignals"
447 #ifndef cygwin32_TARGET_OS
448 awaitSignal :: Maybe SignalSet -> IO ()
449 awaitSignal maybe_sigset = do
452 if err == interruptedOperation
454 else syserr "awaitSignal"
456 pause :: Maybe SignalSet -> IO ()
459 Nothing -> _casm_ ``(void) pause();''
460 Just sigset -> _casm_ ``(void) sigsuspend((sigset_t *)%0);'' sigset
463 scheduleAlarm :: Int -> IO Int
464 scheduleAlarm (I# secs#) =
465 _ccall_ alarm (W# (int2Word# secs#)) >>= \ (W# w#) ->
466 return (I# (word2Int# w#))
468 sleep :: Int -> IO ()
470 sleep (I# secs#) = do
471 _ccall_ sleep (W# (int2Word# secs#))
475 Local utility functions
479 -- Get the trailing component of a path
481 basename :: String -> String
484 | c == '/' = basename cs
485 | otherwise = c : basename cs
487 -- Convert wait options to appropriate set of flags
489 waitOptions :: Bool -> Bool -> Int
491 waitOptions False False = ``WNOHANG''
492 waitOptions False True = ``(WNOHANG|WUNTRACED)''
493 waitOptions True False = 0
494 waitOptions True True = ``WUNTRACED''
496 -- Turn a (ptr to a) wait status into a ProcessStatus
498 decipherWaitStatus :: MutableByteArray s x -> IO ProcessStatus
499 decipherWaitStatus wstat = do
500 exited <- _casm_ ``%r = WIFEXITED(*(int *)%0);'' wstat
503 exitstatus <- _casm_ ``%r = WEXITSTATUS(*(int *)%0);'' wstat
505 then return (Exited ExitSuccess)
506 else return (Exited (ExitFailure exitstatus))
508 signalled <- _casm_ ``%r = WIFSIGNALED(*(int *)%0);'' wstat
511 termsig <- _casm_ ``%r = WTERMSIG(*(int *)%0);'' wstat
512 return (Terminated termsig)
514 stopsig <-_casm_ ``%r = WSTOPSIG(*(int *)%0);'' wstat
515 return (Stopped stopsig)