{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP
, MagicHash
, UnboxedTuples
, ScopedTypeVariables
, RankNTypes
#-}
{-# OPTIONS_GHC -Wno-deprecations #-}
module Control.Concurrent (
ThreadId,
myThreadId,
forkIO,
forkFinally,
forkIOWithUnmask,
killThread,
throwTo,
forkOn,
forkOnWithUnmask,
getNumCapabilities,
setNumCapabilities,
threadCapability,
yield,
threadDelay,
threadWaitRead,
threadWaitWrite,
threadWaitReadSTM,
threadWaitWriteSTM,
module Control.Concurrent.MVar,
module Control.Concurrent.Chan,
module Control.Concurrent.QSem,
module Control.Concurrent.QSemN,
rtsSupportsBoundThreads,
forkOS,
forkOSWithUnmask,
isCurrentThreadBound,
runInBoundThread,
runInUnboundThread,
mkWeakThreadId,
) where
#if !defined(javascript_HOST_ARCH)
#define SUPPORT_BOUND_THREADS
#endif
import Control.Exception.Base as Exception
import GHC.Conc hiding (threadWaitRead, threadWaitWrite,
threadWaitReadSTM, threadWaitWriteSTM)
#if defined(SUPPORT_BOUND_THREADS)
import GHC.IO ( unsafeUnmask, catchException )
import GHC.IORef ( newIORef, readIORef, writeIORef )
import GHC.Base
import Foreign.StablePtr
import Foreign.C.Types
#endif
import System.Posix.Types ( Fd )
#if defined(mingw32_HOST_OS)
import Foreign.C
import System.IO
import Data.Functor ( void )
import Data.Int ( Int64 )
#else
import qualified GHC.Conc
#endif
import Control.Concurrent.MVar
import Control.Concurrent.Chan
import Control.Concurrent.QSem
import Control.Concurrent.QSemN
forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
forkFinally :: forall a. IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
forkFinally IO a
action Either SomeException a -> IO ()
and_then =
((forall a. IO a -> IO a) -> IO ThreadId) -> IO ThreadId
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO ThreadId) -> IO ThreadId)
-> ((forall a. IO a -> IO a) -> IO ThreadId) -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore ->
IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO a -> IO a
forall a. IO a -> IO a
restore IO a
action) IO (Either SomeException a)
-> (Either SomeException a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either SomeException a -> IO ()
and_then
#if !defined(SUPPORT_BOUND_THREADS)
forkOS :: IO () -> IO ThreadId
forkOS _ = error "forkOS not supported on this architecture"
forkOSWithUnmask :: ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId
forkOSWithUnmask _ = error "forkOS not supported on this architecture"
isCurrentThreadBound :: IO Bool
isCurrentThreadBound = pure False
runInBoundThread :: IO a -> IO a
runInBoundThread action = action
runInUnboundThread :: IO a -> IO a
runInUnboundThread action = action
rtsSupportsBoundThreads :: Bool
rtsSupportsBoundThreads = False
#else
foreign import ccall unsafe rtsSupportsBoundThreads :: Bool
forkOS :: IO () -> IO ThreadId
foreign export ccall forkOS_entry
:: StablePtr (IO ()) -> IO ()
foreign import ccall "forkOS_entry" forkOS_entry_reimported
:: StablePtr (IO ()) -> IO ()
forkOS_entry :: StablePtr (IO ()) -> IO ()
forkOS_entry :: StablePtr (IO ()) -> IO ()
forkOS_entry StablePtr (IO ())
stableAction = do
IO ()
action <- StablePtr (IO ()) -> IO (IO ())
forall a. StablePtr a -> IO a
deRefStablePtr StablePtr (IO ())
stableAction
IO ()
action
foreign import ccall forkOS_createThread
:: StablePtr (IO ()) -> IO CInt
failNonThreaded :: IO a
failNonThreaded :: forall a. IO a
failNonThreaded = String -> IO a
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO a) -> String -> IO a
forall a b. (a -> b) -> a -> b
$ String
"RTS doesn't support multiple OS threads "
String -> String -> String
forall a. [a] -> [a] -> [a]
++String
"(use ghc -threaded when linking)"
forkOS :: IO () -> IO ThreadId
forkOS IO ()
action0
| Bool
rtsSupportsBoundThreads = do
MVar ThreadId
mv <- IO (MVar ThreadId)
forall a. IO (MVar a)
newEmptyMVar
MaskingState
b <- IO MaskingState
Exception.getMaskingState
let
action1 :: IO ()
action1 = case MaskingState
b of
MaskingState
Unmasked -> IO () -> IO ()
forall a. IO a -> IO a
unsafeUnmask IO ()
action0
MaskingState
MaskedInterruptible -> IO ()
action0
MaskingState
MaskedUninterruptible -> IO () -> IO ()
forall a. IO a -> IO a
uninterruptibleMask_ IO ()
action0
action_plus :: IO ()
action_plus = IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch IO ()
action1 SomeException -> IO ()
childHandler
StablePtr (IO ())
entry <- IO () -> IO (StablePtr (IO ()))
forall a. a -> IO (StablePtr a)
newStablePtr (IO ThreadId
myThreadId IO ThreadId -> (ThreadId -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MVar ThreadId -> ThreadId -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar ThreadId
mv IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
action_plus)
CInt
err <- StablePtr (IO ()) -> IO CInt
forkOS_createThread StablePtr (IO ())
entry
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
err CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot create OS thread."
ThreadId
tid <- MVar ThreadId -> IO ThreadId
forall a. MVar a -> IO a
takeMVar MVar ThreadId
mv
StablePtr (IO ()) -> IO ()
forall a. StablePtr a -> IO ()
freeStablePtr StablePtr (IO ())
entry
ThreadId -> IO ThreadId
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ThreadId
tid
| Bool
otherwise = IO ThreadId
forall a. IO a
failNonThreaded
forkOSWithUnmask :: ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId
forkOSWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId
forkOSWithUnmask (forall a. IO a -> IO a) -> IO ()
io = IO () -> IO ThreadId
forkOS ((forall a. IO a -> IO a) -> IO ()
io IO a -> IO a
forall a. IO a -> IO a
unsafeUnmask)
isCurrentThreadBound :: IO Bool
isCurrentThreadBound :: IO Bool
isCurrentThreadBound = (State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool)
-> (State# RealWorld -> (# State# RealWorld, Bool #)) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \ State# RealWorld
s# ->
case State# RealWorld -> (# State# RealWorld, Int# #)
isCurrentThreadBound# State# RealWorld
s# of
(# State# RealWorld
s2#, Int#
flg #) -> (# State# RealWorld
s2#, Int# -> Bool
isTrue# (Int#
flg Int# -> Int# -> Int#
/=# Int#
0#) #)
runInBoundThread :: IO a -> IO a
runInBoundThread :: forall a. IO a -> IO a
runInBoundThread IO a
action
| Bool
rtsSupportsBoundThreads = do
Bool
bound <- IO Bool
isCurrentThreadBound
if Bool
bound
then IO a
action
else do
IORef (Either SomeException a)
ref <- Either SomeException a -> IO (IORef (Either SomeException a))
forall a. a -> IO (IORef a)
newIORef Either SomeException a
forall a. HasCallStack => a
undefined
let action_plus :: IO ()
action_plus = IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
Exception.try IO a
action IO (Either SomeException a)
-> (Either SomeException a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IORef (Either SomeException a) -> Either SomeException a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Either SomeException a)
ref
IO (StablePtr (IO ()))
-> (StablePtr (IO ()) -> IO ())
-> (StablePtr (IO ()) -> IO (Either SomeException a))
-> IO (Either SomeException a)
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (IO () -> IO (StablePtr (IO ()))
forall a. a -> IO (StablePtr a)
newStablePtr IO ()
action_plus)
StablePtr (IO ()) -> IO ()
forall a. StablePtr a -> IO ()
freeStablePtr
(\StablePtr (IO ())
cEntry -> StablePtr (IO ()) -> IO ()
forkOS_entry_reimported StablePtr (IO ())
cEntry IO () -> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IORef (Either SomeException a) -> IO (Either SomeException a)
forall a. IORef a -> IO a
readIORef IORef (Either SomeException a)
ref) IO (Either SomeException a)
-> (Either SomeException a -> IO a) -> IO a
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
Either SomeException a -> IO a
forall a. Either SomeException a -> IO a
unsafeResult
| Bool
otherwise = IO a
forall a. IO a
failNonThreaded
runInUnboundThread :: IO a -> IO a
runInUnboundThread :: forall a. IO a -> IO a
runInUnboundThread IO a
action = do
Bool
bound <- IO Bool
isCurrentThreadBound
if Bool
bound
then do
MVar (Either SomeException a)
mv <- IO (MVar (Either SomeException a))
forall a. IO (MVar a)
newEmptyMVar
((forall a. IO a -> IO a) -> IO a) -> IO a
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO a) -> IO a)
-> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
ThreadId
tid <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
Exception.try (IO a -> IO a
forall a. IO a -> IO a
restore IO a
action) IO (Either SomeException a)
-> (Either SomeException a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MVar (Either SomeException a) -> Either SomeException a -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either SomeException a)
mv
let wait :: IO (Either SomeException a)
wait = MVar (Either SomeException a) -> IO (Either SomeException a)
forall a. MVar a -> IO a
takeMVar MVar (Either SomeException a)
mv IO (Either SomeException a)
-> (SomeException -> IO (Either SomeException a))
-> IO (Either SomeException a)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` \(SomeException
e :: SomeException) ->
ThreadId -> SomeException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
Exception.throwTo ThreadId
tid SomeException
e IO () -> IO (Either SomeException a) -> IO (Either SomeException a)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO (Either SomeException a)
wait
IO (Either SomeException a)
wait IO (Either SomeException a)
-> (Either SomeException a -> IO a) -> IO a
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either SomeException a -> IO a
forall a. Either SomeException a -> IO a
unsafeResult
else IO a
action
unsafeResult :: Either SomeException a -> IO a
unsafeResult :: forall a. Either SomeException a -> IO a
unsafeResult = (SomeException -> IO a)
-> (a -> IO a) -> Either SomeException a -> IO a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either SomeException -> IO a
forall e a. Exception e => e -> IO a
Exception.throwIO a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
#endif
threadWaitRead :: Fd -> IO ()
threadWaitRead :: Fd -> IO ()
threadWaitRead Fd
fd
#if defined(mingw32_HOST_OS)
| Bool
threaded = IO () -> IO ()
forall a. IO a -> IO a
withThread (Fd -> Bool -> IO ()
waitFd Fd
fd Bool
False)
| Bool
otherwise = case Fd
fd of
Fd
0 -> do Bool
_ <- Handle -> Int -> IO Bool
hWaitForInput Handle
stdin (-Int
1)
() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Fd
_ -> String -> IO ()
forall a. String -> a
errorWithoutStackTrace String
"threadWaitRead requires -threaded on Windows, or use System.IO.hWaitForInput"
#else
= GHC.Conc.threadWaitRead fd
#endif
threadWaitWrite :: Fd -> IO ()
threadWaitWrite :: Fd -> IO ()
threadWaitWrite Fd
fd
#if defined(mingw32_HOST_OS)
| Bool
threaded = IO () -> IO ()
forall a. IO a -> IO a
withThread (Fd -> Bool -> IO ()
waitFd Fd
fd Bool
True)
| Bool
otherwise = String -> IO ()
forall a. String -> a
errorWithoutStackTrace String
"threadWaitWrite requires -threaded on Windows"
#else
= GHC.Conc.threadWaitWrite fd
#endif
threadWaitReadSTM :: Fd -> IO (STM (), IO ())
threadWaitReadSTM :: Fd -> IO (STM (), IO ())
threadWaitReadSTM Fd
fd
#if defined(mingw32_HOST_OS)
| Bool
threaded = do TVar (Maybe (Either IOException ()))
v <- Maybe (Either IOException ())
-> IO (TVar (Maybe (Either IOException ())))
forall a. a -> IO (TVar a)
newTVarIO Maybe (Either IOException ())
forall a. Maybe a
Nothing
IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> IO ThreadId -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do Either IOException ()
result <- IO () -> IO (Either IOException ())
forall e a. Exception e => IO a -> IO (Either e a)
try (Fd -> Bool -> IO ()
waitFd Fd
fd Bool
False)
STM () -> IO ()
forall a. STM a -> IO a
atomically (TVar (Maybe (Either IOException ()))
-> Maybe (Either IOException ()) -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar (Maybe (Either IOException ()))
v (Maybe (Either IOException ()) -> STM ())
-> Maybe (Either IOException ()) -> STM ()
forall a b. (a -> b) -> a -> b
$ Either IOException () -> Maybe (Either IOException ())
forall a. a -> Maybe a
Just Either IOException ()
result)
let waitAction :: STM ()
waitAction = do Maybe (Either IOException ())
result <- TVar (Maybe (Either IOException ()))
-> STM (Maybe (Either IOException ()))
forall a. TVar a -> STM a
readTVar TVar (Maybe (Either IOException ()))
v
case Maybe (Either IOException ())
result of
Maybe (Either IOException ())
Nothing -> STM ()
forall a. STM a
retry
Just (Right ()) -> () -> STM ()
forall a. a -> STM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (Left IOException
e) -> IOException -> STM ()
forall e a. Exception e => e -> STM a
throwSTM (IOException
e :: IOException)
let killAction :: IO ()
killAction = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
(STM (), IO ()) -> IO (STM (), IO ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (STM ()
waitAction, IO ()
killAction)
| Bool
otherwise = String -> IO (STM (), IO ())
forall a. String -> a
errorWithoutStackTrace String
"threadWaitReadSTM requires -threaded on Windows"
#else
= GHC.Conc.threadWaitReadSTM fd
#endif
threadWaitWriteSTM :: Fd -> IO (STM (), IO ())
threadWaitWriteSTM :: Fd -> IO (STM (), IO ())
threadWaitWriteSTM Fd
fd
#if defined(mingw32_HOST_OS)
| Bool
threaded = do TVar (Maybe (Either IOException ()))
v <- Maybe (Either IOException ())
-> IO (TVar (Maybe (Either IOException ())))
forall a. a -> IO (TVar a)
newTVarIO Maybe (Either IOException ())
forall a. Maybe a
Nothing
IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> IO ThreadId -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do Either IOException ()
result <- IO () -> IO (Either IOException ())
forall e a. Exception e => IO a -> IO (Either e a)
try (Fd -> Bool -> IO ()
waitFd Fd
fd Bool
True)
STM () -> IO ()
forall a. STM a -> IO a
atomically (TVar (Maybe (Either IOException ()))
-> Maybe (Either IOException ()) -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar (Maybe (Either IOException ()))
v (Maybe (Either IOException ()) -> STM ())
-> Maybe (Either IOException ()) -> STM ()
forall a b. (a -> b) -> a -> b
$ Either IOException () -> Maybe (Either IOException ())
forall a. a -> Maybe a
Just Either IOException ()
result)
let waitAction :: STM ()
waitAction = do Maybe (Either IOException ())
result <- TVar (Maybe (Either IOException ()))
-> STM (Maybe (Either IOException ()))
forall a. TVar a -> STM a
readTVar TVar (Maybe (Either IOException ()))
v
case Maybe (Either IOException ())
result of
Maybe (Either IOException ())
Nothing -> STM ()
forall a. STM a
retry
Just (Right ()) -> () -> STM ()
forall a. a -> STM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (Left IOException
e) -> IOException -> STM ()
forall e a. Exception e => e -> STM a
throwSTM (IOException
e :: IOException)
let killAction :: IO ()
killAction = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
(STM (), IO ()) -> IO (STM (), IO ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (STM ()
waitAction, IO ()
killAction)
| Bool
otherwise = String -> IO (STM (), IO ())
forall a. String -> a
errorWithoutStackTrace String
"threadWaitWriteSTM requires -threaded on Windows"
#else
= GHC.Conc.threadWaitWriteSTM fd
#endif
#if defined(mingw32_HOST_OS)
foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
withThread :: IO a -> IO a
withThread :: forall a. IO a -> IO a
withThread IO a
io = do
MVar (Either IOException a)
m <- IO (MVar (Either IOException a))
forall a. IO (MVar a)
newEmptyMVar
ThreadId
_ <- IO ThreadId -> IO ThreadId
forall a. IO a -> IO a
mask_ (IO ThreadId -> IO ThreadId) -> IO ThreadId -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ IO a -> IO (Either IOException a)
forall e a. Exception e => IO a -> IO (Either e a)
try IO a
io IO (Either IOException a)
-> (Either IOException a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MVar (Either IOException a) -> Either IOException a -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either IOException a)
m
Either IOException a
x <- MVar (Either IOException a) -> IO (Either IOException a)
forall a. MVar a -> IO a
takeMVar MVar (Either IOException a)
m
case Either IOException a
x of
Right a
a -> a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
Left IOException
e -> IOException -> IO a
forall e a. Exception e => e -> IO a
throwIO (IOException
e :: IOException)
waitFd :: Fd -> Bool -> IO ()
waitFd :: Fd -> Bool -> IO ()
waitFd Fd
fd Bool
write = do
String -> IO CInt -> IO ()
forall a. (Eq a, Num a) => String -> IO a -> IO ()
throwErrnoIfMinus1_ String
"fdReady" (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$
CInt -> CBool -> Int64 -> CBool -> IO CInt
fdReady (Fd -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Fd
fd) (if Bool
write then CBool
1 else CBool
0) (-Int64
1) CBool
0
foreign import ccall safe "fdReady"
fdReady :: CInt -> CBool -> Int64 -> CBool -> IO CInt
#endif