summaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/fork.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/fork.c')
-rw-r--r--sysdeps/mach/hurd/fork.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 60c34c7620..6e5a7bece2 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <hurd.h>
#include <hurd/signal.h>
+#include <hurd/threadvar.h>
#include <setjmp.h>
#include <thread_state.h>
#include <sysdep.h> /* For stack growth direction. */
@@ -129,9 +130,13 @@ __fork (void)
ports_locked = 1;
+ /* Keep our SS locked while stopping other threads, so they don't get a
+ chance to have it locked in the copied space. */
+ __spin_lock (&ss->lock);
/* Stop all other threads while copying the address space,
so nothing changes. */
err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread);
+ __spin_unlock (&ss->lock);
if (!err)
{
stopped = 1;
@@ -464,6 +469,7 @@ __fork (void)
function, accounted for by mach_port_names (and which will thus be
accounted for in the child below). This extra right gets consumed
in the child by the store into _hurd_sigthread in the child fork. */
+ /* XXX consumed? (_hurd_sigthread is no more) */
if (thread_refs > 1 &&
(err = __mach_port_mod_refs (newtask, ss->thread,
MACH_PORT_RIGHT_SEND,
@@ -504,19 +510,17 @@ __fork (void)
(natural_t *) &state, &statecount))
LOSE;
#if STACK_GROWTH_UP
-#define THREADVAR_SPACE (__hurd_threadvar_max \
- * sizeof *__hurd_sightread_variables)
if (__hurd_sigthread_stack_base == 0)
{
state.SP &= __hurd_threadvar_stack_mask;
- state.SP += __hurd_threadvar_stack_offset + THREADVAR_SPACE;
+ state.SP += __hurd_threadvar_stack_offset;
}
else
state.SP = __hurd_sigthread_stack_base;
#else
if (__hurd_sigthread_stack_end == 0)
{
- /* The signal thread has a normal stack assigned by cthreads.
+ /* The signal thread has a stack assigned by cthreads.
The threadvar_stack variables conveniently tell us how
to get to the highest address in the stack, just below
the per-thread variables. */
@@ -528,6 +532,11 @@ __fork (void)
#endif
MACHINE_THREAD_STATE_SET_PC (&state,
(unsigned long int) _hurd_msgport_receive);
+
+ /* Do special thread setup for TLS if needed. */
+ if (err = _hurd_tls_fork (sigthread, _hurd_msgport_thread, &state))
+ LOSE;
+
if (err = __thread_set_state (sigthread, MACHINE_THREAD_STATE_FLAVOR,
(natural_t *) &state, statecount))
LOSE;
@@ -538,7 +547,7 @@ __fork (void)
_hurd_longjmp_thread_state (&state, env, 1);
/* Do special thread setup for TLS if needed. */
- if (err = _hurd_tls_fork (thread, &state))
+ if (err = _hurd_tls_fork (thread, ss->thread, &state))
LOSE;
if (err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
@@ -621,10 +630,6 @@ __fork (void)
for (i = 0; i < _hurd_nports; ++i)
__spin_unlock (&_hurd_ports[i].lock);
- /* We are one of the (exactly) two threads in this new task, we
- will take the task-global signals. */
- _hurd_sigthread = ss->thread;
-
/* Claim our sigstate structure and unchain the rest: the
threads existed in the parent task but don't exist in this
task (the child process). Delay freeing them until later
@@ -644,6 +649,25 @@ __fork (void)
ss->next = NULL;
_hurd_sigstates = ss;
__mutex_unlock (&_hurd_siglock);
+ /* Earlier on, the global sigstate may have been tainted and now needs to
+ be reinitialized. Nobody is interested in its present state anymore:
+ we're not, the signal thread will be restarted, and there are no other
+ threads.
+
+ We can't simply allocate a fresh global sigstate here, as
+ _hurd_thread_sigstate will call malloc and that will deadlock trying
+ to determine the current thread's sigstate. */
+#if 0
+ _hurd_thread_sigstate_init (_hurd_global_sigstate, MACH_PORT_NULL);
+#else
+ /* Only reinitialize the lock -- otherwise we might have to do additional
+ setup as done in hurdsig.c:_hurdsig_init. */
+ __spin_lock_init (&_hurd_global_sigstate->lock);
+#endif
+
+ /* We are one of the (exactly) two threads in this new task, we
+ will take the task-global signals. */
+ _hurd_sigstate_set_global_rcv (ss);
/* Fetch our new process IDs from the proc server. No need to
refetch our pgrp; it is always inherited from the parent (so
@@ -652,8 +676,10 @@ __fork (void)
err = __USEPORT (PROC, __proc_getpids (port, &_hurd_pid, &_hurd_ppid,
&_hurd_orphaned));
- /* Forking clears the trace flag. */
+ /* Forking clears the trace flag and pending masks. */
__sigemptyset (&_hurdsig_traced);
+ __sigemptyset (&_hurd_global_sigstate->pending);
+ __sigemptyset (&ss->pending);
/* Run things that want to run in the child task to set up. */
RUN_HOOK (_hurd_fork_child_hook, ());