Skip to content

Commit db4f461

Browse files
committed
Lock Configure per build
1 parent 1fc2e2a commit db4f461

File tree

3 files changed

+54
-12
lines changed

3 files changed

+54
-12
lines changed

Cabal/src/Distribution/Simple/ConfigureScript.hs

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ import Distribution.Compat.GetShortPathName (getShortPathName)
4949
import qualified Data.List.NonEmpty as NonEmpty
5050
import qualified Data.Map as Map
5151

52+
import Control.Concurrent.MVar
53+
import Data.IORef
54+
import System.IO.Unsafe (unsafePerformIO)
55+
--- BEGIN MODIFICATION: Locking Mechanism ---
56+
57+
-- Global state for locks, one MVar per build directory path.
58+
-- The MVar () acts as a mutex: it's full when the lock is available (unlocked),
59+
-- and empty when taken (locked).
60+
{-# NOINLINE configureLocks #-}
61+
configureLocks :: IORef (Map.Map FilePath (MVar ()))
62+
configureLocks = unsafePerformIO (newIORef Map.empty)
63+
64+
-- Gets or creates a lock for a given path.
65+
-- Ensures that only one MVar is associated with each path.
66+
getOrCreateLock :: FilePath -> IO (MVar ())
67+
getOrCreateLock path = do
68+
-- Optimistically create a new MVar. It will be used if the path is not already in the map.
69+
-- This MVar is created "full" (i.e., containing ()), meaning the lock is initially available.
70+
newLock <- newMVar ()
71+
atomicModifyIORef' configureLocks $ \currentMap ->
72+
case Map.lookup path currentMap of
73+
Just existingLock -> (currentMap, existingLock) -- Lock already exists, return it. The newLock we created is discarded.
74+
Nothing -> (Map.insert path newLock currentMap, newLock) -- New lock inserted, return it.
75+
--- END MODIFICATION: Locking Mechanism ---
76+
5277
runConfigureScript
5378
:: ConfigFlags
5479
-> FlagAssignment
@@ -179,15 +204,32 @@ runConfigureScript cfg flags programDb hp = do
179204
shConfiguredProg <-
180205
lookupProgram shProg
181206
`fmap` configureProgram verbosity shProg progDb
182-
case shConfiguredProg of
183-
Just sh -> do
184-
let build_in = interpretSymbolicPath mbWorkDir build_dir
185-
createDirectoryIfMissing True build_in
186-
runProgramInvocation verbosity $
187-
(programInvocation (sh{programOverrideEnv = overEnv}) args')
188-
{ progInvokeCwd = Just build_in
189-
}
190-
Nothing -> dieWithException verbosity NotFoundMsg
207+
208+
--- BEGIN MODIFICATION: Apply Locking ---
209+
-- Acquire the lock specific to this build_dir
210+
-- build_dir is used as the key for the lock.
211+
configureLock <- getOrCreateLock (interpretSymbolicPath mbWorkDir build_dir)
212+
213+
let runLockedConfigureAction = do
214+
case shConfiguredProg of
215+
Just sh -> do
216+
let build_in = interpretSymbolicPath mbWorkDir build_dir
217+
createDirectoryIfMissing True build_in
218+
warn verbosity $ "Configure lock acquired. Running configure script in " ++ build_in
219+
runProgramInvocation verbosity $
220+
(programInvocation (sh{programOverrideEnv = overEnv}) args')
221+
{ progInvokeCwd = Just build_in
222+
}
223+
Nothing -> dieWithException verbosity NotFoundMsg
224+
225+
warn verbosity $ "Attempting to acquire configure lock for " ++ interpretSymbolicPath mbWorkDir build_dir
226+
-- withMVar takes the MVar (blocks if already taken), runs the action,
227+
-- and ensures the MVar is put back, even if the action throws an exception.
228+
withMVar configureLock $ \() ->
229+
-- The '()' means the MVar holds a unit value; we're interested in its full/empty state.
230+
runLockedConfigureAction
231+
warn verbosity $ "Configure lock released for " ++ interpretSymbolicPath mbWorkDir build_dir
232+
--- END MODIFICATION: Apply Locking ---
191233
where
192234
args = configureArgs backwardsCompatHack cfg
193235
backwardsCompatHack = False

cabal-install/src/Distribution/Client/InstallPlan.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import Distribution.Package
9393
, UnitId
9494
)
9595
import Distribution.Pretty (defaultStyle)
96+
import Distribution.Simple.Compiler ( Compiler (compilerId) )
9697
import Distribution.Solver.Types.SolverPackage
9798
import Text.PrettyPrint
9899

@@ -590,8 +591,8 @@ fromSolverInstallPlanWithProgress f plan = do
590591

591592
-- | Conversion of 'SolverInstallPlan' to 'InstallPlan'.
592593
-- Similar to 'elaboratedInstallPlan'
593-
configureInstallPlan :: Cabal.ConfigFlags -> Compiler -> SolverInstallPlan -> InstallPlan
594-
configureInstallPlan configFlags comp solverPlan =
594+
configureInstallPlan :: Compiler -> Cabal.ConfigFlags -> SolverInstallPlan -> InstallPlan
595+
configureInstallPlan comp configFlags solverPlan =
595596
flip fromSolverInstallPlan solverPlan $ \mapDep planpkg ->
596597
[ case planpkg of
597598
SolverInstallPlan.PreExisting pkg ->

cabal-install/src/Distribution/Client/ProjectPlanning.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,6 @@ elaborateInstallPlan
18331833
-- Once you've implemented this, swap it for the code below.
18341834
cuz_buildtype =
18351835
case bt of
1836-
PD.Configure -> [CuzBuildType CuzConfigureBuildType]
18371836
PD.Custom -> [CuzBuildType CuzCustomBuildType]
18381837
PD.Hooks -> [CuzBuildType CuzHooksBuildType]
18391838
PD.Make -> [CuzBuildType CuzMakeBuildType]

0 commit comments

Comments
 (0)