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を受け取ったときだけのようにみえるので、ライブラリ側で変なシグナルを発生させているのかもしれません。