16

如果我按 Ctrl+C,这会引发异常(总是在线程 0 中?)。如果你愿意,你可以抓住它——或者更有可能的是,运行一些清理然后重新抛出它。但通常的结果是使程序以一种或另一种方式停止。

现在假设我使用 Unixkill命令。据我了解,kill基本上是向指定进程发送一个(可配置的)Unix 信号。

Haskell RTS 对此有何反应?它是否记录在某处?我想发送SIGTERM按 Ctrl+C 的效果相同,但我不知道事实上...

(当然,您可以使用它kill来发送与杀戮无关的信号。同样,我想RTS会忽略,比如说,SIGHUPSIGPWR,但我不确定。)

4

2 回答 2

17

谷歌搜索“haskell catch sigterm”让我找到System.Posix.Signals了这个unix包,它有一个相当漂亮的系统来捕捉和处理这些信号。只需向下滚动到“处理信号”部分。

编辑: 一个简单的例子:

import System.Posix.Signals
import Control.Concurrent (threadDelay)
import Control.Concurrent.MVar

termHandler :: MVar () -> Handler
termHandler v = CatchOnce $ do
    putStrLn "Caught SIGTERM"
    putMVar v ()

loop :: MVar () -> IO ()
loop v = do
    putStrLn "Still running"
    threadDelay 1000000
    val <- tryTakeMVar v
    case val of
        Just _ -> putStrLn "Quitting" >> return ()
        Nothing -> loop v

main = do
    v <- newEmptyMVar
    installHandler sigTERM (termHandler v) Nothing
    loop v

请注意,我必须使用 MVar 来通知loop是时候退出了。我尝试使用exitSuccessfrom System.Exit,但由于termHandler在不是主线程的线程中执行,它不会导致程序退出。可能有一种更简单的方法可以做到这一点,但我以前从未使用过这个模块,所以我不知道有一个。我在 Ubuntu 12.10 上对此进行了测试。

于 2013-08-25T15:57:04.607 回答
13

在 github 上的ghc 源代码中搜索“信号”会发现installDefaultSignals函数:

void
initDefaultHandlers(void)
{
    struct sigaction action,oact;

    // install the SIGINT handler
    action.sa_handler = shutdown_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    if (sigaction(SIGINT, &action, &oact) != 0) {
sysErrorBelch("warning: failed to install SIGINT handler");
    }

#if defined(HAVE_SIGINTERRUPT)
    siginterrupt(SIGINT, 1);    // isn't this the default? --SDM
#endif

    // install the SIGFPE handler

    // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
    // Apparently IEEE requires floating-point exceptions to be ignored by
    // default, but alpha-dec-osf3 doesn't seem to do so.

    // Commented out by SDM 2/7/2002: this causes an infinite loop on
    // some architectures when an integer division by zero occurs: we
    // don't recover from the floating point exception, and the
    // program just generates another one immediately.
#if 0
    action.sa_handler = SIG_IGN;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    if (sigaction(SIGFPE, &action, &oact) != 0) {
    sysErrorBelch("warning: failed to install SIGFPE handler");
}
#endif

#ifdef alpha_HOST_ARCH
    ieee_set_fp_control(0);
#endif

    // ignore SIGPIPE; see #1619
    // actually, we use an empty signal handler rather than SIG_IGN,
    // so that SIGPIPE gets reset to its default behaviour on exec.
    action.sa_handler = empty_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    if (sigaction(SIGPIPE, &action, &oact) != 0) {
sysErrorBelch("warning: failed to install SIGPIPE handler");
    }

    set_sigtstp_action(rtsTrue);
}

从那里,您可以看到 GHC 至少安装了 SIGINT 和 SIGPIPE 处理程序。我不知道源代码中是否隐藏了任何其他信号处理程序。

于 2013-08-25T17:28:58.350 回答