【发布时间】:2016-01-18 20:02:13
【问题描述】:
我正在尝试在 Haskell 中编写一个简单的 shell,但我无法让信号处理工作。如果没有命令正在运行,则向 shell 进程发送 SIGINT 会触发信号处理程序。但是当对getProcessStatus 进行阻塞调用时,该信号将被忽略。立即向子进程发送信号当然会杀死子进程并使阻塞调用返回。
用Control.Concurrent.threadDelay 替换阻塞调用不会阻止信号,即一切都按预期工作。将阻塞标志替换为getProcessStatus 为False 使函数在子进程完成之前返回。
流程包参考:https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-Process.html#v:getProcessStatus
相关代码如下,见(唯一)注释行。
main :: IO ()
main = do
pidRef <- (newIORef [] :: IO (IORef [ProcessID]))
setSigHant pidRef
doPrompt pidRef
printPrompt :: IO ()
printPrompt = fdWrite stdError "λ➔ " >> return ()
doPrompt :: IORef [ProcessID] -> IO ()
doPrompt pidRef = do
printPrompt
tryLine <- try getLine :: IO (Either SomeException String)
case tryLine of
Left _ -> do
putStrLn ""
exitSuccess
Right line -> do
tryCl <- try (parse line) :: IO (Either SomeException [Command])
case tryCl of
Left e -> fdWrite stdError (show e ++ "\n") >> return ()
Right cl ->
if length cl > 0 && (cmd . head) cl == "cd" then
cd (head cl)
else do
execCommands pidRef cl (stdInput, stdOutput)
pids <- readIORef pidRef
-- This call to getProcessStatus blocks the signals
_ <- sequence $ map (getProcessStatus True False) pids
_ <- writeIORef pidRef []
return ()
doPrompt pidRef
setSigHant :: (IORef [ProcessID]) -> IO ()
setSigHant pidRef = do
let handler = Catch (sigIntHandler pidRef)
installHandler sigINT handler Nothing
return ()
sigIntHandler :: (IORef [ProcessID]) -> IO ()
sigIntHandler pidRef = do
pids <- readIORef pidRef
sequence_ $ map (signalProcess sigINT) pids
fdWrite stdError "\n"
printPrompt
【问题讨论】:
-
您是在 Linux 上工作还是在 Windows (Cygwin) 上工作?
-
另外,用 -thread chage 编译有什么用吗?
-
Linux (Debian)。
-threaded成功了,谢谢!我是在 SO 发帖的新手,我可以接受答案吗? -
我已将我的评论扩展为答案。
标签: haskell process signals posix