2008-08-07 [長年日記]

[Haskell] FFIとシグナル

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

[]

トップ «前の日記(2008-08-03) 最新 次の日記(2008-08-12)»