SIGALRMシグナルを使っているライブラリをFFIで呼び出すと、コールバックのスタブの中でInterruptedというメッセージを出してプロセスが落ちてしまうことがあるので、テストコードを書いて調べてみました。
alarm.h
void test();
alarm.c
#include <signal.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include "alarm.h" int g_count = 0; void handler(int n) { ++g_count; alarm(1); } typedef void (*callback)(int); void test(callback f) { struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = handler; sigemptyset(&action.sa_mask); sigaction(SIGALRM, &action, 0); alarm(1); while (getchar() != 'q') { f(g_count); } }
Alarm.hs
{-# LANGUAGE ForeignFunctionInterface #-} {-# INCLUDE "alarm.h" #-} module Main (main) where import Foreign.C.Types import Foreign.Ptr main :: IO () main = do c <- wrapCallback callback test c freeHaskellFunPtr c callback :: CInt -> IO () callback n = do putStrLn $ "Haskell: " ++ show n mapM_ return [1..10000000] foreign import ccall "test" test :: FunPtr (CInt -> IO ()) -> IO () foreign import ccall "wrapper" wrapCallback :: (CInt -> IO ()) -> IO (FunPtr (CInt -> IO ()))
これを、
ghc --make Alarm.hs alarm.c
でビルドして実験して見ましたが、コールバック中にシグナルが発生しても特に問題はないようで、見込み違いっぽいです。GHCのRTSのソースをちょっと追ってみた感じだと、Interruptedでプロセスが死ぬのは、SIGINTを受け取ったときだけのようにみえるので、ライブラリ側で変なシグナルを発生させているのかもしれません。