--- /usr/src/lib/libc/stdlib/malloc.c Tue Apr 20 16:43:25 2004 +++ /usr/src/lib/libc/stdlib/malloc.c Thu Dec 29 08:19:54 2005 @@ -60,9 +60,9 @@ */ # include "libc_private.h" # include "spinlock.h" - static spinlock_t thread_lock = _SPINLOCK_INITIALIZER; -# define THREAD_LOCK() if (__isthreaded) _SPINLOCK(&thread_lock); -# define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock); + spinlock_t _malloc_thread_lock = _SPINLOCK_INITIALIZER; +# define THREAD_LOCK() if (__isthreaded) _SPINLOCK(&_malloc_thread_lock); +# define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&_malloc_thread_lock); #endif /* __FreeBSD__ */ #if defined(__sparc__) && defined(sun) --- /usr/src/lib/libc_r/uthread/uthread_fork.c Tue Oct 22 16:44:03 2002 +++ /usr/src/lib/libc_r/uthread/uthread_fork.c Thu Dec 29 15:34:41 2005 @@ -37,8 +37,28 @@ #include #include #include +#include #include "pthread_private.h" +/* Very ugly code to assure that none of the libc locks are locked when forking. + */ + +extern spinlock_t _malloc_thread_lock; + +static void +_fork_get_locks(void) +{ + if (__isthreaded) + _SPINLOCK(&_malloc_thread_lock); +} + +static void +_fork_release_locks(void) +{ + if (__isthreaded) + _SPINUNLOCK(&_malloc_thread_lock); +} + pid_t _fork(void) { @@ -48,6 +68,12 @@ pthread_t pthread; pthread_t pthread_save; + /* Get all the locks in libc so that the new process will start in a + * consistent state. + */ + + _fork_get_locks(); + /* * Defer signals to protect the scheduling queues from access * by the signal handler: @@ -56,7 +82,8 @@ /* Fork a new process: */ if ((ret = __sys_fork()) != 0) { - /* Parent process or error. Nothing to do here. */ + /* Make sure we can handle signals again in the parent. */ + _thread_kern_sig_undefer(); } else { /* Close the pthread kernel pipe: */ __sys_close(_thread_kern_pipe[0]); @@ -109,6 +136,11 @@ /* Abort this application: */ PANIC("Cannot initialize priority ready queue."); } else { + /* Release all the libc locks so that we can do things. + */ + + _fork_release_locks(); + /* * Enter a loop to remove all threads other than * the running thread from the thread list: @@ -207,12 +239,24 @@ } } } + + /* We do not call _thread_kern_sig_undefer() here unless the + * parent hadn't started any threads yet. This means that the + * child is unable to proces signals. This is not necessary + * anyway, because the child is supposed to call exec() as soon + * as possible. The thread scheduler is not going to be used in + * the child, because there is only one thread and the child is + * not allowed to create any more threads. + */ + + if (!__isthreaded) + _thread_kern_sig_undefer(); } - /* - * Undefer and handle pending signals, yielding if necessary: + /* Release all the locks that we have in libc. */ - _thread_kern_sig_undefer(); + + _fork_release_locks(); /* Return the process ID: */ return (ret);