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 _ccall_ stg_sigaddset bytes oldset int
364 inSignalSet :: Signal -> SignalSet -> Bool
365 inSignalSet int sigset = unsafePerformPrimIO $ do
366 rc <- _casm_ ``%r = sigismember((sigset_t *)%0, %1);'' sigset int
369 deleteSignal :: Signal -> SignalSet -> SignalSet
370 deleteSignal int oldset = unsafePerformPrimIO $ do
371 bytes <- allocChars sigSetSize
372 _ccall_ stg_sigdelset bytes oldset int
375 installHandler :: Signal
377 -> Maybe SignalSet -- other signals to block
378 -> IO Handler -- old handler
380 #ifdef __PARALLEL_HASKELL__
381 installHandler = fail (userError "installHandler: not available for Parallel Haskell")
383 installHandler int handler maybe_mask = (
385 Default -> _ccall_ stg_sig_default int mask
386 Ignore -> _ccall_ stg_sig_ignore int mask
388 sptr <- makeStablePtr (ioToPrimIO m)
389 _ccall_ stg_sig_catch int sptr mask
393 osptr <- _casm_ ``%r = (StgStablePtr) (%0);'' rc
394 m <- deRefStablePtr osptr
396 else if rc == ``STG_SIG_DFL'' then
398 else if rc == ``STG_SIG_IGN'' then
401 syserr "installHandler"
403 mask = case maybe_mask of
404 Nothing -> emptySignalSet
407 #endif {-!__PARALLEL_HASKELL__-}
409 getSignalMask :: IO SignalSet
411 bytes <- allocChars sigSetSize
412 rc <- _casm_ ``%r = sigprocmask(0, NULL, (sigset_t *)%0);'' bytes
415 else syserr "getSignalMask"
417 sigProcMask :: String -> Int -> SignalSet -> IO SignalSet
418 sigProcMask name how sigset = do
419 bytes <- allocChars sigSetSize
420 rc <- _casm_ ``%r = sigprocmask(%0, (sigset_t *)%1, (sigset_t *)%2);''
426 setSignalMask :: SignalSet -> IO SignalSet
427 setSignalMask = sigProcMask "setSignalMask" ``SIG_SETMASK''
429 blockSignals :: SignalSet -> IO SignalSet
430 blockSignals = sigProcMask "blockSignals" ``SIG_BLOCK''
432 unBlockSignals :: SignalSet -> IO SignalSet
433 unBlockSignals = sigProcMask "unBlockSignals" ``SIG_UNBLOCK''
435 getPendingSignals :: IO SignalSet
436 getPendingSignals = do
437 bytes <- allocChars sigSetSize
438 rc <- _casm_ ``%r = sigpending((sigset_t *)%0);'' bytes
441 else syserr "getPendingSignals"
443 #ifndef cygwin32_TARGET_OS
444 awaitSignal :: Maybe SignalSet -> IO ()
445 awaitSignal maybe_sigset = do
448 if err == interruptedOperation
450 else syserr "awaitSignal"
452 pause :: Maybe SignalSet -> IO ()
455 Nothing -> _casm_ ``(void) pause();''
456 Just sigset -> _casm_ ``(void) sigsuspend((sigset_t *)%0);'' sigset
459 scheduleAlarm :: Int -> IO Int
460 scheduleAlarm (I# secs#) =
461 _ccall_ alarm (W# (int2Word# secs#)) >>= \ (W# w#) ->
462 return (I# (word2Int# w#))
464 sleep :: Int -> IO ()
466 sleep (I# secs#) = do
467 _ccall_ sleep (W# (int2Word# secs#))
471 Local utility functions
475 -- Get the trailing component of a path
477 basename :: String -> String
480 | c == '/' = basename cs
481 | otherwise = c : basename cs
483 -- Convert wait options to appropriate set of flags
485 waitOptions :: Bool -> Bool -> Int
487 waitOptions False False = ``WNOHANG''
488 waitOptions False True = ``(WNOHANG|WUNTRACED)''
489 waitOptions True False = 0
490 waitOptions True True = ``WUNTRACED''
492 -- Turn a (ptr to a) wait status into a ProcessStatus
494 decipherWaitStatus :: MutableByteArray s x -> IO ProcessStatus
495 decipherWaitStatus wstat = do
496 exited <- _casm_ ``%r = WIFEXITED(*(int *)%0);'' wstat
499 exitstatus <- _casm_ ``%r = WEXITSTATUS(*(int *)%0);'' wstat
501 then return (Exited ExitSuccess)
502 else return (Exited (ExitFailure exitstatus))
504 signalled <- _casm_ ``%r = WIFSIGNALED(*(int *)%0);'' wstat
507 termsig <- _casm_ ``%r = WTERMSIG(*(int *)%0);'' wstat
508 return (Terminated termsig)
510 stopsig <-_casm_ ``%r = WSTOPSIG(*(int *)%0);'' wstat
511 return (Stopped stopsig)