Пожалуйста, игнорируйте часть в кавычках и смотрите обновление ниже — я сохраняю исходное решение, не связанное с ним, из-за комментариев, связанных с ним.
Вы должны пометить import
как unsafe
, так как вы хотите, чтобы основной поток блокировался во время выполнения функции (см. комментарий @carl ниже). По умолчанию импорт является безопасным, а не unsafe
. Таким образом, изменение сигнатуры функции на это должно привести к блокировке основного потока:
foreign import ccall unsafe "wiring.h delay" c_delay :: CUInt -> IO ()
Кроме того, если вы планируете писать многопоточный код, Документы GHC для многопоточных FFI >очень полезны. Это также кажется хорошим началом.
Обновить
Похоже, такое поведение связано с обработкой сигнальных прерываний (если я правильно помню, это было добавлено в 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;
}
Хаскель-код:
{-# 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 – отключите SIGVTALRM перед вызовом кода FFI и снова включите:
Я не уверен, каковы последствия отключения SIGVTALRM. Это альтернативный подход, который отключает SIGVTALRM во время вызова FFI, если вы не можете изменить код FFI. Таким образом, код 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 ()
person
Sal
schedule
05.03.2013
usleep
, т.к. у меня нет вайринга Пи) с непотоковой РТС, для ghc‹=7.2.*, ждет пока не закончится сон. С прошитой RTS или с GHC ›= 7.4 он сразу же завершается. Вероятно, ошибка, но я не знаю, в старых GHC или в новых. - person Daniel Fischer   schedule 06.03.2013wiringPi.h
. Спасибо что подметил это. Я отредактирую исходный вопрос, чтобы отразить изменение. - person Jay   schedule 06.03.2013