Cheng Shao pushed to branch wip/hi-atomic at Glasgow Haskell Compiler / GHC Commits: c740a860 by Cheng Shao at 2026-01-19T12:44:14+01:00 compiler: monomorphize & inline withAtomicRename This commit monomorphizes withAtomicRename to IO and return type to (), since all its call sites are in the IO monad and discards return value, and also marks it as INLINE since it proves to be a hot spot and there may be stat increases otherwise. - - - - - 22ca4a67 by Cheng Shao at 2026-01-19T12:44:49+01:00 compiler: write interface files atomically This patch makes the GHC driver write the interface files atomically. This opens up the theoretical possibility for increased parallelism in an external build system, since they can monitor the appearance of upstream module's interface file and speculatively start downstream module's build without needing to wait for upstream module's codegen pipeline to finish. - - - - - 2 changed files: - compiler/GHC/Iface/Load.hs - compiler/GHC/Utils/Misc.hs Changes: ===================================== compiler/GHC/Iface/Load.hs ===================================== @@ -66,6 +66,7 @@ import GHC.Tc.Utils.Monad import GHC.Utils.Binary ( BinData(..) ) import GHC.Utils.Error +import GHC.Utils.Misc import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic import GHC.Utils.Constants (debugIsOn) @@ -989,7 +990,8 @@ writeIface :: Logger -> Profile -> CompressionIFace -> FilePath -> ModIface -> I writeIface logger profile compression_level hi_file_path new_iface = do createDirectoryIfMissing True (takeDirectory hi_file_path) let printer = TraceBinIFace (debugTraceMsg logger 3) - writeBinIface profile printer compression_level hi_file_path new_iface + withAtomicRename hi_file_path $ \temp_path -> + writeBinIface profile printer compression_level temp_path new_iface flagsToIfCompression :: DynFlags -> CompressionIFace flagsToIfCompression dflags ===================================== compiler/GHC/Utils/Misc.hs ===================================== @@ -133,7 +133,6 @@ import GHC.Stack (HasCallStack) import GHC.Data.List import Control.Monad ( guard ) -import Control.Monad.IO.Class ( MonadIO, liftIO ) import System.IO.Error as IO ( isDoesNotExistError ) import System.Directory ( doesDirectoryExist, getModificationTime, renameFile ) import qualified System.Directory.OsPath as OsPath @@ -1273,8 +1272,8 @@ fileHashIfExists f = -- and uses their modification time to skip work later, -- as otherwise a partially written file (e.g. due to crash or Ctrl+C) -- also results in a skip. - -withAtomicRename :: (MonadIO m) => FilePath -> (FilePath -> m a) -> m a +{-# INLINE withAtomicRename #-} +withAtomicRename :: FilePath -> (FilePath -> IO ()) -> IO () withAtomicRename targetFile f = do -- The temp file must be on the same file system (mount) as the target file -- to result in an atomic move on most platforms. @@ -1282,9 +1281,8 @@ withAtomicRename targetFile f = do -- This can still be fooled when somebody mounts a different file system -- at just the right time, but that is not a case we aim to cover here. let temp = targetFile <.> "tmp" - res <- f temp - liftIO $ renameFile temp targetFile - return res + f temp + renameFile temp targetFile -- -------------------------------------------------------------- -- split a string at the last character where 'pred' is True, View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7f4f668349faf427daa0547fc55dbf5... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7f4f668349faf427daa0547fc55dbf5... You're receiving this email because of your account on gitlab.haskell.org.