diff options
Diffstat (limited to 'sysdeps/nptl/fork.c')
-rw-r--r-- | sysdeps/nptl/fork.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index 1a68cbd647..616d897a36 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -54,6 +54,12 @@ __libc_fork (void) struct used_handler *next; } *allp = NULL; + /* Determine if we are running multiple threads. We skip some fork + handlers in the single-thread case, to make fork safer to use in + signal handlers. POSIX requires that fork is async-signal-safe, + but our current fork implementation is not. */ + bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); + /* Run all the registered preparation handlers. In reverse order. While doing this we build up a list of all the entries. */ struct fork_handler *runp; @@ -109,12 +115,21 @@ __libc_fork (void) break; } - _IO_list_lock (); + /* If we are not running multiple threads, we do not have to + preserve lock state. If fork runs from a signal handler, only + async-signal-safe functions can be used in the child. These data + structures are only used by unsafe functions, so their state does + not matter if fork was called from a signal handler. */ + if (multiple_threads) + { + _IO_list_lock (); - /* Acquire malloc locks. This needs to come last because fork - handlers may use malloc, and the libio list lock has an indirect - malloc dependency as well (via the getdelim function). */ - __malloc_fork_lock_parent (); + /* Acquire malloc locks. This needs to come last because fork + handlers may use malloc, and the libio list lock has an + indirect malloc dependency as well (via the getdelim + function). */ + __malloc_fork_lock_parent (); + } #ifndef NDEBUG pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); @@ -173,14 +188,18 @@ __libc_fork (void) # endif #endif - /* Release malloc locks. */ - __malloc_fork_unlock_child (); + /* Reset the lock state in the multi-threaded case. */ + if (multiple_threads) + { + /* Release malloc locks. */ + __malloc_fork_unlock_child (); - /* Reset the file list. These are recursive mutexes. */ - fresetlockfiles (); + /* Reset the file list. These are recursive mutexes. */ + fresetlockfiles (); - /* Reset locks in the I/O code. */ - _IO_list_resetlock (); + /* Reset locks in the I/O code. */ + _IO_list_resetlock (); + } /* Reset the lock the dynamic loader uses to protect its data. */ __rtld_lock_initialize (GL(dl_load_lock)); @@ -217,11 +236,15 @@ __libc_fork (void) /* Restore the PID value. */ THREAD_SETMEM (THREAD_SELF, pid, parentpid); - /* Release malloc locks, parent process variant. */ - __malloc_fork_unlock_parent (); + /* Release acquired locks in the multi-threaded case. */ + if (multiple_threads) + { + /* Release malloc locks, parent process variant. */ + __malloc_fork_unlock_parent (); - /* We execute this even if the 'fork' call failed. */ - _IO_list_unlock (); + /* We execute this even if the 'fork' call failed. */ + _IO_list_unlock (); + } /* Run the handlers registered for the parent. */ while (allp != NULL) |