[Haskell-cafe] threads + IORefs = Segmentation fault?

David Roundy droundy at darcs.net
Fri Jan 18 18:22:55 EST 2008


Hi all,

I'm working on some new progress-reporting code for darcs, and am getting
segmentation faults!  :( The code uses threads + an IORef global variable
to do this (with lots of unsafePerformIO).  So my question for the gurus
who know more about this than I do:  is this safe? I thought it would be,
because only one thread ever modifies the IORef, and the others only read
it.  I don't really care if they read a correct value, as long as they
don't segfault.

The code (to summarize) looks like:

{-# NOINLINE _progressData #-}
_progressData :: IORef (Map String ProgressData)
_progressData = unsafePerformIO $ newIORef empty

updateProgressData :: String -> (ProgressData -> ProgressData) -> IO ()
updateProgressData k f = when (progressMode) $ modifyIORef _progressData (adjust f k)

setProgressData :: String -> ProgressData -> IO ()
setProgressData k p = when (progressMode) $ modifyIORef _progressData (insert k p)

getProgressData :: String -> IO (Maybe ProgressData)
getProgressData k = if progressMode then lookup k `fmap` readIORef _progressData
                                    else return Nothing

The key function is

beginTedious :: String -> IO ()
beginTedious k = do tid <- forkIO $ handleProgress k
                    debugMessage $ "Beginning " ++ k
                    setProgressData k $ ProgressData { sofar = 0,
                                                       latest = Nothing,
                                                       total = Nothing,
                                                       handler = Just tid }

which is called before an action that may be so tedious for our users that
they need their day brightened by messages such as "Applying patch
137/1436".  The handleProgress function alternates between threadDelay and
reading the progress data to see whether any progress has been made and
printing messages.  Meanwhile the main thread calls functions that update
_progressData.

Anyhow, the point is that I'm getting segfaults, even after recompiling
everything from scratch! Is this in fact that unsafe? Do I really need to
switch to MVars, even though no locking is required?
-- 
David Roundy
Department of Physics
Oregon State University


More information about the Haskell-Cafe mailing list