time-manager 0.3.1 → 0.3.1.1
raw patch · 5 files changed
+110/−46 lines, 5 files
Files
- ChangeLog.md +25/−17
- README.md +13/−0
- System/ThreadManager.hs +69/−28
- System/TimeManager.hs +1/−0
- time-manager.cabal +2/−1
ChangeLog.md view
@@ -1,29 +1,37 @@ # ChangeLog for time-manager +## 0.3.1.1++* Added `README.md` file and improved documentation of modules and functions.+ [#1057](https://github.com/yesodweb/wai/pull/1057)+ ## 0.3.1 BUGFIXES: -* `resume` now acts as a `tickle` if the `Handle` isn't paused.- This is the same behaviour as before version `0.3.0`.-* `registerKillThread` now throws the `TimeoutThread` in a separate- thread, so as to not block the GHC's System TimerManager.- This does mean that `TimeoutThread` exceptions could technically- be thrown "out of order", but they will be more prompt.+* [#1055](https://github.com/yesodweb/wai/pull/1055)+ * `resume` now acts as a `tickle` if the `Handle` isn't paused.+ This is the same behaviour as before version `0.3.0`.+ * `registerKillThread` now throws the `TimeoutThread` in a separate+ thread, so as to not block the GHC's System TimerManager.+ This does mean that `TimeoutThread` exceptions could technically+ be thrown "out of order", but they will be more prompt. + ## 0.3.0 -* New architecture. The backend is switched from the designated thread- to GHC's System TimerManager. From this version, this library is- just wrapper APIs of GHC's System TimerManager. Unlike v0.2 or- earlier, callbacks are executed at the exact time. System- TimerManager uses a PSQ (a tree) while v0.2 or earlier uses a list.- So, this version hopefully scales better.-* Deprecated functions: `stopManager`, `killManager` and `withManager'`.-* `tickle` sets the specified timeout from now.-* `pause` is now identical to `cancel`.-* `resume` is now re-registration of timeout.-* The signature of `withHandle` is changed.+* [#1048](https://github.com/yesodweb/wai/pull/1048)+ * New architecture. The backend is switched from the designated thread+ to GHC's System TimerManager. From this version, this library is+ just wrapper APIs of GHC's System TimerManager. Unlike v0.2 or+ earlier, callbacks are executed at the exact time. System+ TimerManager uses a PSQ (a tree) while v0.2 or earlier uses a list.+ So, this version hopefully scales better.+ * Deprecated functions: `stopManager`, `killManager` and `withManager'`.+ * `tickle` sets the specified timeout from now.+ * `pause` is now identical to `cancel`.+ * `resume` is now re-registration of timeout.+ * The signature of `withHandle` is changed. ## 0.2.4
+ README.md view
@@ -0,0 +1,13 @@+## time-manager++This package provides module to let you run actions with resettable timeouts+(i.e. `System.TimeManager`) and run actions that will make sure that all+threads forked with the given `ThreadManager` will be killed when the action+finishes.++## WARNINGS++Since version `0.3.0`, **the timeout manager relies on GHC internals**.+This change also means that using **this package only works with the threaded**+**runtime**. The moment a timeout is registered on a non-threaded runtime, an+exception will be thrown.
System/ThreadManager.hs view
@@ -4,6 +4,17 @@ -- | A thread manager including a time manager. -- The manager has responsibility to kill managed threads.+--+-- Because this is based on the accompanying "System.TimeManager" module,+-- the same caveats apply:+--+-- * Only works for GHC.+-- * Only works with a threaded runtime.+-- * Users of older versions should check the current semantics.+-- * Using 32-bit systems means the max timeout is @'maxBound' :: Int@+-- (2147483647) microseconds, which is less than 36 minutes.+-- * Using the same 'Handle' in different threads might cause issues in some+-- edge cases. (i.e. using cancel/pause in one thread, and resume in another) module System.ThreadManager ( ThreadManager, newThreadManager,@@ -36,7 +47,7 @@ import qualified Control.Exception as E import Control.Monad (unless, void) import Data.Foldable (forM_)-import Data.IORef+import Data.IORef (IORef, atomicModifyIORef', newIORef) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Word (Word64)@@ -65,10 +76,12 @@ ---------------------------------------------------------------- --- | Starting a thread manager.--- Its action is initially set to 'return ()' and should be set--- by 'setAction'. This allows that the action can include--- the manager itself.+-- | Create a thread manager.+--+-- To create a 'ThreadManager', you will first have to create a+-- 'T.Manager' from the "System.TimeManager" module.+--+-- You can use either 'System.TimeManager.initialize' or 'System.TimeManager.withManager'. newThreadManager :: T.Manager -> IO ThreadManager newThreadManager timmgr = ThreadManager timmgr <$> newTVarIO Map.empty @@ -84,6 +97,10 @@ -- | Stopping the manager. --+-- @+-- stopAfter threadManager action cleanup+-- @+-- -- The action is run in the scope of an exception handler that catches all -- exceptions (including asynchronous ones); this allows the cleanup handler -- to cleanup in all circumstances. If an exception is caught, it is rethrown@@ -123,14 +140,25 @@ -- | Like 'forkManaged', but run action with exceptions masked forkManagedUnmask- :: ThreadManager -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO ()+ :: ThreadManager+ -> String+ -- ^ Thread name+ -> ((forall x. IO x -> IO x) -> IO ())+ -- ^ Action with unmask argument+ -> IO () forkManagedUnmask (ThreadManager _timmgr var) label io = void $ E.mask_ $ forkIOWithUnmask $ \unmask -> E.handle ignore $ do labelMe label E.bracket (setup var) (clear var) $ \_ -> io unmask -- | Fork a managed thread with a handle created by a timeout manager.-forkManagedTimeout :: ThreadManager -> String -> (T.Handle -> IO ()) -> IO ()+forkManagedTimeout+ :: ThreadManager+ -> String+ -- ^ Thread name+ -> (T.Handle -> IO ())+ -- ^ Action with timeout handle+ -> IO () forkManagedTimeout (ThreadManager timmgr var) label io = void $ forkIO $ do labelMe label@@ -140,26 +168,37 @@ ex = KilledByThreadManager Nothing -- | Fork a managed thread with a cleanup function.-forkManagedFinally :: ThreadManager -> String -> IO () -> IO () -> IO ()-forkManagedFinally mgr label io final = E.mask $ \restore ->- forkManaged- mgr- label- (E.try (restore io) >>= \(_ :: Either E.SomeException ()) -> final)+forkManagedFinally+ :: ThreadManager+ -> String+ -- ^ Thread name+ -> IO ()+ -- ^ Action+ -> IO ()+ -- ^ Cleanup function+ -> IO ()+forkManagedFinally mgr label io final =+ forkManagedUnmask mgr label $ \restore ->+ E.try (restore io) >>= \(_ :: Either E.SomeException ()) -> final -- | Fork a managed thread with a handle created by a timeout manager -- and with a cleanup function. forkManagedTimeoutFinally- :: ThreadManager -> String -> (T.Handle -> IO ()) -> IO () -> IO ()+ :: ThreadManager+ -> String+ -- ^ Thread name+ -> (T.Handle -> IO ())+ -- ^ Action with timeout handle+ -> IO ()+ -- ^ Cleanup function+ -> IO () forkManagedTimeoutFinally mgr label io final = E.mask $ \restore ->- forkManagedTimeout- mgr- label- (\th -> E.try (restore $ io th) >>= \(_ :: Either E.SomeException ()) -> final)+ forkManagedTimeout mgr label $ \th ->+ E.try (restore $ io th) >>= \(_ :: Either E.SomeException ()) -> final setup :: TVar (Map Key ManagedThread) -> IO (Key, Weak ThreadId, IORef Bool) setup var = do- (wtid, n) <- myWeakThradId+ (wtid, n) <- myWeakThreadId ref <- newIORef False let ent = ManagedThread wtid ref -- asking to throw KilledByThreadManager to me@@ -184,21 +223,21 @@ ignore :: KilledByThreadManager -> IO () ignore (KilledByThreadManager _) = return () --- | Wait until all managed thread are finished.+-- | Wait until all managed threads are finished. waitUntilAllGone :: ThreadManager -> IO ()-waitUntilAllGone (ThreadManager _timmgr var) = atomically $ do- m <- readTVar var- check (Map.size m == 0)+waitUntilAllGone tm =+ atomically $+ isAllGone tm >>= check +-- | STM action that checks if all managed threads are finished. isAllGone :: ThreadManager -> STM Bool-isAllGone (ThreadManager _timmgr var) = do- m <- readTVar var- return (Map.size m == 0)+isAllGone (ThreadManager _timmgr var) =+ Map.null <$> readTVar var ---------------------------------------------------------------- -myWeakThradId :: IO (Weak ThreadId, Key)-myWeakThradId = do+myWeakThreadId :: IO (Weak ThreadId, Key)+myWeakThreadId = do tid <- myThreadId wtid <- mkWeakThreadId tid let n = fromThreadId tid@@ -209,6 +248,8 @@ tid <- myThreadId labelThread tid l +-- | Registering a 'T.TimeoutAction' and unregister its 'T.Handle'+-- when the body action is finished. withHandle :: ThreadManager -> T.TimeoutAction -> (T.Handle -> IO a) -> IO a withHandle (ThreadManager timmgr _) = T.withHandle timmgr
System/TimeManager.hs view
@@ -5,6 +5,7 @@ -- GHC System TimerManager. -- -- Some caveats of using this package:+-- -- * Only works for GHC -- * Only works with a threaded runtime -- * Users of older versions should check the current semantics.
time-manager.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: time-manager-version: 0.3.1+version: 0.3.1.1 license: MIT license-file: LICENSE maintainer: kazu@iij.ad.jp@@ -16,6 +16,7 @@ category: System build-type: Simple extra-source-files: ChangeLog.md+ README.md library exposed-modules: