【问题标题】:Haskell: getProcessStatus blocking SIGINTHaskell:getProcessStatus 阻塞 SIGINT
【发布时间】:2016-01-18 20:02:13
【问题描述】:

我正在尝试在 Haskell 中编写一个简单的 shell,但我无法让信号处理工作。如果没有命令正在运行,则向 shell 进程发送 SIGINT 会触发信号处理程序。但是当对getProcessStatus 进行阻塞调用时,该信号将被忽略。立即向子进程发送信号当然会杀死子进程并使阻塞调用返回。

Control.Concurrent.threadDelay 替换阻塞调用不会阻止信号,即一切都按预期工作。将阻塞标志替换为getProcessStatusFalse 使函数在子进程完成之前返回。

流程包参考: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


【解决方案1】:

getProcessStatus 在内部使用 interruptible FFI 调用。但是为什么需要-threaded

This blog post 关于在 Haskell 中处理 ctrl-c 表明信号处理是在一个单独的线程中完成的,该线程使用异步异常杀死主线程:

当用户按下 Ctrl-C 时,GHC 会引发一个异步异常类型 主线程上的 UserInterrupt。这是因为 GHC 安装了一个 引发该异常的中断处理程序,将其发送到主 线程与 throwTo。

但是 async 包的 documentation 提到:

不同的 Haskell 实现具有不同的特性 关于哪些操作阻塞了所有线程。

使用不带 -thread 选项的 GHC,所有外部调用都会阻塞 系统中的所有其他 Haskell 线程,尽管 I/O 操作将 不是。使用 -thread 选项,只有带有 unsafe 的外部调用 属性将阻塞所有其他线程。

也许这就是为什么在存在可中断的 ffi 调用时正确处理 SIGINT 需要-threaded:否则,将阻止引发异步异常的线程运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 2016-07-06
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多