-
-
Notifications
You must be signed in to change notification settings - Fork 370
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
Unify critical session running in hls #4256
Changes from 24 commits
15f9892
3ba47f6
5d66041
d7946a0
da56bfb
fb0a370
d1775e6
39bdf6a
b06186b
1a9374b
c9bdc87
cb131e3
96d6d07
b552c80
aef173a
f231648
d08f175
60839b0
aba6a88
981724e
8f9ef7a
0e3a6e8
a1b0a69
78e9fc1
b2be89f
8aea82e
8c3773f
5f27fad
e800cac
86d7fb9
027e5be
99322fa
c1b3e7d
a16d04a
c832da3
6bdba37
442e776
5d657b6
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
module Development.IDE.Core.Thread | ||
( ThreadRun(..), runWithThread, blockRunInThread) | ||
where | ||
|
||
import Control.Concurrent.Async | ||
import Control.Concurrent.STM | ||
import Control.Concurrent.Strict (newBarrier, signalBarrier, | ||
waitBarrier) | ||
import Control.Monad (forever) | ||
import Control.Monad.Cont (ContT (ContT)) | ||
|
||
-- Note [Serializing runs in separate thread] | ||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
-- In a lof cases we want to have a separate thread that will serialize the runs of the actions. | ||
soulomoon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-- Like the db writes, session loading in session loader, shake session restarts. | ||
-- | ||
-- Originally we used various ways to implement this, but it was hard to maintain and error prone. | ||
-- Moreover, we can not stop these threads uniformly when we are shutting down the server. | ||
-- | ||
-- `Development.IDE.Core.Thread` module provides a declarative api to implement this easily. | ||
-- In `ThreadRun` data type: | ||
-- * `tRunWithResource`: is used to create the resources needed to perform the long running action. | ||
-- * `tWorker`: is the action we want to run in separate thread serially. | ||
-- | ||
-- runWithThread will create a worker thread to run along with the main thread. | ||
-- runWithThread provides `resource` created by `tRunWithResource` and a `TQueue` to send the actions to run. | ||
-- The worker thread will serialize the runs of the actions from the TQueue. | ||
|
||
|
||
data ThreadRun input workerResource resource arg = ThreadRun { | ||
tRunWithResource :: | ||
input -- ^ input of running | ||
-> (workerResource -> resource -> IO ()) -- ^ the long running action need to run with resource | ||
-> IO (), | ||
tWorker -- ^ A single action we want to run in separate thread serially | ||
:: input -- ^ input of running | ||
-> workerResource -- ^ writer resource | ||
-> arg -- ^ argument to run | ||
-> IO () | ||
} | ||
|
||
-- | runWithThread | ||
-- Run a long running action with a additional running thread | ||
-- The additional thread will serialize runs of the actions from the TQueue. | ||
-- Return ContT to run the action | ||
runWithThread :: ThreadRun input workerResource resource arg -> input -> ContT () IO (resource, TQueue arg) | ||
runWithThread ThreadRun{..} ip = ContT $ \f -> do | ||
tRunWithResource ip $ \w r -> do | ||
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 guess this kind of looks like two separate things to me:
My instinct is that we could focus on defining the worker queue, and just leave the creation of the resource, where necessary, to the call site. Indeed, many of the call sites don't create a resource at all! I think we could then quite naturally write:
or something? 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. Make sense, let's implement |
||
q <- newTQueueIO | ||
withAsync (writerThread w q) $ \_ -> f (r, q) | ||
where | ||
writerThread r q = | ||
forever $ do | ||
l <- atomically $ readTQueue q | ||
tWorker ip r l | ||
|
||
|
||
-- | blockRunInThread run and wait for the result | ||
-- Take an action from TQueue, run it and | ||
-- use barrier to wait for the result | ||
soulomoon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
blockRunInThread :: TQueue (IO ()) -> IO result -> IO result | ||
blockRunInThread q act = do | ||
barrier <- newBarrier | ||
atomically $ writeTQueue q $ do | ||
res <- act | ||
signalBarrier barrier res | ||
waitBarrier barrier |
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.
I think a more typical name for something like this would be a "work queue" or "job queue".