Skip to content

Commit 5490865

Browse files
committed
Refactor runActions'
Separates out `processActions` and `processAction`. Makes use of `check b = unless b retry`. Uses variables to avoid code duplication. Avoids duplication of `inAction <- readTVar esInAction`. Minimise the actions within the `mask` to those strictly necessary.
1 parent 1c31386 commit 5490865

File tree

1 file changed

+44
-37
lines changed

1 file changed

+44
-37
lines changed

src/Control/Concurrent/Execute.hs

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module Control.Concurrent.Execute
1212
, runActions
1313
) where
1414

15-
import Control.Concurrent.STM ( retry )
15+
import Control.Concurrent.STM ( check )
1616
import Stack.Prelude
1717
import Data.List ( sortBy )
1818
import qualified Data.Set as Set
@@ -134,49 +134,56 @@ runActions' ExecuteState {..} = loop
134134
else inner actions
135135

136136
loop :: IO ()
137-
loop = join $ atomically $ breakOnErrs $ withActions $ \as ->
138-
case break (Set.null . actionDeps) as of
137+
loop = join $ atomically $ breakOnErrs $ withActions processActions
138+
139+
processActions :: [Action] -> STM (IO ())
140+
processActions actions = do
141+
inAction <- readTVar esInAction
142+
case break (Set.null . actionDeps) actions of
139143
(_, []) -> do
140-
inAction <- readTVar esInAction
141-
if Set.null inAction
142-
then do
143-
unless esKeepGoing $
144-
modifyTVar esExceptions (toException InconsistentDependenciesBug:)
145-
doNothing
146-
else retry
147-
(xs, action:ys) -> do
148-
inAction <- readTVar esInAction
149-
case actionConcurrency action of
150-
ConcurrencyAllowed -> pure ()
151-
ConcurrencyDisallowed -> unless (Set.null inAction) retry
152-
let as' = xs ++ ys
153-
remaining = Set.union
154-
(Set.fromList $ map actionId as')
155-
inAction
156-
writeTVar esActions as'
157-
modifyTVar esInAction (Set.insert $ actionId action)
158-
pure $ mask $ \restore -> do
159-
eres <- try $ restore $ actionDo action ActionContext
160-
{ acRemaining = remaining
161-
, acDownstream = downstreamActions (actionId action) as'
162-
, acConcurrency = actionConcurrency action
163-
}
164-
atomically $ do
165-
modifyTVar esInAction (Set.delete $ actionId action)
166-
modifyTVar esCompleted (+1)
167-
case eres of
168-
Left err -> modifyTVar esExceptions (err:)
169-
Right () ->
170-
let dropDep a =
171-
a { actionDeps = Set.delete (actionId action) $ actionDeps a }
172-
in modifyTVar esActions $ map dropDep
173-
restore loop
144+
check (Set.null inAction)
145+
unless esKeepGoing $
146+
modifyTVar esExceptions (toException InconsistentDependenciesBug:)
147+
doNothing
148+
(xs, action:ys) -> processAction inAction (xs ++ ys) action
149+
150+
processAction :: Set ActionId -> [Action] -> Action -> STM (IO ())
151+
processAction inAction otherActions action = do
152+
let concurrency = actionConcurrency action
153+
unless (concurrency == ConcurrencyAllowed) $
154+
check (Set.null inAction)
155+
let action' = actionId action
156+
otherActions' = Set.fromList $ map actionId otherActions
157+
remaining = Set.union otherActions' inAction
158+
actionContext = ActionContext
159+
{ acRemaining = remaining
160+
, acDownstream = downstreamActions action' otherActions
161+
, acConcurrency = concurrency
162+
}
163+
writeTVar esActions otherActions
164+
modifyTVar esInAction (Set.insert action')
165+
pure $ do
166+
mask $ \restore -> do
167+
eres <- try $ restore $ actionDo action actionContext
168+
atomically $ do
169+
modifyTVar esInAction (Set.delete action')
170+
modifyTVar esCompleted (+1)
171+
case eres of
172+
Left err -> modifyTVar esExceptions (err:)
173+
Right () -> modifyTVar esActions $ map (dropDep action')
174+
loop
174175

175176
-- | Filter a list of actions to include only those that depend on the given
176177
-- action.
177178
downstreamActions :: ActionId -> [Action] -> [Action]
178179
downstreamActions aid = filter (\a -> aid `Set.member` actionDeps a)
179180

181+
-- | Given two actions (the first specified by its id) yield an action
182+
-- equivalent to the second but excluding any dependency on the first action.
183+
dropDep :: ActionId -> Action -> Action
184+
dropDep action' action =
185+
action { actionDeps = Set.delete action' $ actionDeps action }
186+
180187
-- | @IO ()@ lifted into 'STM'.
181188
doNothing :: STM (IO ())
182189
doNothing = pure $ pure ()

0 commit comments

Comments
 (0)