fix STM deadlock in finishCommandActions

Happened every time, because it was taking the pool TMVar while threads
were still running, and then the thread would try to switch state.
This commit is contained in:
Joey Hess 2019-06-19 18:34:26 -04:00
parent 19321e6892
commit ad6b8c5f77
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 16 additions and 6 deletions

View file

@ -129,11 +129,12 @@ finishCommandActions = Annex.getState Annex.workers >>= \case
Nothing -> noop
Just tv -> do
Annex.changeState $ \s -> s { Annex.workers = Nothing }
pool <- liftIO $ atomically $ takeTMVar tv
forM_ (mapMaybe workerAsync $ workerList pool) $ \aid ->
liftIO (waitCatch aid) >>= \case
Left _ -> noop
Right st -> mergeState st
sts <- liftIO $ atomically $ do
pool <- readTMVar tv
if allIdle pool
then return (spareVals pool)
else retry
mapM_ mergeState sts
{- Like commandAction, but without the concurrency. -}
includeCommandAction :: CommandStart -> CommandCleanup

View file

@ -17,7 +17,8 @@ data WorkerPool t = WorkerPool
, workerList :: [Worker t]
, spareVals :: [t]
-- ^ Normally there is one value for each IdleWorker,
-- but there can temporarily be fewer.
-- but there can temporarily be fewer values, when a thread is
-- changing between stages.
}
deriving (Show)
@ -130,3 +131,11 @@ deactivateWorker pool aid t = pool
| a == aid = IdleWorker st : rest
| otherwise = w : go rest
allIdle :: WorkerPool t -> Bool
allIdle pool = all idle (workerList pool)
-- If this does not hold, a thread must be transitioning between
-- states, so it's not really idle.
&& length (spareVals pool) == length (workerList pool)
where
idle (IdleWorker _) = True
idle (ActiveWorker _ _) = False