ブロック引用の部分を無視して、以下の更新を参照してください。コメントが関連付けられているため、元の非解決策を保持しています。
関数の実行中にメインスレッドをブロックしたいので、 import
asをマークする必要があります (以下の @carl によるコメントを参照してください)。unsafe
デフォルトでは、インポートは安全であり、安全ではありませんunsafe
。したがって、関数シグネチャを次のように変更すると、メイン スレッドがブロックされます。
foreign import ccall unsafe "wiring.h delay" c_delay :: CUInt -> IO ()
また、マルチスレッドコードを書くつもりなら、マルチスレッド FFI の GHC ドキュメントはとても役に立ちます。これも良いスターターのようです。
アップデート
この動作は、シグナル割り込み処理によるものと思われます (私の記憶が正しければ、これはいくつかのバグを修正するために GHC 7.4+ で追加されました)。詳細はこちら:
http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals
上記のページのコメントに注意してください: Signal handling differs between the threaded version of the runtime and the non-threaded version
.
アプローチ 1 - FFI コードでシグナル割り込みを処理する: スリープ状態で割り込みを処理するおもちゃのコードを以下に示します。Linux 2.6.18 と ghc 7.6.1 でテストしました。
C コード:
/** ctest.c **/
#include <unistd.h>
#include <stdio.h>
#include <time.h>
unsigned delay(unsigned sec)
{
struct timespec req={0};
req.tv_sec = sec;
req.tv_nsec = 0;
while (nanosleep(&req, &req) == -1) {
printf("Got interrupt, continuing\n");
continue;
}
return 1;
}
Haskell コード:
{-# LANGUAGE ForeignFunctionInterface #-}
-- Filename Test.hs
module Main (main) where
import Foreign.C.Types
foreign import ccall safe "delay" delay :: CUInt -> IO CUInt
main = do
putStrLn "Sleeping"
n <- delay 2000
putStrLn $ "Got return code from sleep: " ++ show n
現在、ghc 7.6.1 (コマンド: ghc Test.hs ctest.c
) でコンパイルした後、スリープが終了するまで待機し、スリープ中に割り込み信号を受け取るたびにメッセージを出力します。
./Test
Sleeping
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
....
....
Got return code from sleep: 1
アプローチ 2 - FFI コードを呼び出す前に SIGVTALRM を無効にし、再度有効にします。
SIGVTALRM を無効にすることの意味がわかりません。これは、FFI コードを変更できない場合に、FFI 呼び出し中に SIGVTALRM を無効にする代替アプローチです。そのため、スリープ中に FFI コードが中断されることはありません (中断を引き起こしているのが SIGVTALRM であると仮定します)。
{-# LANGUAGE ForeignFunctionInterface #-}
-- Test.hs
module Main (main) where
import Foreign.C.Types
import System.Posix.Signals
foreign import ccall safe "delay" delay :: CUInt -> IO CUInt
main = do
putStrLn "Sleeping"
-- Block SIGVTALRM temporarily to avoid interrupts while sleeping
blockSignals $ addSignal sigVTALRM emptySignalSet
n <- delay 2
putStrLn $ "Got return code from sleep: " ++ show n
-- Unblock SIGVTALRM
unblockSignals $ addSignal sigVTALRM emptySignalSet
return ()