{-# LINE 1 "src/Data/Number/Flint/ThreadPool/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.ThreadPool.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.ThreadPool.FFI (
  -- * Thread pool
    ThreadPool (..)
  , CThreadPool (..)
  , ThreadPoolHandle (..)
  , CThreadPoolHandle (..)
  -- * Thread pool functions
  , thread_pool_init
  , thread_pool_get_size
  , thread_pool_set_size
  , thread_pool_request
  , thread_pool_wake
  , thread_pool_wait
  , thread_pool_give_back
  , thread_pool_clear
) where

-- thread pool -----------------------------------------------------------------

import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr ( Ptr, FunPtr, plusPtr )
import Foreign.Storable
import Foreign.Marshal ( free )

import Data.Number.Flint.Flint
import Data.Number.Flint.Fmpz
import Data.Number.Flint.Fmpq




-- thread_pool_t ---------------------------------------------------------------

data ThreadPool = ThreadPool {-# UNPACK #-} !(ForeignPtr CThreadPool)
type CThreadPool = CFlint ThreadPool

instance Storable CThreadPool where
  {-# INLINE sizeOf #-}
  sizeOf :: CThreadPool -> Int
sizeOf CThreadPool
_ = (Int
80)
{-# LINE 48 "src/Data/Number/Flint/ThreadPool/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CThreadPool -> Int
alignment CThreadPool
_ = Int
8
{-# LINE 50 "src/Data/Number/Flint/ThreadPool/FFI.hsc" #-}
  peek = undefined
  poke :: Ptr CThreadPool -> CThreadPool -> IO ()
poke = Ptr CThreadPool -> CThreadPool -> IO ()
forall a. HasCallStack => a
undefined

newThreadPool :: CLong -> IO ThreadPool
newThreadPool CLong
size = do
  ForeignPtr CThreadPool
x <- IO (ForeignPtr CThreadPool)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CThreadPool -> (Ptr CThreadPool -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CThreadPool
x ((Ptr CThreadPool -> IO ()) -> IO ())
-> (Ptr CThreadPool -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CThreadPool
x -> Ptr CThreadPool -> CLong -> IO ()
thread_pool_init Ptr CThreadPool
x CLong
size
  FinalizerPtr CThreadPool -> ForeignPtr CThreadPool -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CThreadPool
p_thread_pool_clear ForeignPtr CThreadPool
x
  ThreadPool -> IO ThreadPool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ThreadPool -> IO ThreadPool) -> ThreadPool -> IO ThreadPool
forall a b. (a -> b) -> a -> b
$ ForeignPtr CThreadPool -> ThreadPool
ThreadPool ForeignPtr CThreadPool
x

{-# INLINE withThreadPool #-}
withThreadPool :: ThreadPool -> (Ptr CThreadPool -> IO a) -> IO (ThreadPool, a)
withThreadPool (ThreadPool ForeignPtr CThreadPool
x) Ptr CThreadPool -> IO a
f = do
  ForeignPtr CThreadPool
-> (Ptr CThreadPool -> IO (ThreadPool, a)) -> IO (ThreadPool, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CThreadPool
x ((Ptr CThreadPool -> IO (ThreadPool, a)) -> IO (ThreadPool, a))
-> (Ptr CThreadPool -> IO (ThreadPool, a)) -> IO (ThreadPool, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CThreadPool
px -> Ptr CThreadPool -> IO a
f Ptr CThreadPool
px IO a -> (a -> IO (ThreadPool, a)) -> IO (ThreadPool, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ThreadPool, a) -> IO (ThreadPool, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((ThreadPool, a) -> IO (ThreadPool, a))
-> (a -> (ThreadPool, a)) -> a -> IO (ThreadPool, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CThreadPool -> ThreadPool
ThreadPool ForeignPtr CThreadPool
x,)

-- thread_pool_handle_t --------------------------------------------------------

data ThreadPoolHandle = ThreadPoolHandle {-# UNPACK #-} !(ForeignPtr CThreadPoolHandle)
type CThreadPoolHandle = CFlint ThreadPoolHandle

-- Thread pool -----------------------------------------------------------------

-- | /thread_pool_init/ /T/ /size/ 
-- 
-- Initialise @T@ and create @size@ sleeping threads that are available to
-- work. If @size \\le 0@ no threads are created and future calls to
-- @thread_pool_request@ will return \(0\) (unless @thread_pool_set_size@
-- has been called).
foreign import ccall "flint/thread_pool.h thread_pool_init"
  thread_pool_init :: Ptr CThreadPool -> CLong -> IO ()

-- | /thread_pool_get_size/ /T/ 
-- 
-- Return the number of threads in @T@.
foreign import ccall "flint/thread_pool.h thread_pool_get_size"
  thread_pool_get_size :: Ptr CThreadPool -> IO CLong

-- | /thread_pool_set_size/ /T/ /new_size/ 
-- 
-- If all threads in @T@ are in the available state, resize @T@ and return
-- 1. Otherwise, return @0@.
foreign import ccall "flint/thread_pool.h thread_pool_set_size"
  thread_pool_set_size :: Ptr CThreadPool -> CLong -> IO CInt

-- | /thread_pool_request/ /T/ /out/ /requested/ 
-- 
-- Put at most @requested@ threads in the unavailable state and return
-- their handles. The handles are written to @out@ and the number of
-- handles written is returned. These threads must be released by a call to
-- @thread_pool_give_back@.
foreign import ccall "flint/thread_pool.h thread_pool_request"
  thread_pool_request :: Ptr CThreadPool -> Ptr CThreadPoolHandle -> CLong -> IO CLong

-- | /thread_pool_wake/ /T/ /i/ /max_workers/ /f/ /a/ 
-- 
-- Wake up a sleeping thread @i@ and have it work on @f(a)@. The thread
-- being woken will be allowed to start @max_workers@ additional worker
-- threads. Usually this value should be set to @0@.
foreign import ccall "flint/thread_pool.h thread_pool_wake"
  thread_pool_wake :: Ptr CThreadPool -> Ptr CThreadPoolHandle -> CInt -> FunPtr (Ptr () -> IO ())  -> Ptr () -> IO ()

-- | /thread_pool_wait/ /T/ /i/ 
-- 
-- Wait for thread @i@ to finish working and go back to sleep.
foreign import ccall "flint/thread_pool.h thread_pool_wait"
  thread_pool_wait :: Ptr CThreadPool -> Ptr CThreadPoolHandle -> IO ()

-- | /thread_pool_give_back/ /T/ /i/ 
-- 
-- Put thread @i@ back in the available state. This thread should be
-- sleeping when this function is called.
foreign import ccall "flint/thread_pool.h thread_pool_give_back"
  thread_pool_give_back :: Ptr CThreadPool -> Ptr CThreadPoolHandle -> IO ()

-- | /thread_pool_clear/ /T/ 
-- 
-- Release any resources used by @T@. All threads should be given back
-- before this function is called.
foreign import ccall "flint/thread_pool.h thread_pool_clear"
  thread_pool_clear :: Ptr CThreadPool -> IO ()

foreign import ccall "flint/thread_pool.h &thread_pool_clear"
  p_thread_pool_clear :: FunPtr (Ptr CThreadPool -> IO ())