Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jan 2009 23:56:37 -0500
From:      David Schultz <das@FreeBSD.ORG>
To:        Daniel Eischen <deischen@FreeBSD.ORG>
Cc:        Brian Fundakowski Feldman <green@FreeBSD.ORG>, hackers@FreeBSD.ORG, Jason Evans <jasone@FreeBSD.ORG>, Julian Elischer <julian@elischer.org>
Subject:   Re: threaded, forked, rethreaded processes will deadlock
Message-ID:  <20090122045637.GA61058@zim.MIT.EDU>
In-Reply-To: <Pine.GSO.4.64.0901211831210.4150@sea.ntplx.net>
References:  <Pine.GSO.4.64.0901082237001.28531@sea.ntplx.net> <20090109053117.GB2825@green.homeunix.org> <4966F81C.3070406@elischer.org> <20090109163426.GC2825@green.homeunix.org> <49678BBC.8050306@elischer.org> <20090116211959.GA12007@green.homeunix.org> <49710BD6.7040705@FreeBSD.org> <20090120004135.GB12007@green.homeunix.org> <20090121230033.GC12007@green.homeunix.org> <Pine.GSO.4.64.0901211831210.4150@sea.ntplx.net>

next in thread | previous in thread | raw e-mail | index | archive | help
I think there *is* a real bug here, but there's two distinct ways
to fix it. When a threaded process forks, malloc acquires all its
locks so that its state is consistent after a fork. However, the
post-fork hook that's supposed to release these locks fails to do
so in the child because the child process isn't threaded, and
malloc_mutex_unlock() is optimized to be a no-op in
single-threaded processes. If the child *stays* single-threaded,
malloc() works by accident even with all the locks held because
malloc_mutex_lock() is also a no-op in single-threaded processes.
But if the child goes multi-threaded, then things break.

Solution 1 is to actually unlock the locks in the child process,
which is what Brian is proposing.

Solution 2 is to take the position that all of this pre- and
post-fork bloat in the fork() path is gratuitous and should be
removed. The rationale here is that if you fork with multiple
running threads, there's scads of ways in which the child's heap
could be inconsistent; fork hooks would be needed not just in
malloc(), but in stdio, third party libraries, etc. Why should
malloc() be special? It's the programmer's job to quiesce all the
threads before calling fork(), and if the programmer doesn't do
this, then POSIX only guarantees that async-signal-safe functions
will work.

Note that Solution 2 also fixes Brian's problem if he quiesces all
of his worker threads before forking (as he should!) With the
pre-fork hook removed, all the locks will start out free in the
child.  So that's what I vote for...



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090122045637.GA61058>