5

delayタイプで呼び出されるwireingPi 'C'ライブラリに関数があります

void delay(unsigned int howLong);

howLongこの関数は、コードの実行をミリ秒遅らせます。この関数を呼び出せるように、haskell でバインド コードを書きました。Haskellコードは次のとおりです。

foreign import ccall "wiringPi.h delay" c_delay :: CUInt -> IO ()
hdelay :: Int -> IO ()
hdelay howlong = c_delay (fromIntegral howlong)

この後、この関数を呼び出す簡単な haskell プログラムを作成しました。単純な Haskell コードは次のとおりです。

--私が行った関連ライブラリをインポートした後

main = wiringPiSetup
    >> delay 5000

しかし、遅延は発生せず、ghc コンパイラによって生成された実行可能ファイルはすぐに終了します。

誰かがここで何がうまくいかないのか教えてもらえますか? 正しい方向への小さな微調整が役立ちます。

乾杯とよろしく。

4

1 に答える 1

2

ブロック引用の部分を無視して、以下の更新を参照してください。コメントが関連付けられているため、元の非解決策を保持しています。

関数の実行中にメインスレッドをブロックしたいので、 importasをマークする必要があります (以下の @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 ()
于 2013-03-05T15:24:53.923 に答える