-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
withHandle #1015
withHandle #1015
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,16 +14,20 @@ module System.TimeManager ( | |
withManager, | ||
withManager', | ||
|
||
-- ** Registration | ||
register, | ||
registerKillThread, | ||
-- ** Registering a timeout action | ||
withHandle, | ||
withHandleKillThread, | ||
|
||
-- ** Control | ||
tickle, | ||
cancel, | ||
pause, | ||
resume, | ||
|
||
-- ** Low level | ||
register, | ||
registerKillThread, | ||
cancel, | ||
|
||
-- ** Exceptions | ||
TimeoutThread (..), | ||
) where | ||
|
@@ -96,6 +100,22 @@ killManager = reaperKill | |
|
||
---------------------------------------------------------------- | ||
|
||
-- | Registering a timeout action and unregister its handle | ||
-- when the body action is finished. | ||
withHandle :: Manager -> TimeoutAction -> (Handle -> IO a) -> IO a | ||
withHandle mgr onTimeout action = | ||
E.bracket (register mgr onTimeout) cancel action | ||
|
||
-- | Registering a timeout action of killing this thread and | ||
-- unregister its handle when the body action is killed or finished. | ||
withHandleKillThread :: Manager -> TimeoutAction -> (Handle -> IO ()) -> IO () | ||
withHandleKillThread mgr onTimeout action = | ||
E.handle handler $ E.bracket (registerKillThread mgr onTimeout) cancel action | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better/worse to do the following? 🤔
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it will matter much... since the The difference is this, effectively: -- Here's the body of 'bracket'
-- either here instead of:
-- mask $ \restore -> do
E.handle handler $ mask $ \restore -> do
a <- before
-- or here instead of:
-- r <- restore (thing a) `onException` after a
r <- restore (E.handle handler $ thing a) `onException` after a
_ <- after a
return r |
||
where | ||
handler TimeoutThread = return () | ||
|
||
---------------------------------------------------------------- | ||
|
||
-- | Registering a timeout action. | ||
register :: Manager -> TimeoutAction -> IO Handle | ||
register mgr !onTimeout = do | ||
|
@@ -105,6 +125,34 @@ register mgr !onTimeout = do | |
reaperAdd mgr h | ||
return h | ||
|
||
-- | Removing the 'Handle' from the 'Manager' immediately. | ||
cancel :: Handle -> IO () | ||
cancel (Handle mgr _ stateRef) = do | ||
_ <- reaperModify mgr filt | ||
return () | ||
where | ||
-- It's very important that this function forces the whole workload so we | ||
-- don't retain old handles, otherwise disasterous leaks occur. | ||
filt [] = [] | ||
filt (h@(Handle _ _ stateRef') : hs) | ||
| stateRef == stateRef' = hs | ||
| otherwise = | ||
let !hs' = filt hs | ||
in h : hs' | ||
|
||
---------------------------------------------------------------- | ||
|
||
-- | The asynchronous exception thrown if a thread is registered via | ||
-- 'registerKillThread'. | ||
data TimeoutThread = TimeoutThread | ||
deriving (Typeable) | ||
|
||
instance E.Exception TimeoutThread where | ||
toException = E.asyncExceptionToException | ||
fromException = E.asyncExceptionFromException | ||
instance Show TimeoutThread where | ||
show TimeoutThread = "Thread killed by timeout manager" | ||
|
||
-- | Registering a timeout action of killing this thread. | ||
-- 'TimeoutThread' is thrown to the thread which called this | ||
-- function on timeout. Catch 'TimeoutThread' if you don't | ||
|
@@ -121,40 +169,13 @@ registerKillThread m onTimeout = do | |
Nothing -> return () | ||
Just tid' -> E.throwTo tid' TimeoutThread | ||
|
||
-- | The asynchronous exception thrown if a thread is registered via | ||
-- 'registerKillThread'. | ||
data TimeoutThread = TimeoutThread | ||
deriving (Typeable) | ||
|
||
instance E.Exception TimeoutThread where | ||
toException = E.asyncExceptionToException | ||
fromException = E.asyncExceptionFromException | ||
instance Show TimeoutThread where | ||
show TimeoutThread = "Thread killed by timeout manager" | ||
|
||
---------------------------------------------------------------- | ||
|
||
-- | Setting the state to active. | ||
-- 'Manager' turns active to inactive repeatedly. | ||
tickle :: Handle -> IO () | ||
tickle (Handle _ _ stateRef) = I.writeIORef stateRef Active | ||
|
||
-- | Removing the 'Handle' from the 'Manager' immediately. | ||
cancel :: Handle -> IO () | ||
cancel (Handle mgr _ stateRef) = do | ||
_ <- reaperModify mgr filt | ||
return () | ||
where | ||
-- It's very important that this function forces the whole workload so we | ||
-- don't retain old handles, otherwise disasterous leaks occur. | ||
filt [] = [] | ||
filt (h@(Handle _ _ stateRef') : hs) | ||
| stateRef == stateRef' = | ||
hs | ||
| otherwise = | ||
let !hs' = filt hs | ||
in h : hs' | ||
|
||
-- | Setting the state to paused. | ||
-- 'Manager' does not change the value. | ||
pause :: Handle -> IO () | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
Name: time-manager | ||
Version: 0.1.2 | ||
Version: 0.1.3 | ||
Synopsis: Scalable timer | ||
License: MIT | ||
License-file: LICENSE | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,10 +106,6 @@ http2server label settings ii transport addr app h2req0 aux0 response = do | |
logResponse req st msiz | ||
mapM_ (logPushPromise req) pps | ||
Left e | ||
-- killed by the local worker manager | ||
| Just E.ThreadKilled <- E.fromException e -> return () | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now not caught anymore, right? Is that intentional?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is very old code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But people can implement their own forking behaviour with Though now that I think about it, this is actually better, right? Since if someone would want to kill an HTTP thread that's handling a request, this would just ignore the signal. So I now also believe this is the right decision. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that |
||
-- killed by the local timeout manager | ||
| Just T.TimeoutThread <- E.fromException e -> return () | ||
| isAsyncException e -> E.throwIO e | ||
| otherwise -> do | ||
S.settingsOnException settings (Just req) e | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.