summaryrefslogtreecommitdiff
path: root/server/src/Control/Concurrent/Delay.hs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/Control/Concurrent/Delay.hs')
-rw-r--r--server/src/Control/Concurrent/Delay.hs50
1 files changed, 50 insertions, 0 deletions
diff --git a/server/src/Control/Concurrent/Delay.hs b/server/src/Control/Concurrent/Delay.hs
new file mode 100644
index 00000000..5cc1f99a
--- /dev/null
+++ b/server/src/Control/Concurrent/Delay.hs
@@ -0,0 +1,50 @@
1{-# LANGUAGE NondecreasingIndentation #-}
2module Control.Concurrent.Delay where
3
4import Control.Concurrent
5import Control.Monad
6import Control.Exception ({-evaluate,-}handle,finally,throwIO)
7import Data.Time.Clock (NominalDiffTime)
8import System.IO.Error
9
10type Microseconds = Int
11
12microseconds :: NominalDiffTime -> Microseconds
13microseconds d = round $ 1000000 * d
14
15data InterruptibleDelay = InterruptibleDelay
16 { delayThread :: MVar ThreadId
17 }
18
19interruptibleDelay :: IO InterruptibleDelay
20interruptibleDelay = do
21 fmap InterruptibleDelay newEmptyMVar
22
23-- | Delay for the given number of microseconds and return 'True' if the delay
24-- is not interrupted.
25--
26-- Note: If a thread is already waiting on the given 'InterruptibleDelay'
27-- object, then this will block until it becomes available and only then start
28-- the delay timer.
29startDelay :: InterruptibleDelay -> Microseconds -> IO Bool
30startDelay d interval = do
31 thread <- myThreadId
32 handle (\e -> do when (not $ isUserError e) (throwIO e)
33 return False) $ do
34 putMVar (delayThread d) thread
35 threadDelay interval
36 void $ takeMVar (delayThread d)
37 return True
38 -- The following cleanup shouldn't be necessary, but I'm paranoid.
39 `finally` tryTakeMVar (delayThread d)
40
41 where debugNoise str = return ()
42
43-- | Signal the thread waiting on the given 'InterruptibleDelay' object to
44-- continue even though the timeout has not elapsed. If no thread is waiting,
45-- then this is a no-op.
46interruptDelay :: InterruptibleDelay -> IO ()
47interruptDelay d = do
48 mthread <- tryTakeMVar (delayThread d)
49 forM_ mthread $ \thread -> do
50 throwTo thread (userError "Interrupted delay")