Убийство двоичного кода Haskell

Если я нажимаю Ctrl + C, это генерирует исключение (всегда в потоке 0?). Вы можете поймать это, если хотите, или, что более вероятно, выполнить некоторую очистку, а затем перебросить ее. Но обычный результат заключается в том, чтобы остановить программу так или иначе.

Теперь предположим, что я использую команду Unix kill. Как я понимаю, kill в основном отправляет (настраиваемый) сигнал Unix в указанный процесс.

Как реагирует на это RTS Haskell? Это где-то задокументировано? Я бы предположил, что отправка SIGTERM будет иметь тот же эффект, что и нажатие Ctrl + C, но я не знаю, что для факта...

(И, конечно, вы можете использовать kill для отправки сигналов, которые вообще не имеют никакого отношения к убийству. Опять же, я бы предположил, что RTS игнорирует, скажем, SIGHUP или SIGPWR, но Я точно не знаю.)

Ответы

Ответ 1

Поиск "сигнала" в исходный код ghc на github показал 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. Я не знаю, есть ли какие-либо другие обработчики сигналов, скрытые в исходном коде.

Ответ 2

Googling "haskell catch sigterm" привел меня к System.Posix.Signals пакета unix, который имеет довольно красивую систему для ловли и обработки этих сигналов. Просто прокрутите вниз до раздела "Обработка сигналов".

EDIT: Тривиальный пример:

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, что пришло время выйти. Я попытался использовать exitSuccess из System.Exit, но поскольку termHandler выполняется в потоке, который не является основным, он не может заставить программу выйти. Там может быть более простой способ сделать это, но я никогда не использовал этот модуль раньше, поэтому я не знаю об этом. Я тестировал это на Ubuntu 12.10.