module System.Semaphore
(
ClientSemaphore, ServerSemaphore
, serverClientSemaphore
, SemaphoreName(..)
, clientSemaphoreName
, SemaphoreIdentifier
, semaphoreIdentifier
, createSemaphore, freshSemaphore
, SemaphoreToken
, openSemaphore
, parseSemaphoreIdentifier
, SemaphoreProtocolVersion(..)
, semaphoreVersion
, versionsAreCompatible
, SemaphoreError(..)
, waitOnSemaphore, tryWaitOnSemaphore
, withSemaphoreToken
, getSemaphoreValue
, releaseSemaphoreToken
, destroyClientSemaphore, destroyServerSemaphore
, AbstractSem(..)
, withAbstractSem
) where
import Control.Exception ( bracket, bracket_ )
import Data.List.NonEmpty ( NonEmpty(..) )
import System.Semaphore.Internal
import System.Semaphore.Internal.Version
versionsAreCompatible :: SemaphoreProtocolVersion -> SemaphoreProtocolVersion -> Bool
versionsAreCompatible :: SemaphoreProtocolVersion -> SemaphoreProtocolVersion -> Bool
versionsAreCompatible SemaphoreProtocolVersion
a SemaphoreProtocolVersion
b =
SemaphoreProtocolVersion
a SemaphoreProtocolVersion -> SemaphoreProtocolVersion -> Bool
forall a. Eq a => a -> a -> Bool
== SemaphoreProtocolVersion
b
createSemaphore :: String
-> Int
-> IO (Either SemaphoreError ServerSemaphore)
createSemaphore :: String -> Int -> IO (Either SemaphoreError ServerSemaphore)
createSemaphore String
label Int
init_toks = do
let sem_nm :: SemaphoreName
sem_nm = SemaphoreName
{ semaphoreProtocolVersion :: SemaphoreProtocolVersion
semaphoreProtocolVersion = SemaphoreProtocolVersion
semaphoreVersion
, unversionedSemaphoreNameString :: String
unversionedSemaphoreNameString = String
label
}
SemaphoreName -> Int -> IO (Either SemaphoreError ServerSemaphore)
create_sem SemaphoreName
sem_nm Int
init_toks
freshSemaphore :: String
-> Int
-> IO (Either SemaphoreError ServerSemaphore)
freshSemaphore :: String -> Int -> IO (Either SemaphoreError ServerSemaphore)
freshSemaphore String
prefix Int
init_toks = do
Int
seed <- IO Int
get_time_seed
Int
-> NonEmpty String -> IO (Either SemaphoreError ServerSemaphore)
go Int
0 (Int -> NonEmpty String
seedStrings Int
seed)
where
go :: Int -> NonEmpty String -> IO (Either SemaphoreError ServerSemaphore)
go :: Int
-> NonEmpty String -> IO (Either SemaphoreError ServerSemaphore)
go Int
i (String
suffix :| [String]
suffs) = do
let sem_str :: String
sem_str = String
prefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
suffix
sem_nm :: SemaphoreName
sem_nm = SemaphoreName
{ semaphoreProtocolVersion :: SemaphoreProtocolVersion
semaphoreProtocolVersion = SemaphoreProtocolVersion
semaphoreVersion
, unversionedSemaphoreNameString :: String
unversionedSemaphoreNameString = String
sem_str
}
Either SemaphoreError ServerSemaphore
mb_sem <- SemaphoreName -> Int -> IO (Either SemaphoreError ServerSemaphore)
create_sem SemaphoreName
sem_nm Int
init_toks
case Either SemaphoreError ServerSemaphore
mb_sem of
Right ServerSemaphore
sem -> Either SemaphoreError ServerSemaphore
-> IO (Either SemaphoreError ServerSemaphore)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ServerSemaphore -> Either SemaphoreError ServerSemaphore
forall a b. b -> Either a b
Right ServerSemaphore
sem)
Left SemaphoreError
err
| String
next : [String]
nexts <- [String]
suffs
, Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
32
-> Int
-> NonEmpty String -> IO (Either SemaphoreError ServerSemaphore)
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (String
next String -> [String] -> NonEmpty String
forall a. a -> [a] -> NonEmpty a
:| [String]
nexts)
| Bool
otherwise
-> Either SemaphoreError ServerSemaphore
-> IO (Either SemaphoreError ServerSemaphore)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (SemaphoreError -> Either SemaphoreError ServerSemaphore
forall a b. a -> Either a b
Left SemaphoreError
err)
openSemaphore :: SemaphoreIdentifier -> IO (Either SemaphoreError ClientSemaphore)
openSemaphore :: String -> IO (Either SemaphoreError ClientSemaphore)
openSemaphore String
ident =
case String -> Maybe SemaphoreName
parseSemaphoreIdentifier String
ident of
Maybe SemaphoreName
Nothing
| SemaphoreProtocolVersion -> SemaphoreProtocolVersion -> Bool
versionsAreCompatible SemaphoreProtocolVersion
v1 SemaphoreProtocolVersion
semaphoreVersion ->
SemaphoreName -> IO (Either SemaphoreError ClientSemaphore)
open_sem_raw (SemaphoreName { semaphoreProtocolVersion :: SemaphoreProtocolVersion
semaphoreProtocolVersion = SemaphoreProtocolVersion
v1
, unversionedSemaphoreNameString :: String
unversionedSemaphoreNameString = String
ident })
| Bool
otherwise ->
Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore))
-> Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore)
forall a b. (a -> b) -> a -> b
$ SemaphoreError -> Either SemaphoreError ClientSemaphore
forall a b. a -> Either a b
Left (SemaphoreError -> Either SemaphoreError ClientSemaphore)
-> SemaphoreError -> Either SemaphoreError ClientSemaphore
forall a b. (a -> b) -> a -> b
$ SemaphoreProtocolVersion -> SemaphoreError
semVerError SemaphoreProtocolVersion
v1
Just SemaphoreName
nm
| Bool -> Bool
not (SemaphoreProtocolVersion -> SemaphoreProtocolVersion -> Bool
versionsAreCompatible (SemaphoreName -> SemaphoreProtocolVersion
semaphoreProtocolVersion SemaphoreName
nm) SemaphoreProtocolVersion
semaphoreVersion) ->
Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore))
-> Either SemaphoreError ClientSemaphore
-> IO (Either SemaphoreError ClientSemaphore)
forall a b. (a -> b) -> a -> b
$ SemaphoreError -> Either SemaphoreError ClientSemaphore
forall a b. a -> Either a b
Left (SemaphoreError -> Either SemaphoreError ClientSemaphore)
-> SemaphoreError -> Either SemaphoreError ClientSemaphore
forall a b. (a -> b) -> a -> b
$ SemaphoreProtocolVersion -> SemaphoreError
semVerError (SemaphoreName -> SemaphoreProtocolVersion
semaphoreProtocolVersion SemaphoreName
nm)
| Bool
otherwise ->
SemaphoreName -> IO (Either SemaphoreError ClientSemaphore)
open_sem_raw SemaphoreName
nm
where
v1 :: SemaphoreProtocolVersion
v1 = Int -> SemaphoreProtocolVersion
SemaphoreProtocolVersion Int
1
semVerError :: SemaphoreProtocolVersion -> SemaphoreError
semVerError SemaphoreProtocolVersion
ver = SemaphoreProtocolVersion
-> SemaphoreProtocolVersion -> SemaphoreError
SemaphoreIncompatibleVersion SemaphoreProtocolVersion
ver SemaphoreProtocolVersion
semaphoreVersion
withSemaphoreToken :: ClientSemaphore -> (SemaphoreToken -> IO a) -> IO a
withSemaphoreToken :: forall a. ClientSemaphore -> (SemaphoreToken -> IO a) -> IO a
withSemaphoreToken ClientSemaphore
sem = IO SemaphoreToken
-> (SemaphoreToken -> IO ()) -> (SemaphoreToken -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (HasCallStack => ClientSemaphore -> IO SemaphoreToken
ClientSemaphore -> IO SemaphoreToken
waitOnSemaphore ClientSemaphore
sem) HasCallStack => SemaphoreToken -> IO ()
SemaphoreToken -> IO ()
releaseSemaphoreToken
seedStrings :: Int -> NonEmpty String
seedStrings :: Int -> NonEmpty String
seedStrings Int
seed = (Int -> String) -> NonEmpty Int -> NonEmpty String
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ( \ Int
i -> Int -> String
iToBase62 (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
seed) ) (Int
0 Int -> [Int] -> NonEmpty Int
forall a. a -> [a] -> NonEmpty a
:| [Int
1..])
data AbstractSem =
AbstractSem
{ AbstractSem -> IO ()
acquireSem :: IO ()
, AbstractSem -> IO ()
releaseSem :: IO ()
}
withAbstractSem :: AbstractSem -> IO b -> IO b
withAbstractSem :: forall b. AbstractSem -> IO b -> IO b
withAbstractSem AbstractSem
s = IO () -> IO () -> IO b -> IO b
forall a b c. IO a -> IO b -> IO c -> IO c
bracket_ (AbstractSem -> IO ()
acquireSem AbstractSem
s) (AbstractSem -> IO ()
releaseSem AbstractSem
s)