diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/mach/hurd/Makefile | 4 | ||||
-rw-r--r-- | sysdeps/mach/hurd/fork.c | 171 |
2 files changed, 97 insertions, 78 deletions
diff --git a/sysdeps/mach/hurd/Makefile b/sysdeps/mach/hurd/Makefile index 02430faed9..d1e8580e93 100644 --- a/sysdeps/mach/hurd/Makefile +++ b/sysdeps/mach/hurd/Makefile @@ -128,6 +128,10 @@ ifeq (,$(subdir)) install-others += $(libdir)/libc.a $(libdir)/libc.a: $(hurd)/libc-ldscript; $(do-install) endif + +# For the shared library, we don't need to do the linker script machination. +# Instead, we specify the required libraries when building the shared object. +LDLIBS-c.so = -lmachuser -lhurduser endif # in-Makerules diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c index b9170f155e..8e625b8e5e 100644 --- a/sysdeps/mach/hurd/fork.c +++ b/sysdeps/mach/hurd/fork.c @@ -67,24 +67,14 @@ __fork (void) error_t err; thread_t thread_self = __mach_thread_self (); struct hurd_sigstate *volatile ss; - sigset_t pending; - - void unlockss (void) - { - __spin_lock (&ss->lock); - ss->critical_section = 0; - pending = ss->pending & ~ss->blocked; - __spin_unlock (&ss->lock); - /* XXX Copying mutex into child and calling mutex_unlock lossy. */ - __mutex_unlock (&_hurd_siglock); - ss = NULL; /* Make sure we crash if we use it again. */ - } ss = _hurd_self_sigstate (); __spin_lock (&ss->lock); ss->critical_section = 1; __spin_unlock (&ss->lock); - __mutex_lock (&_hurd_siglock); + +#undef LOSE +#define LOSE assert_perror (err) /* XXX */ if (! setjmp (env)) { @@ -108,6 +98,7 @@ __fork (void) /* Lock things that want to be locked before we fork. */ for (i = 0; i < _hurd_fork_locks.n; ++i) __mutex_lock (_hurd_fork_locks.locks[i]); + __mutex_lock (&_hurd_siglock); newtask = MACH_PORT_NULL; thread = sigthread = MACH_PORT_NULL; @@ -121,31 +112,37 @@ __fork (void) ports_locked = 1; /* Create the child task. It will inherit a copy of our memory. */ - if (err = __task_create (__mach_task_self (), 1, &newtask)) - goto lose; + err = __task_create (__mach_task_self (), 1, &newtask); + + /* Unlock the global signal state lock, so we do not + block the signal thread any longer than necessary. */ + __mutex_unlock (&_hurd_siglock); + + if (err) + LOSE; /* Fetch the names of all ports used in this task. */ if (err = __mach_port_names (__mach_task_self (), &portnames, &nportnames, &porttypes, &nporttypes)) - goto lose; + LOSE; if (nportnames != nporttypes) { err = EGRATUITOUS; - goto lose; + LOSE; } /* Get send rights for all the threads in this task. We want to avoid giving these rights to the child. */ if (err = __task_threads (__mach_task_self (), &threads, &nthreads)) - goto lose; + LOSE; /* Get the child process's proc server port. We will insert it into the child with the same name as we use for our own proc server port; and we will need it to set the child's message port. */ if (err = __proc_task2proc (_hurd_ports[INIT_PORT_PROC].port, newtask, &newproc)) - goto lose; + LOSE; /* Insert all our port rights into the child task. */ thread_refs = sigthread_refs = 0; @@ -187,7 +184,7 @@ __fork (void) })); } else if (err) - goto lose; + LOSE; if (porttypes[i] & MACH_PORT_TYPE_SEND) { /* Give the child as many send rights for its receive @@ -199,12 +196,12 @@ __fork (void) portnames[i], MACH_PORT_RIGHT_SEND, &refs)) - goto lose; + LOSE; if (err = __mach_port_extract_right (newtask, portnames[i], MACH_MSG_TYPE_MAKE_SEND, &port, &poly)) - goto lose; + LOSE; if (portnames[i] == _hurd_msgport) { /* We just created a receive right for the child's @@ -213,7 +210,7 @@ __fork (void) for it, give it to the proc server. */ mach_port_t old; if (err = __proc_setmsgport (newproc, port, &old)) - goto lose; + LOSE; if (old != MACH_PORT_NULL) /* XXX what to do here? */ __mach_port_deallocate (__mach_task_self (), old); @@ -222,13 +219,13 @@ __fork (void) portnames[i], port, MACH_MSG_TYPE_MOVE_SEND)) - goto lose; + LOSE; if (refs > 1 && (err = __mach_port_mod_refs (newtask, portnames[i], MACH_PORT_RIGHT_SEND, refs - 1))) - goto lose; + LOSE; } if (porttypes[i] & MACH_PORT_TYPE_SEND_ONCE) { @@ -241,15 +238,16 @@ __fork (void) portnames[i], MACH_MSG_TYPE_MAKE_SEND_ONCE, &port, &poly)) - goto lose; + LOSE; if (err = __mach_port_insert_right (newtask, portnames[i], port, MACH_MSG_TYPE_MOVE_SEND_ONCE)) - goto lose; + LOSE; } } - else if (porttypes[i] & MACH_PORT_TYPE_SEND) + else if (porttypes[i] & + (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_DEAD_NAME)) { /* This is a send right or a dead name. Give the child as many references for it as we have. */ @@ -266,7 +264,7 @@ __fork (void) { /* Get the proc server port for the new task. */ if (err = __proc_task2proc (portnames[i], newtask, &insert)) - goto lose; + LOSE; } else if (portnames[i] == thread_self) { @@ -281,7 +279,7 @@ __fork (void) rights created when a thread is created). */ if (err = __mach_port_allocate_name (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i])) - goto lose; + LOSE; } else if (portnames[i] == _hurd_msgport_thread) /* For the name we use for our signal thread's thread port, @@ -293,7 +291,7 @@ __fork (void) /* Allocate a dead name right as a placeholder. */ if (err = __mach_port_allocate_name (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i])) - goto lose; + LOSE; } else { @@ -313,38 +311,61 @@ __fork (void) portnames[i], MACH_PORT_RIGHT_SEND, record_refs ?: &refs)) - goto lose; + LOSE; if (insert == MACH_PORT_NULL) continue; - /* Insert the chosen send right into the child. */ - err = __mach_port_insert_right (newtask, - portnames[i], - insert, - MACH_MSG_TYPE_COPY_SEND); - if (err == KERN_NAME_EXISTS) + if (insert == portnames[i] && + (porttypes[i] & MACH_PORT_TYPE_DEAD_NAME)) + /* This is a dead name; allocate another dead name + with the same name in the child. */ + allocate_dead_name: + err = __mach_port_allocate_name (newtask, + MACH_PORT_RIGHT_DEAD_NAME, + portnames[i]); + else + /* Insert the chosen send right into the child. */ + err = __mach_port_insert_right (newtask, + portnames[i], + insert, + MACH_MSG_TYPE_COPY_SEND); + switch (err) { - /* It already has a send right under this name (?!). - Well, it starts out with a send right for its task - port, and inherits the bootstrap and exception ports - from us. */ - mach_port_t childport; - mach_msg_type_name_t poly; - assert (__mach_port_extract_right (newtask, portnames[i], - MACH_MSG_TYPE_COPY_SEND, - &childport, &poly) == 0 && - childport == insert && - __mach_port_deallocate (__mach_task_self (), - childport) == 0); + case KERN_NAME_EXISTS: + { + /* It already has a send right under this name (?!). + Well, it starts out with a send right for its task + port, and inherits the bootstrap and exception ports + from us. */ + mach_port_t childport; + mach_msg_type_name_t poly; + assert (__mach_port_extract_right (newtask, portnames[i], + MACH_MSG_TYPE_COPY_SEND, + &childport, + &poly) == 0 && + childport == insert && + __mach_port_deallocate (__mach_task_self (), + childport) == 0); + break; + } + + case KERN_INVALID_CAPABILITY: + /* The port just died. It was a send right, + and now it's a dead name. */ + goto allocate_dead_name; + + default: + LOSE; + break; + + case KERN_SUCCESS: + /* Give the child as many user references as we have. */ + if (refs > 1 && + (err = __mach_port_mod_refs (newtask, + portnames[i], + MACH_PORT_RIGHT_SEND, + refs - 1))) + LOSE; } - else if (err) - goto lose; - /* Give the child as many user references as we have. */ - if (refs > 1 && - (err = __mach_port_mod_refs (newtask, - portnames[i], - MACH_PORT_RIGHT_SEND, - refs - 1))) - goto lose; } } @@ -354,13 +375,10 @@ __fork (void) __spin_unlock (&_hurd_ports[i].lock); ports_locked = 0; - /* Unlock the signal state. The child must unlock its own copy too. */ - unlockss (); - /* Create the child main user thread and signal thread. */ if ((err = __thread_create (newtask, &thread)) || (err = __thread_create (newtask, &sigthread))) - goto lose; + LOSE; /* Insert send rights for those threads. We previously allocated dead name rights with the names we want to give the thread ports @@ -369,7 +387,7 @@ __fork (void) if ((err = __mach_port_deallocate (newtask, thread_self)) || (err = __mach_port_insert_right (newtask, thread_self, thread, MACH_MSG_TYPE_COPY_SEND))) - goto lose; + LOSE; /* We have one extra user reference created at the beginning of this function, accounted for by mach_port_names (and which will thus be accounted for in the child below). This extra right gets consumed @@ -378,18 +396,18 @@ __fork (void) (err = __mach_port_mod_refs (newtask, thread_self, MACH_PORT_RIGHT_SEND, thread_refs - 1))) - goto lose; + LOSE; if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none. */ && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) || (err = __mach_port_insert_right (newtask, _hurd_msgport_thread, sigthread, MACH_MSG_TYPE_COPY_SEND)))) - goto lose; + LOSE; if (sigthread_refs > 1 && (err = __mach_port_mod_refs (newtask, _hurd_msgport_thread, MACH_PORT_RIGHT_SEND, sigthread_refs - 1))) - goto lose; + LOSE; /* This seems like a convenient juncture to copy the proc server's idea of what addresses our argv and envp are found at from the @@ -400,7 +418,7 @@ __fork (void) err = (__USEPORT (PROC, __proc_get_arg_locations (port, &argv, &envp)) ?: __proc_set_arg_locations (newproc, argv, envp)); if (err) - goto lose; + LOSE; } /* Set the child signal thread up to run the msgport server function @@ -412,7 +430,7 @@ __fork (void) if (err = __thread_get_state (_hurd_msgport_thread, MACHINE_THREAD_STATE_FLAVOR, (natural_t *) &state, &statecount)) - goto lose; + LOSE; #if STACK_GROWTH_UP state.SP = __hurd_sigthread_stack_base; #else @@ -422,7 +440,7 @@ __fork (void) (unsigned long int) _hurd_msgport_receive); if (err = __thread_set_state (sigthread, MACHINE_THREAD_STATE_FLAVOR, (natural_t *) &state, statecount)) - goto lose; + LOSE; /* We do not thread_resume SIGTHREAD here because the child fork needs to do more setup before it can take signals. */ @@ -430,13 +448,13 @@ __fork (void) _hurd_longjmp_thread_state (&state, env, 1); if (err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR, (natural_t *) &state, statecount)) - goto lose; + LOSE; /* Get the PID of the child from the proc server. We must do this before calling proc_child below, because at that point any authorized POSIX.1 process may kill the child task with SIGKILL. */ if (err = __USEPORT (PROC, __proc_task2pid (port, newtask, &pid))) - goto lose; + LOSE; /* Register the child with the proc server. It is important that this be that last thing we do before starting the child thread @@ -445,7 +463,7 @@ __fork (void) this point, and the child must have a message port so it responds to POSIX.1 signals. */ if (err = __USEPORT (PROC, __proc_child (port, newtask))) - goto lose; + LOSE; /* This must be the absolutely last thing we do; we can't assume that the child will remain alive for even a moment once we do this. We @@ -527,9 +545,7 @@ __fork (void) } ss->next = NULL; _hurd_sigstates = ss; - - /* Unlock our copies of the signal state locks. */ - unlockss (); + __mutex_unlock (&_hurd_siglock); /* Fetch our new process IDs from the proc server. No need to refetch our pgrp; it is always inherited from the parent (so @@ -565,8 +581,7 @@ __fork (void) for (i = 0; i < _hurd_fork_locks.n; ++i) __mutex_unlock (_hurd_fork_locks.locks[i]); - if (pending) - __msg_sig_post (_hurd_msgport, 0, __mach_task_self ()); + _hurd_critical_section_unlock (ss); return err ? __hurd_fail (err) : pid; } |