forkProcess() in Schedule.c with -threaded should initialize mutexes in child process (POSIX)
forkProcess()
in Schedule.c
implements System.Posix.Process.forkProcess
essentially by fork()
'ing. In http://www.gnu.org/software/libc/manual/html_node/Threads-and-Fork.html we read that
It's not intuitively obvious what should happen when a multi-threaded POSIX process calls fork. ... fork duplicates the whole memory space, including mutexes in their current locking state, but only the calling thread: other threads are not running in the child process. The mutexes are not usable after the fork and must be initialized with pthread_mutex_init in the child process.
Although a lot of things happen in forkProcess()
in Schedule.c
in the child process after fork()
returns, this initialization of mutexes and related delicate matters are not done.
On my PPC Mac OS X 10.4.9, I have observed this to eventually result in the child process getting a SIGSEGV
(signal 11; segmentation fault) when run via ghc --interactive
. The failing test case forkprocess01(ghci)
for PPC Mac OS X is an example of this.
The case of forkprocess01
failing when run via ghci --interactive
comes about because ghc itself is linked with -threaded
. With a ghc linked without -threaded
, the segmentation fault does not happen.
When executing forkprocess01
compiled with --make
-threaded
, the error again cannot be reproduced. But this seems to be because forkprocess01
itself does not use multiple threads. With a slightly extended version of forkprocess01
called forkprocess03
:
-- forkprocess03.hs:
-- Test that we can call exitFailure in a forked process, and have it
-- communicated properly to the parent.
-- Do this (forkprocess01) within a forkIO'ed child process.
import System.Exit
import System.Posix.Process
import Control.Concurrent
main0 = do
p <- forkProcess $ exitWith (ExitFailure 72)
r <- getProcessStatus True False p
print r
main = do
p <- forkIO $ main0
threadDelay 10000000
print p
the erroneous reaction can be observed when compiled with -threaded
using a fairly recent ghc HEAD:
$ /Users/thorkilnaur/tn/GHCDarcsRepository/ghc-HEAD-for-HughesPJ-wrong-fill-indent-20070506_1304/ghc/compiler/stage2/ghc-inplace --version
The Glorious Glasgow Haskell Compilation System, version 6.7.20070513
$ touch forkprocess03.hs
$ /Users/thorkilnaur/tn/GHCDarcsRepository/ghc-HEAD-for-HughesPJ-wrong-fill-indent-20070506_1304/ghc/compiler/stage2/ghc-inplace --make forkprocess03 -threaded
[1 of 1] Compiling Main ( forkprocess03.hs, forkprocess03.o )
Linking forkprocess03 ...
$ ./forkprocess03
Just (Terminated 11)
ThreadId 4
$
Whereas without -threaded
, the program seems to run fine:
$ touch forkprocess03.hs
$ /Users/thorkilnaur/tn/GHCDarcsRepository/ghc-HEAD-for-HughesPJ-wrong-fill-indent-20070506_1304/ghc/compiler/stage2/ghc-inplace --make forkprocess03
[1 of 1] Compiling Main ( forkprocess03.hs, forkprocess03.o )
Linking forkprocess03 ...
$ ./forkprocess03
Just (Exited (ExitFailure 72))
ThreadId 2
$
The repair, however, is not particularly obvious. The above reference suggests using pthread_atfork
to set up handlers to lock all mutexes before fork()
'ing and subsequently unlock them in the parent and initializing them in the child. But even if this is chosen as the way forward, additional matters need to be clarified, to ensure that such handling plays well with the rest of the threaded runtime system and also retains the Windows variant of things. Also, if anything is done about this, #1185 (closed) should probably considered as well.
Trac metadata
Trac field | Value |
---|---|
Version | 6.7 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Runtime System |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |