readBinIface :: CheckHiWay -> TraceBinIFaceReading -> FilePath
-> TcRnIf a b ModIface
readBinIface checkHiWay traceBinIFaceReading hi_path = do
- lockedUpdNameCache $ \nc ->
- readBinIface_ checkHiWay traceBinIFaceReading hi_path nc
+ update_nc <- mkNameCacheUpdater
+ liftIO $ readBinIface_ checkHiWay traceBinIFaceReading hi_path update_nc
-readBinIface_ :: CheckHiWay -> TraceBinIFaceReading -> FilePath -> NameCache
- -> IO (NameCache, ModIface)
-readBinIface_ checkHiWay traceBinIFaceReading hi_path nc = do
+readBinIface_ :: CheckHiWay -> TraceBinIFaceReading -> FilePath
+ -> NameCacheUpdater (Array Int Name)
+ -> IO ModIface
+readBinIface_ checkHiWay traceBinIFaceReading hi_path update_nc = do
let printer :: SDoc -> IO ()
printer = case traceBinIFaceReading of
TraceBinIFaceReading -> \sd -> printSDoc sd defaultDumpStyle
symtab_p <- Binary.get bh -- Get the symtab ptr
data_p <- tellBin bh -- Remember where we are now
seekBin bh symtab_p
- (nc', symtab) <- getSymbolTable bh nc
+ symtab <- getSymbolTable bh update_nc
seekBin bh data_p -- Back to where we were before
let ud = getUserData bh
bh <- return $! setUserData bh ud{ud_symtab = symtab}
iface <- get bh
- return (nc', iface)
+ return iface
writeBinIface :: DynFlags -> FilePath -> ModIface -> IO ()
let names = elems (array (0,next_off-1) (eltsUFM symtab))
mapM_ (\n -> serialiseName bh n symtab) names
-getSymbolTable :: BinHandle -> NameCache -> IO (NameCache, Array Int Name)
-getSymbolTable bh namecache = do
+getSymbolTable :: BinHandle -> NameCacheUpdater (Array Int Name)
+ -> IO (Array Int Name)
+getSymbolTable bh update_namecache = do
sz <- get bh
od_names <- sequence (replicate sz (get bh))
- let
+ update_namecache $ \namecache ->
+ let
arr = listArray (0,sz-1) names
(namecache', names) =
mapAccumR (fromOnDiskName arr) namecache od_names
- --
- return (namecache', arr)
+ in (namecache', arr)
type OnDiskName = (PackageId, ModuleName, OccName)
-- Name-cache stuff
allocateGlobalBinder, initNameCache,
- getNameCache, lockedUpdNameCache,
+ getNameCache, mkNameCacheUpdater, NameCacheUpdater
) where
#include "HsVersions.h"
import MkId
import Outputable
-import Exception ( onException )
+import Exception ( evaluate )
-import Control.Concurrent.MVar ( tryTakeMVar, takeMVar, putMVar )
+import Data.IORef ( atomicModifyIORef, readIORef )
\end{code}
HscEnv { hsc_NC = nc_var } <- getTopEnv
atomicUpdMutVar' nc_var upd_fn
--- | Update the name cache, but takes a lock while the update function is
--- running. If the update function throws an exception the lock is released
--- and the exception propagated.
-lockedUpdNameCache :: (NameCache -> IO (NameCache, c)) -> TcRnIf a b c
-lockedUpdNameCache upd_fn = do
- lock <- hsc_NC_lock `fmap` getTopEnv
- -- Non-blocking "takeMVar" so we can show diagnostics if we didn't get the
- -- lock.
- mb_ok <- liftIO $ tryTakeMVar lock
- case mb_ok of
- Nothing -> do
- traceIf (text "lockedUpdNameCache: failed to take lock. blocking..")
- _ <- liftIO $ takeMVar lock
- traceIf (text "lockedUpdNameCache: got lock")
- Just _ -> return ()
-
- name_cache <- getNameCache
- (name_cache', rslt) <- liftIO (upd_fn name_cache
- `onException` putMVar lock ())
+-- | A function that atomically updates the name cache given a modifier
+-- function. The second result of the modifier function will be the result
+-- of the IO action.
+type NameCacheUpdater c = (NameCache -> (NameCache, c)) -> IO c
+-- | Return a function to atomically update the name cache.
+mkNameCacheUpdater :: TcRnIf a b (NameCacheUpdater c)
+mkNameCacheUpdater = do
nc_var <- hsc_NC `fmap` getTopEnv
- writeMutVar nc_var $! name_cache'
-
- liftIO (putMVar lock ())
- return rslt
+ let update_nc f = do r <- atomicModifyIORef nc_var f
+ _ <- evaluate =<< readIORef nc_var
+ return r
+ return update_nc
\end{code}
-- import MonadUtils
import Control.Monad
-import Control.Concurrent.MVar ( newMVar )
-- import System.IO
import Data.IORef
\end{code}
= do { eps_var <- newIORef initExternalPackageState
; us <- mkSplitUniqSupply 'r'
; nc_var <- newIORef (initNameCache us knownKeyNames)
- ; nc_lock <- newMVar ()
; fc_var <- newIORef emptyUFM
; mlc_var <- newIORef emptyModuleEnv
; optFuel <- initOptFuelState
hsc_HPT = emptyHomePackageTable,
hsc_EPS = eps_var,
hsc_NC = nc_var,
- hsc_NC_lock = nc_lock,
hsc_FC = fc_var,
hsc_MLC = mlc_var,
hsc_OptFuel = optFuel,
import Data.List
import Control.Monad ( mplus, guard, liftM, when )
import Exception
-import Control.Concurrent.MVar ( MVar )
\end{code}
-- reflect sucking in interface files. They cache the state of
-- external interface files, in effect.
- hsc_NC_lock :: !(MVar ()),
- -- ^ A lock used for updating the name cache.
-
hsc_FC :: {-# UNPACK #-} !(IORef FinderCache),
-- ^ The cached result of performing finding in the file system
hsc_MLC :: {-# UNPACK #-} !(IORef ModLocationCache),