Re: threaded, forked, rethreaded processes will deadlock
Kostik Belousov wrote: I looked at the issue once more recently, and I propose the following much less intrusive patch. It is somewhat hackish, but I think that it would be good to have this working. Most other Unixes do have working thread library after the fork. Any objections ? diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c index bc410d1..ae6b9ad 100644 --- a/lib/libthr/thread/thr_fork.c +++ b/lib/libthr/thread/thr_fork.c @@ -173,14 +173,19 @@ _fork(void) /* Ready to continue, unblock signals. */ _thr_signal_unblock(curthread); - if (unlock_malloc) + if (unlock_malloc) { + __isthreaded = 1; _malloc_postfork(); + __isthreaded = 0; + } /* Run down atfork child handlers. */ TAILQ_FOREACH(af, &_thr_atfork_list, qe) { if (af->child != NULL) af->child(); } + + THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock); ^^^ This line is not needed. } else { /* Parent process */ errsave = errno; ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Wed, 18 Mar 2009, Kostik Belousov wrote: I looked at the issue once more recently, and I propose the following much less intrusive patch. It is somewhat hackish, but I think that it would be good to have this working. Most other Unixes do have working thread library after the fork. Any objections ? No objections. -- DE ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 22, 2009 at 12:42:56AM -0500, Daniel Eischen wrote: > On Wed, 21 Jan 2009, David Schultz wrote: > > >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... > > The problem is that our own libraries (libthr included) > need to malloc() for themselves, even after a fork() in > the child. After a fork(), the malloc locks should be > reinitialized in the child if it was threaded, so that > our implementation actually works for all the async > signal calls, fork(), exec(), etc. I forget the exact > failure modes for very common cases, but if you remove > the re-initialization of the malloc locks, I'm sure > you will have problems. > > Perhaps much of this malloc() stuff goes away when we > move to pthread locks that are not pointers to allocated > objects, but instead are actual objects/structures. > This needs to be done in order for mutexes/CVs/etc > to be PTHREAD_PROCESS_SHARED (placed in shared memory > and used by multiple processes). In other words, > pthread_mutex_t goes from this: > > typedef struct pthread_mutex *pthread_mutex_t; > > to something like this: > > struct __pthread_mutex { > uint32_tlock; > ... > } > typedef struct __pthread_mutex pthread_mutex_t; > > Same thing for CVs, and we probably should convert any other > locks used internally by libc/libpthread (spinlocks). > > So after a fork(), there is no need to reallocate anything, > it can just be reinitialized if necessary. > I looked at the issue once more recently, and I propose the following much less intrusive patch. It is somewhat hackish, but I think that it would be good to have this working. Most other Unixes do have working thread library after the fork. Any objections ? diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c index bc410d1..ae6b9ad 100644 --- a/lib/libthr/thread/thr_fork.c +++ b/lib/libthr/thread/thr_fork.c @@ -173,14 +173,19 @@ _fork(void) /* Ready to continue, unblock signals. */ _thr_signal_unblock(curthread); - if (unlock_malloc) + if (unlock_malloc) { + __isthreaded = 1; _malloc_postfork(); + __isthreaded = 0; + } /* Run down atfork child handlers. */ TAILQ_FOREACH(af, &_thr_atfork_list, qe) { if (af->child != NULL) af->child(); } + + THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock); } else { /* Parent process */ errsave = errno; pgplLb1p3doD4.pgp Description: PGP signature
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 22, 2009 at 12:42:56AM -0500, Daniel Eischen wrote: > On Wed, 21 Jan 2009, David Schultz wrote: > >> 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... > > The problem is that our own libraries (libthr included) > need to malloc() for themselves, even after a fork() in > the child. After a fork(), the malloc locks should be > reinitialized in the child if it was threaded, so that > our implementation actually works for all the async > signal calls, fork(), exec(), etc. I forget the exact > failure modes for very common cases, but if you remove > the re-initialization of the malloc locks, I'm sure > you will have problems. > > Perhaps much of this malloc() stuff goes away when we > move to pthread locks that are not pointers to allocated > objects, but instead are actual objects/structures. > This needs to be done in order for mutexes/CVs/etc > to be PTHREAD_PROCESS_SHARED (placed in shared memory > and used by multiple processes). In other words, > pthread_mutex_t goes from this: > > typedef struct pthread_mutex *pthread_mutex_t; > > to something like this: > > struct __pthread_mutex { > uint32_tlock; > ... > } > typedef struct __pthread_mutex pthread_mutex_t; > > Same thing for CVs, and we probably should convert any other > locks used internally by libc/libpthread (spinlocks). > > So after a fork(), there is no need to reallocate anything, > it can just be reinitialized if necessary. In this case it's not a matter of locks needing to be again initialized -- the mutexes are fine -- they just need to be relinquished, which never occurs for the child now, but used to work fine in 7.0. What is truly broken about the current behavior module the bug I'm trying to fix? -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 22, 2009, David Schultz wrote: > If you can't implement functions that are required to be > async-signal-safe like fork() and exec() without malloc(), then > for now I guess we should go for something along the lines of what > Brian is proposing. If the app programmer has taken special pains > to ensure that all other threads are stopped when a fork happens, > the fork() call shouldn't return in the child with all the malloc > locks bogusly held. Note that even with Brian's patch, the memory associated with the all the parent's threads' stacks is leaked, and libthr can't be expected to be in a particularly happy state after all of its threads disappear. It just happens to (sort of) work for now. In any case, it's clearly a bug that libthr's fork handler calls _malloc_postfork() in the child even when _malloc_postfork() doesn't work properly in the (now single-threaded) child. Which way to fix it is up to you guys... ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 22, 2009, Daniel Eischen wrote: > On Wed, 21 Jan 2009, David Schultz wrote: > > >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... > > The problem is that our own libraries (libthr included) > need to malloc() for themselves, even after a fork() in > the child. After a fork(), the malloc locks should be > reinitialized in the child if it was threaded, so that > our implementation actually works for all the async > signal calls, fork(), exec(), etc. I forget the exact > failure modes for very common cases, but if you remove > the re-initialization of the malloc locks, I'm sure > you will have problems. If you can't implement functions that are required to be async-signal-safe like fork() and exec() without malloc(), then for now I guess we should go for something along the lines of what Brian is proposing. If the app programmer has taken special pains to ensure that all other threads are stopped when a fork happens, the fork() call shouldn't return in the child with all the malloc locks bogusly held. ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Wed, 21 Jan 2009, David Schultz wrote: 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... The problem is that our own libraries (libthr included) need to malloc() for themselves, even after a fork() in the child. After a fork(), the malloc locks should be reinitialized in the child if it was threaded, so that our implementation actually works for all the async signal calls, fork(), exec(), etc. I forget the exact failure modes for very common cases, but if you remove the re-initialization of the malloc locks, I'm sure you will have problems. Perhaps much of this malloc() stuff goes away when we move to pthread locks that are not pointers to allocated objects, but instead are actual objects/structures. This needs to be done in order for mutexes/CVs/etc to be PTHREAD_PROCESS_SHARED (placed in shared memory and used by multiple processes). In other words, pthread_mutex_t goes from this: typedef struct pthread_mutex *pthread_mutex_t; to something like this: struct __pthread_mutex { uint32_tlock; ... } typedef struct __pthread_mutex pthread_mutex_t; Same thing for CVs, and we probably should convert any other locks used internally by libc/libpthread (spinlocks). So after a fork(), there is no need to reallocate anything, it can just be reinitialized if necessary. -- DE ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
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... ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Wed, 21 Jan 2009, Brian Fundakowski Feldman wrote: On Mon, Jan 19, 2009 at 07:41:35PM -0500, Brian Fundakowski Feldman wrote: On Fri, Jan 16, 2009 at 02:36:06PM -0800, Jason Evans wrote: Brian Fundakowski Feldman wrote: > Could you, and anyone else who would care to, check this out? It's a regression fix but it also makes the code a little bit clearer. Thanks! Index: lib/libc/stdlib/malloc.c Why does malloc need to change for this? Unless there's a really good reason, I don't want the extra branches in the locking functions. Because malloc is the thing causing the regression. It is easy enough to optimize out the one extra fetch and branch in the single-threaded case if I can get some consensus that the fix to it is actually fine. The changes to thr_fork.c seem gratuituous; they don't affect any functionality, and I don't see the difference between the flag saying "unlock the malloc mutex" or "I was threaded". Clearly, it is set in "if (__isthreaded)", so it is obvious that it indeed was threaded. I can't speak to the malloc changes... -- DE ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Mon, Jan 19, 2009 at 07:41:35PM -0500, Brian Fundakowski Feldman wrote: > On Fri, Jan 16, 2009 at 02:36:06PM -0800, Jason Evans wrote: > > Brian Fundakowski Feldman wrote: > > > Could you, and anyone else who would care to, check this out? It's a > > regression > >> fix but it also makes the code a little bit clearer. Thanks! > >> > >> Index: lib/libc/stdlib/malloc.c > > > > Why does malloc need to change for this? Unless there's a really good > > reason, I don't want the extra branches in the locking functions. > > Because malloc is the thing causing the regression. It is easy enough > to optimize out the one extra fetch and branch in the single-threaded case > if I can get some consensus that the fix to it is actually fine. Pessimization removed: Index: lib/libc/stdlib/malloc.c === --- lib/libc/stdlib/malloc.c(revision 187160) +++ lib/libc/stdlib/malloc.c(working copy) @@ -1217,6 +1217,13 @@ _SPINUNLOCK(&mutex->lock); } +static inline void +malloc_mutex_always_unlock(malloc_mutex_t *mutex) +{ + + _SPINUNLOCK(&mutex->lock); +} + /* * End mutex. */ @@ -1300,6 +1307,13 @@ _pthread_mutex_unlock(lock); } +static inline void +malloc_spin_always_unlock(pthread_mutex_t *lock) +{ + + _pthread_mutex_unlock(lock); +} + /* * End spin lock. */ @@ -5515,9 +5529,8 @@ void _malloc_prefork(void) { + arena_t *larenas[narenas]; bool again; - unsigned i, j; - arena_t *larenas[narenas], *tarenas[narenas]; /* Acquire all mutexes in a safe order. */ @@ -5530,19 +5543,23 @@ */ memset(larenas, 0, sizeof(arena_t *) * narenas); do { + unsigned int i; + again = false; malloc_spin_lock(&arenas_lock); for (i = 0; i < narenas; i++) { if (arenas[i] != larenas[i]) { + arena_t *tarenas[narenas]; + unsigned int j; + memcpy(tarenas, arenas, sizeof(arena_t *) * narenas); malloc_spin_unlock(&arenas_lock); for (j = 0; j < narenas; j++) { if (larenas[j] != tarenas[j]) { larenas[j] = tarenas[j]; - malloc_spin_lock( - &larenas[j]->lock); + malloc_spin_lock(&larenas[j]->lock); } } again = true; @@ -5569,19 +5586,24 @@ /* Release all mutexes, now that fork() has completed. */ #ifdef MALLOC_DSS - malloc_mutex_unlock(&dss_mtx); + malloc_mutex_always_unlock(&dss_mtx); #endif - malloc_mutex_unlock(&huge_mtx); + malloc_mutex_always_unlock(&huge_mtx); - malloc_mutex_unlock(&base_mtx); + malloc_mutex_always_unlock(&base_mtx); memcpy(larenas, arenas, sizeof(arena_t *) * narenas); - malloc_spin_unlock(&arenas_lock); + malloc_spin_always_unlock(&arenas_lock); for (i = 0; i < narenas; i++) { if (larenas[i] != NULL) - malloc_spin_unlock(&larenas[i]->lock); + malloc_spin_always_unlock(&larenas[i]->lock); } + /* +* This ends the special post-__isthreaded exemption behavior for +* malloc stuff. We should really be single threaded right now +* in effect regardless of __isthreaded status. +*/ } /* Index: lib/libthr/thread/thr_fork.c === --- lib/libthr/thread/thr_fork.c(revision 187160) +++ lib/libthr/thread/thr_fork.c(working copy) @@ -105,7 +105,7 @@ struct pthread_atfork *af; pid_t ret; int errsave; - int unlock_malloc; + int was_threaded; int rtld_locks[MAX_RTLD_LOCKS]; if (!_thr_is_inited()) @@ -122,16 +122,16 @@ } /* -* Try our best to protect memory from being corrupted in -* child process because another thread in malloc code will -* simply be kill by fork(). +* All bets are off as to what should happen soon if the parent +* process was not so kindly as to set up pthread fork hooks to +* relinquish all running threads. */ if (_thr_isthreaded() != 0) { - unlock_malloc = 1; + was_threaded = 1; _malloc_prefork(); _rtld_atfork_pre(rtld_locks); } else { - unlock_malloc = 0; + was_threaded = 0; } /* @@ -159,7 +159,7 @@
Re: threaded, forked, rethreaded processes will deadlock
On Fri, Jan 16, 2009 at 02:36:06PM -0800, Jason Evans wrote: > Brian Fundakowski Feldman wrote: > > Could you, and anyone else who would care to, check this out? It's a > regression >> fix but it also makes the code a little bit clearer. Thanks! >> >> Index: lib/libc/stdlib/malloc.c > > Why does malloc need to change for this? Unless there's a really good > reason, I don't want the extra branches in the locking functions. Because malloc is the thing causing the regression. It is easy enough to optimize out the one extra fetch and branch in the single-threaded case if I can get some consensus that the fix to it is actually fine. -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
Brian Fundakowski Feldman wrote: > Could you, and anyone else who would care to, check this out? It's a regression fix but it also makes the code a little bit clearer. Thanks! Index: lib/libc/stdlib/malloc.c Why does malloc need to change for this? Unless there's a really good reason, I don't want the extra branches in the locking functions. Thanks, Jason ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Fri, Jan 09, 2009 at 09:39:08AM -0800, Julian Elischer wrote: > Brian Fundakowski Feldman wrote: >> On Thu, Jan 08, 2009 at 11:09:16PM -0800, Julian Elischer wrote: >>> Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: > On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: > >> It appears that the post-fork hooks for malloc(3) are somewhat broken >> such that >> when a threaded program forks, and then its child attempts to go >> threaded, it >> deadlocks because it already appears to have locks held. I am not >> familiar >> enough with the current libthr/libc/rtld-elf interaction that I've been >> able >> to fix it myself, unfortunately. > There's really nothing to fix - according to POSIX you are only > allowed to call async-signal-safe functions in the child forked > from a threaded process. If you are trying to do anything other > than that, it may or may not work on FreeBSD, but it is not > guaranteed and is not portable. > > The rationale is that what is the point of forking and creating > more threads, when you can just as easily create more threads in > the parent without forking? The only reason to fork from a threaded > process is to call one of the exec() functions. Well, it worked until the last major set of changes to malloc. For me, the point was that I was able to have transparent background worker threads in any program regardless of its architecture, using the standard pthread fork hooks. Could you point me to the POSIX section covering fork and threads? If it's really not supposed to work then that's fine, but there's an awful lot of code there dedicated to support going threaded again after a fork. >>> Practically, you can't go threaded again after a fork >>> (by which I mean creating new threads or use things >>> like mutexes etc.) in any posix system I know of. >>> >>> It would require that: >>> The forking thread stop until: >>> Every other thread has released every resource it owns >>> and reports itself to be in a "safe quiescent state", >>> or at least report every resource it owns, especially >>> locks, >>> and >>> After the fork: >>> The child, post fork, to take ownership of all >>> of them, and free them. >>> >>> You might be able to do that in a simple >>> threaded program, but consider then that the libraries may have >>> threads running in them of which you are unaware, and that >>> some of the resources may interract with resources owned by the >>> forking thread. >>> >>> Add to this that there may be a signal thrown into this mix as well >>> >>> (signals are the bane of thread developement) >> >> Well, I wouldn't mind showing all of you what I can of what I had been doing >> with the background threads -- it works pretty well modulo this particular >> malloc lock bug. Due to it being inappropriate to share library resources >> between a child and parent for an open socket connection, I always considered >> the only "safe" behavior to be going single-threaded for the duration of the >> fork >> processes in both the parent and child, and the pthread_atfork(3) hooks have >> been >> sufficient to do so. > > > a > well going single threaded for the duration of the fork, changes > everything! Could you, and anyone else who would care to, check this out? It's a regression fix but it also makes the code a little bit clearer. Thanks! Index: lib/libc/stdlib/malloc.c === --- lib/libc/stdlib/malloc.c(revision 187160) +++ lib/libc/stdlib/malloc.c(working copy) @@ -415,6 +415,7 @@ /* Set to true once the allocator has been initialized. */ static bool malloc_initialized = false; +static bool malloc_during_fork = false; /* Used to avoid initialization races. */ static malloc_mutex_t init_lock = {_SPINLOCK_INITIALIZER}; @@ -1205,7 +1206,7 @@ malloc_mutex_lock(malloc_mutex_t *mutex) { - if (__isthreaded) + if (__isthreaded || malloc_during_fork) _SPINLOCK(&mutex->lock); } @@ -1213,7 +1214,7 @@ malloc_mutex_unlock(malloc_mutex_t *mutex) { - if (__isthreaded) + if (__isthreaded || malloc_during_fork) _SPINUNLOCK(&mutex->lock); } @@ -1260,7 +1261,7 @@ { unsigned ret = 0; - if (__isthreaded) { + if (__isthreaded || malloc_during_fork) { if (_pthread_mutex_trylock(lock) != 0) { /* Exponentially back off if there are multiple CPUs. */ if (ncpus > 1) { @@ -1296,7 +1297,7 @@ malloc_spin_unlock(pthread_mutex_t *lock) { - if (__isthreaded) + if (__isthreaded || malloc_during_fork) _pthread_mutex_unlock(lock); } @@ -5515,9 +5516,8 @@ void _malloc_prefork(void) { + arena_t *larenas
Re: threaded, forked, rethreaded processes will deadlock
On Fri, Jan 09, 2009 at 07:42:32PM +0200, Kostik Belousov wrote: > On Fri, Jan 09, 2009 at 11:34:26AM -0500, Brian Fundakowski Feldman wrote: > > On Thu, Jan 08, 2009 at 11:09:16PM -0800, Julian Elischer wrote: > > > Brian Fundakowski Feldman wrote: > > >> On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: > > >>> On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: > > >>> > > It appears that the post-fork hooks for malloc(3) are somewhat broken > > such that > > when a threaded program forks, and then its child attempts to go > > threaded, it > > deadlocks because it already appears to have locks held. I am not > > familiar > > enough with the current libthr/libc/rtld-elf interaction that I've > > been able > > to fix it myself, unfortunately. > > >>> There's really nothing to fix - according to POSIX you are only > > >>> allowed to call async-signal-safe functions in the child forked > > >>> from a threaded process. If you are trying to do anything other > > >>> than that, it may or may not work on FreeBSD, but it is not > > >>> guaranteed and is not portable. > > >>> > > >>> The rationale is that what is the point of forking and creating > > >>> more threads, when you can just as easily create more threads in > > >>> the parent without forking? The only reason to fork from a threaded > > >>> process is to call one of the exec() functions. > > >> > > >> Well, it worked until the last major set of changes to malloc. For me, > > >> the point > > >> was that I was able to have transparent background worker threads in any > > >> program > > >> regardless of its architecture, using the standard pthread fork hooks. > > >> Could you > > >> point me to the POSIX section covering fork and threads? If it's really > > >> not > > >> supposed to work then that's fine, but there's an awful lot of code > > >> there dedicated > > >> to support going threaded again after a fork. > > >> > > > > > > Practically, you can't go threaded again after a fork > > > (by which I mean creating new threads or use things > > > like mutexes etc.) in any posix system I know of. > > > > > > It would require that: > > > The forking thread stop until: > > > Every other thread has released every resource it owns > > > and reports itself to be in a "safe quiescent state", > > > or at least report every resource it owns, especially > > > locks, > > > and > > > After the fork: > > > The child, post fork, to take ownership of all > > > of them, and free them. > > > > > > You might be able to do that in a simple > > > threaded program, but consider then that the libraries may have > > > threads running in them of which you are unaware, and that > > > some of the resources may interract with resources owned by the > > > forking thread. > > > > > > Add to this that there may be a signal thrown into this mix as well > > > > > > (signals are the bane of thread developement) > > > > Well, I wouldn't mind showing all of you what I can of what I had been doing > > with the background threads -- it works pretty well modulo this particular > > malloc lock bug. Due to it being inappropriate to share library resources > > between a child and parent for an open socket connection, I always > > considered > > the only "safe" behavior to be going single-threaded for the duration of > > the fork > > processes in both the parent and child, and the pthread_atfork(3) hooks > > have been > > sufficient to do so. > > > In fact, try recent HEAD, it contains the fixed for deadlocks caused by > fork calls in mt processes. Also, see r185456, that may be directly > relevant to your problem. > > The MFC to the stable/7 is doable, but depends on the MFC of some stuff > committed by David Xu, that would take me some time to look into. Ah, thank you for the pointer. Seems this is an opportunity for me to catch up with our switch to SVN, then. I'll take a further look at this this weekend. For reference, these platforms passed the particular regression test I posted: Linux 2.6.18-92.1.17.el5 SunOS 5.10 Generic_137138-09 Darwin macintosh.green.homeunix.org 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008;root:xnu-1228.9.59~1/RELEASE_I386 i386 FreeBSD 7.0-RELEASE -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Fri, Jan 09, 2009 at 11:34:26AM -0500, Brian Fundakowski Feldman wrote: > On Thu, Jan 08, 2009 at 11:09:16PM -0800, Julian Elischer wrote: > > Brian Fundakowski Feldman wrote: > >> On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: > >>> On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: > >>> > It appears that the post-fork hooks for malloc(3) are somewhat broken > such that > when a threaded program forks, and then its child attempts to go > threaded, it > deadlocks because it already appears to have locks held. I am not > familiar > enough with the current libthr/libc/rtld-elf interaction that I've been > able > to fix it myself, unfortunately. > >>> There's really nothing to fix - according to POSIX you are only > >>> allowed to call async-signal-safe functions in the child forked > >>> from a threaded process. If you are trying to do anything other > >>> than that, it may or may not work on FreeBSD, but it is not > >>> guaranteed and is not portable. > >>> > >>> The rationale is that what is the point of forking and creating > >>> more threads, when you can just as easily create more threads in > >>> the parent without forking? The only reason to fork from a threaded > >>> process is to call one of the exec() functions. > >> > >> Well, it worked until the last major set of changes to malloc. For me, > >> the point > >> was that I was able to have transparent background worker threads in any > >> program > >> regardless of its architecture, using the standard pthread fork hooks. > >> Could you > >> point me to the POSIX section covering fork and threads? If it's really > >> not > >> supposed to work then that's fine, but there's an awful lot of code there > >> dedicated > >> to support going threaded again after a fork. > >> > > > > Practically, you can't go threaded again after a fork > > (by which I mean creating new threads or use things > > like mutexes etc.) in any posix system I know of. > > > > It would require that: > > The forking thread stop until: > > Every other thread has released every resource it owns > > and reports itself to be in a "safe quiescent state", > > or at least report every resource it owns, especially > > locks, > > and > > After the fork: > > The child, post fork, to take ownership of all > > of them, and free them. > > > > You might be able to do that in a simple > > threaded program, but consider then that the libraries may have > > threads running in them of which you are unaware, and that > > some of the resources may interract with resources owned by the > > forking thread. > > > > Add to this that there may be a signal thrown into this mix as well > > > > (signals are the bane of thread developement) > > Well, I wouldn't mind showing all of you what I can of what I had been doing > with the background threads -- it works pretty well modulo this particular > malloc lock bug. Due to it being inappropriate to share library resources > between a child and parent for an open socket connection, I always considered > the only "safe" behavior to be going single-threaded for the duration of the > fork > processes in both the parent and child, and the pthread_atfork(3) hooks have > been > sufficient to do so. > In fact, try recent HEAD, it contains the fixed for deadlocks caused by fork calls in mt processes. Also, see r185456, that may be directly relevant to your problem. The MFC to the stable/7 is doable, but depends on the MFC of some stuff committed by David Xu, that would take me some time to look into. pgpzFbJ3BCzH2.pgp Description: PGP signature
Re: threaded, forked, rethreaded processes will deadlock
Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 11:09:16PM -0800, Julian Elischer wrote: Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. There's really nothing to fix - according to POSIX you are only allowed to call async-signal-safe functions in the child forked from a threaded process. If you are trying to do anything other than that, it may or may not work on FreeBSD, but it is not guaranteed and is not portable. The rationale is that what is the point of forking and creating more threads, when you can just as easily create more threads in the parent without forking? The only reason to fork from a threaded process is to call one of the exec() functions. Well, it worked until the last major set of changes to malloc. For me, the point was that I was able to have transparent background worker threads in any program regardless of its architecture, using the standard pthread fork hooks. Could you point me to the POSIX section covering fork and threads? If it's really not supposed to work then that's fine, but there's an awful lot of code there dedicated to support going threaded again after a fork. Practically, you can't go threaded again after a fork (by which I mean creating new threads or use things like mutexes etc.) in any posix system I know of. It would require that: The forking thread stop until: Every other thread has released every resource it owns and reports itself to be in a "safe quiescent state", or at least report every resource it owns, especially locks, and After the fork: The child, post fork, to take ownership of all of them, and free them. You might be able to do that in a simple threaded program, but consider then that the libraries may have threads running in them of which you are unaware, and that some of the resources may interract with resources owned by the forking thread. Add to this that there may be a signal thrown into this mix as well (signals are the bane of thread developement) Well, I wouldn't mind showing all of you what I can of what I had been doing with the background threads -- it works pretty well modulo this particular malloc lock bug. Due to it being inappropriate to share library resources between a child and parent for an open socket connection, I always considered the only "safe" behavior to be going single-threaded for the duration of the fork processes in both the parent and child, and the pthread_atfork(3) hooks have been sufficient to do so. a well going single threaded for the duration of the fork, changes everything! ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 08, 2009 at 11:09:16PM -0800, Julian Elischer wrote: > Brian Fundakowski Feldman wrote: >> On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: >>> On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: >>> It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. >>> There's really nothing to fix - according to POSIX you are only >>> allowed to call async-signal-safe functions in the child forked >>> from a threaded process. If you are trying to do anything other >>> than that, it may or may not work on FreeBSD, but it is not >>> guaranteed and is not portable. >>> >>> The rationale is that what is the point of forking and creating >>> more threads, when you can just as easily create more threads in >>> the parent without forking? The only reason to fork from a threaded >>> process is to call one of the exec() functions. >> >> Well, it worked until the last major set of changes to malloc. For me, the >> point >> was that I was able to have transparent background worker threads in any >> program >> regardless of its architecture, using the standard pthread fork hooks. >> Could you >> point me to the POSIX section covering fork and threads? If it's really not >> supposed to work then that's fine, but there's an awful lot of code there >> dedicated >> to support going threaded again after a fork. >> > > Practically, you can't go threaded again after a fork > (by which I mean creating new threads or use things > like mutexes etc.) in any posix system I know of. > > It would require that: > The forking thread stop until: > Every other thread has released every resource it owns > and reports itself to be in a "safe quiescent state", > or at least report every resource it owns, especially > locks, > and > After the fork: > The child, post fork, to take ownership of all > of them, and free them. > > You might be able to do that in a simple > threaded program, but consider then that the libraries may have > threads running in them of which you are unaware, and that > some of the resources may interract with resources owned by the > forking thread. > > Add to this that there may be a signal thrown into this mix as well > > (signals are the bane of thread developement) Well, I wouldn't mind showing all of you what I can of what I had been doing with the background threads -- it works pretty well modulo this particular malloc lock bug. Due to it being inappropriate to share library resources between a child and parent for an open socket connection, I always considered the only "safe" behavior to be going single-threaded for the duration of the fork processes in both the parent and child, and the pthread_atfork(3) hooks have been sufficient to do so. -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Fri, 9 Jan 2009, Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. There's really nothing to fix - according to POSIX you are only allowed to call async-signal-safe functions in the child forked from a threaded process. If you are trying to do anything other than that, it may or may not work on FreeBSD, but it is not guaranteed and is not portable. The rationale is that what is the point of forking and creating more threads, when you can just as easily create more threads in the parent without forking? The only reason to fork from a threaded process is to call one of the exec() functions. Well, it worked until the last major set of changes to malloc. For me, the point was that I was able to have transparent background worker threads in any program regardless of its architecture, using the standard pthread fork hooks. Could you point me to the POSIX section covering fork and threads? If it's really not supposed to work then that's fine, but there's an awful lot of code there dedicated to support going threaded again after a fork. I don't know if this link will work for you, but you can start here: http://www.opengroup.org/onlinepubs/009695399/nframe.html "It is suggested that programs that use fork() call an exec function very soon afterwards in the child process, thus resetting all states. In the meantime, only a short list of async-signal-safe library routines are promised to be available." -- DE -- ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. There's really nothing to fix - according to POSIX you are only allowed to call async-signal-safe functions in the child forked from a threaded process. If you are trying to do anything other than that, it may or may not work on FreeBSD, but it is not guaranteed and is not portable. The rationale is that what is the point of forking and creating more threads, when you can just as easily create more threads in the parent without forking? The only reason to fork from a threaded process is to call one of the exec() functions. Well, it worked until the last major set of changes to malloc. For me, the point was that I was able to have transparent background worker threads in any program regardless of its architecture, using the standard pthread fork hooks. Could you point me to the POSIX section covering fork and threads? If it's really not supposed to work then that's fine, but there's an awful lot of code there dedicated to support going threaded again after a fork. Practically, you can't go threaded again after a fork (by which I mean creating new threads or use things like mutexes etc.) in any posix system I know of. It would require that: The forking thread stop until: Every other thread has released every resource it owns and reports itself to be in a "safe quiescent state", or at least report every resource it owns, especially locks, and After the fork: The child, post fork, to take ownership of all of them, and free them. You might be able to do that in a simple threaded program, but consider then that the libraries may have threads running in them of which you are unaware, and that some of the resources may interract with resources owned by the forking thread. Add to this that there may be a signal thrown into this mix as well (signals are the bane of thread developement) ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
Brian Fundakowski Feldman wrote: On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. What version of FreeBSD? I've only glanced through the relevant code, but the malloc() implementation in -CURRENT certainly tries to claim all malloc locks before the fork and releases them all (in both child and parent) just after the fork, so the scenario you describe shouldn't happen. Of course, there may be other locks getting in the way. Tim ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, Jan 08, 2009 at 10:44:20PM -0500, Daniel Eischen wrote: > On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: > >> It appears that the post-fork hooks for malloc(3) are somewhat broken such >> that >> when a threaded program forks, and then its child attempts to go threaded, it >> deadlocks because it already appears to have locks held. I am not familiar >> enough with the current libthr/libc/rtld-elf interaction that I've been able >> to fix it myself, unfortunately. > > There's really nothing to fix - according to POSIX you are only > allowed to call async-signal-safe functions in the child forked > from a threaded process. If you are trying to do anything other > than that, it may or may not work on FreeBSD, but it is not > guaranteed and is not portable. > > The rationale is that what is the point of forking and creating > more threads, when you can just as easily create more threads in > the parent without forking? The only reason to fork from a threaded > process is to call one of the exec() functions. Well, it worked until the last major set of changes to malloc. For me, the point was that I was able to have transparent background worker threads in any program regardless of its architecture, using the standard pthread fork hooks. Could you point me to the POSIX section covering fork and threads? If it's really not supposed to work then that's fine, but there's an awful lot of code there dedicated to support going threaded again after a fork. -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
In the last episode (Jan 08), Daniel Eischen said: > On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: > > It appears that the post-fork hooks for malloc(3) are somewhat > > broken such that when a threaded program forks, and then its child > > attempts to go threaded, it deadlocks because it already appears to > > have locks held. I am not familiar enough with the current > > libthr/libc/rtld-elf interaction that I've been able to fix it > > myself, unfortunately. > > There's really nothing to fix - according to POSIX you are only > allowed to call async-signal-safe functions in the child forked from > a threaded process. If you are trying to do anything other than > that, it may or may not work on FreeBSD, but it is not guaranteed and > is not portable. The Rationale section of the pthread_atfork() page is a good read here, too. -- Dan Nelson dnel...@allantgroup.com ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
Re: threaded, forked, rethreaded processes will deadlock
On Thu, 8 Jan 2009, Brian Fundakowski Feldman wrote: It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. There's really nothing to fix - according to POSIX you are only allowed to call async-signal-safe functions in the child forked from a threaded process. If you are trying to do anything other than that, it may or may not work on FreeBSD, but it is not guaranteed and is not portable. The rationale is that what is the point of forking and creating more threads, when you can just as easily create more threads in the parent without forking? The only reason to fork from a threaded process is to call one of the exec() functions. -- DE___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
threaded, forked, rethreaded processes will deadlock
It appears that the post-fork hooks for malloc(3) are somewhat broken such that when a threaded program forks, and then its child attempts to go threaded, it deadlocks because it already appears to have locks held. I am not familiar enough with the current libthr/libc/rtld-elf interaction that I've been able to fix it myself, unfortunately. I discovered this today upgrading my work box from 7.0 to 7.1, but I can easily reproduce it at home on a stale -CURRENT as well. Testing on an OS X box to make sure, the regression test does exit 0 there. Has anyone happened to have fixed this already locally? -- Brian Fundakowski Feldman \'[ FreeBSD ]''\ <> gr...@freebsd.org \ The Power to Serve! \ Opinions expressed are my own. \,,\ ___ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"