diff options
author | Roland McGrath <roland@gnu.org> | 1995-04-24 09:00:07 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-04-24 09:00:07 +0000 |
commit | 11872325e2cf0443e17d50eebbf883eb0c24ea27 (patch) | |
tree | 7b43aa9bc213e898d1f3add3cb6b6fec42503086 | |
parent | b96bdcd7d92fb44e9e2ad2458fdff03bda715151 (diff) | |
download | glibc-11872325e2cf0443e17d50eebbf883eb0c24ea27.tar.gz glibc-11872325e2cf0443e17d50eebbf883eb0c24ea27.tar.xz glibc-11872325e2cf0443e17d50eebbf883eb0c24ea27.zip |
Sat Apr 22 14:48:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* mach/Machrules [interface-library] (LDFLAGS-$(interface-library:lib%=%.so)): New variable, set to -nostdlib. * sysdeps/mach/hurd/fork.c: Subfunction `unlockss' removed. Lock _hurd_siglock only around initial task creation in parent. Use _hurd_critical_section_unlock at end. Handle dead name rights properly, and deal with a send right dying while we try to copy it. For the time being, use assert_perror for kernel and proc RPC failures. Fri Apr 21 01:10:15 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> * extra-lib.mk: Don't include $(o-iterator); construct it by hand using $(object-suffixes-$(lib)) instead. * sysdeps/mach/hurd/Makefile (LDLIBS-c.so): New variable. * Makerules (lib%.so: lib%_pic.a): Pass $(LDFLAGS-$(notdir $*).so). (LDFLAGS-c.so): New variable. * resolv/res_init.c (res_init): Don't clobber _res.options with RES_DEFAULT. If RES_INIT is clear, OR in RES_DEFAULT. * hurd/hurd.h: Declare _hurd_startup. * hurd/hurdstartup.c: New file. * hurd/Makefile (routines): Add hurdstartup.
-rw-r--r-- | ChangeLog | 30 | ||||
-rw-r--r-- | Makerules | 6 | ||||
-rw-r--r-- | extra-lib.mk | 2 | ||||
-rw-r--r-- | hurd/Makefile | 3 | ||||
-rw-r--r-- | hurd/hurd.h | 17 | ||||
-rw-r--r-- | hurd/hurdstartup.c | 302 | ||||
-rw-r--r-- | mach/Machrules | 6 | ||||
-rw-r--r-- | resolv/res_init.c | 4 | ||||
-rw-r--r-- | sysdeps/mach/hurd/Makefile | 4 | ||||
-rw-r--r-- | sysdeps/mach/hurd/fork.c | 171 |
10 files changed, 463 insertions, 82 deletions
diff --git a/ChangeLog b/ChangeLog index 193ca761c1..d33d7af2d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +Sat Apr 22 14:48:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * mach/Machrules [interface-library] + (LDFLAGS-$(interface-library:lib%=%.so)): New variable, set to + -nostdlib. + + * sysdeps/mach/hurd/fork.c: Subfunction `unlockss' removed. Lock + _hurd_siglock only around initial task creation in parent. Use + _hurd_critical_section_unlock at end. Handle dead name rights + properly, and deal with a send right dying while we try to copy + it. For the time being, use assert_perror for kernel and proc RPC + failures. + +Fri Apr 21 01:10:15 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * extra-lib.mk: Don't include $(o-iterator); construct it by hand + using $(object-suffixes-$(lib)) instead. + + * sysdeps/mach/hurd/Makefile (LDLIBS-c.so): New variable. + + * Makerules (lib%.so: lib%_pic.a): Pass $(LDFLAGS-$(notdir $*).so). + (LDFLAGS-c.so): New variable. + + * resolv/res_init.c (res_init): Don't clobber _res.options with + RES_DEFAULT. If RES_INIT is clear, OR in RES_DEFAULT. + + * hurd/hurd.h: Declare _hurd_startup. + * hurd/hurdstartup.c: New file. + * hurd/Makefile (routines): Add hurdstartup. + Thu Apr 20 22:23:58 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> * hurd/hurdsig.c: Use assert_perror for many calls which should diff --git a/Makerules b/Makerules index 64282fb8ec..f19a9f7b71 100644 --- a/Makerules +++ b/Makerules @@ -342,8 +342,14 @@ ifeq (yes,$(build-shared)) # on other shared objects. lib%.so: lib%_pic.a $(LINK.o) -shared -o $@ -Wl,--whole-archive $< \ + $(LDFLAGS-$(notdir $*).so) \ -L$(firstword $(objdir) .) -L$(common-objpfx:%/=%) \ $(LDLIBS-$(notdir $*).so) + +# Don't try to use -lc when making libc.so itself. +# Also omits crti.o and crtn.o, which we do not want +# since we define our own `.init' section specially. +LDFLAGS-c.so = -nostdlib endif libobjs: $(foreach o,$(object-suffixes),\ diff --git a/extra-lib.mk b/extra-lib.mk index d4d2b52829..c62450a06f 100644 --- a/extra-lib.mk +++ b/extra-lib.mk @@ -33,4 +33,4 @@ $(objpfx)$(patsubst %,$(libtype$o),$(lib:lib%=%)): \ $($(lib)-routines:%=$(objpfx)%$o); $$(build-extra-lib) endef object-suffixes-left = $(object-suffixes-$(lib)) -include $(o-iterator) +include $(patsubst %,$(..)o-iterator.mk,$(object-suffixes-$(lib))) diff --git a/hurd/Makefile b/hurd/Makefile index 254e89cb50..0ef626f5e3 100644 --- a/hurd/Makefile +++ b/hurd/Makefile @@ -39,7 +39,8 @@ user-interfaces := $(addprefix hurd/,\ fs fsys io term socket ifsock) server-interfaces := hurd/msg -routines = hurdinit hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \ +routines = hurdstartup hurdinit \ + hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \ setauth \ pid2task task2pid \ getuids setuids getumask fchroot \ diff --git a/hurd/hurd.h b/hurd/hurd.h index 968910fffb..77b8acf9d0 100644 --- a/hurd/hurd.h +++ b/hurd/hurd.h @@ -227,6 +227,23 @@ extern error_t _hurd_exec (task_t task, extern void _hurd_exit (int status) __attribute__ ((noreturn)); +/* Initialize Mach RPCs and essential Hurd things (_hurd_preinit_hook); do + initial handshake with the exec server (or extract the arguments from + the stack in the case of the bootstrap task); if cthreads is in use, + initialize it now and switch the calling thread to a cthread stack; + finally, call *MAIN with the information gleaned. That function is not + expected to return. ARGPTR should be the address of the first argument + of the entry point function that is called with the stack exactly as the + exec server or kernel sets it. */ + +extern void _hurd_startup (void **argptr, + void (*main) (int argc, char **argv, char **envp, + mach_port_t *portarray, + mach_msg_type_number_t portarraysize, + int *intarray, + mach_msg_type_number_t intarraysize)) + __attribute__ ((noreturn)); + /* Initialize the library data structures from the ints and ports passed to us by the exec server. Then vm_deallocate PORTARRAY and INTARRAY. */ diff --git a/hurd/hurdstartup.c b/hurd/hurdstartup.c new file mode 100644 index 0000000000..1612859884 --- /dev/null +++ b/hurd/hurdstartup.c @@ -0,0 +1,302 @@ +/* Initial program startup for running under the GNU Hurd. +Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <hurd.h> +#include <hurd/exec.h> +#include <sysdep.h> +#include <hurd/threadvar.h> +#include <unistd.h> +#include "set-hooks.h" +#include "hurdmalloc.h" /* XXX */ + +mach_port_t *_hurd_init_dtable; +mach_msg_type_number_t _hurd_init_dtablesize; + +unsigned int __hurd_threadvar_max; +unsigned long int __hurd_threadvar_stack_mask; +unsigned long int __hurd_threadvar_stack_offset; + +/* These are set up by _hurdsig_init. */ +unsigned long int __hurd_sigthread_stack_base; +unsigned long int __hurd_sigthread_stack_end; +unsigned long int *__hurd_sigthread_variables; + +vm_address_t _hurd_stack_base; +vm_size_t _hurd_stack_size; + +/* Things that want to be run before _hurd_init or much anything else. + Importantly, these are called before anything tries to use malloc. */ +DEFINE_HOOK (_hurd_preinit_hook, (void)); + +extern void __mach_init (void); +extern void __libc_init (int argc, char **argv, char **envp); + +void *(*_cthread_init_routine) (void); /* Returns new SP to use. */ +void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__)); + +int _hurd_split_args (char *, size_t, char **); + +/* These communicate values from _hurd_startup to start1, + where we cannot use the stack for anything. */ +struct info + { + char *args, *env; + mach_port_t *portarray; + int *intarray; + mach_msg_type_number_t argslen, envlen, portarraysize, intarraysize; + int flags; + char **argv, **envp; + int argc; + void (*hurd_main) (int, char **, char **, + mach_port_t *, mach_msg_type_number_t, + int *, mach_msg_type_number_t); + }; + +static void start1 (struct info *) __attribute__ ((__noreturn__)); + + +/* Entry point. This is the first thing in the text segment. + + The exec server started the initial thread in our task with this spot the + PC, and a stack that is presumably big enough. We do basic Mach + initialization so mig-generated stubs work, and then do an exec_startup + RPC on our bootstrap port, to which the exec server responds with the + information passed in the exec call, as well as our original bootstrap + port, and the base address and size of the preallocated stack. + + If using cthreads, we are given a new stack by cthreads initialization and + deallocate the stack set up by the exec server. On the new stack we call + `start1' (above) to do the rest of the startup work. Since the stack may + disappear out from under us in a machine-dependent way, we use a pile of + static variables to communicate the information from exec_startup to start1. + This is unfortunate but preferable to machine-dependent frobnication to copy + the state from the old stack to the new one. */ + +void +_hurd_startup (void **argptr, + void (*main) (int, char **, char **, + mach_port_t *, mach_msg_type_number_t, + int *, mach_msg_type_number_t)) +{ + error_t err; + mach_port_t in_bootstrap; + struct info i; + + /* Basic Mach initialization, must be done before RPCs can be done. */ + __mach_init (); + + /* Run things that want to do initialization as soon as possible. We do + this before exec_startup so that no out of line data arrives and + clutters up the address space before brk initialization. */ + + RUN_HOOK (_hurd_preinit_hook, ()); + + if (err = __task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT, + &in_bootstrap)) + LOSE; + + if (in_bootstrap != MACH_PORT_NULL) + { + /* Call the exec server on our bootstrap port and + get all our standard information from it. */ + + i.argslen = i.envlen = 0; + _hurd_init_dtablesize = i.portarraysize = i.intarraysize = 0; + + err = __exec_startup (in_bootstrap, + &_hurd_stack_base, &_hurd_stack_size, + &i.flags, + &i.args, &i.argslen, &i.env, &i.envlen, + &_hurd_init_dtable, &_hurd_init_dtablesize, + &i.portarray, &i.portarraysize, + &i.intarray, &i.intarraysize); + __mach_port_deallocate (__mach_task_self (), in_bootstrap); + } + + if (err || in_bootstrap == MACH_PORT_NULL) + { + /* Either we have no bootstrap port, or the RPC to the exec server + failed. Try to snarf the args in the canonical Mach way. + Hopefully either they will be on the stack as expected, or the + stack will be zeros so we don't crash. Set all our other + variables to have empty information. */ + + /* SNARF_ARGS (ARGPTR, ARGC, ARGV, ENVP) snarfs the arguments and + environment from the stack, assuming they were put there by the + microkernel. */ + SNARF_ARGS (argptr, i.argc, i.argv, i.envp); + + i.flags = 0; + i.args = i.env = NULL; + i.argslen = i.envlen = 0; + _hurd_init_dtable = NULL; + _hurd_init_dtablesize = 0; + i.portarray = NULL; + i.portarraysize = 0; + i.intarray = NULL; + i.intarraysize = 0; + } + else + i.argv = i.envp = NULL; + + i.hurd_main = main; + + /* The user might have defined a value for this, to get more variables. + Otherwise it will be zero on startup. We must make sure it is set + properly before before cthreads initialization, so cthreads can know + how much space to leave for thread variables. */ + if (__hurd_threadvar_max < _HURD_THREADVAR_MAX) + __hurd_threadvar_max = _HURD_THREADVAR_MAX; + + /* Do cthreads initialization and switch to the cthread stack. */ + + if (_cthread_init_routine != NULL) + CALL_WITH_SP (start1, i, (*_cthread_init_routine) ()); + else + start1 (&i); + + /* Should never get here. */ + LOSE; +} + + +static void +start1 (struct info *info) +{ + register int envc = 0; + + { + /* Check if the stack we are now on is different from + the one described by _hurd_stack_{base,size}. */ + + char dummy; + const vm_address_t newsp = (vm_address_t) &dummy; + + if (_hurd_stack_size != 0 && (newsp < _hurd_stack_base || + newsp - _hurd_stack_base > _hurd_stack_size)) + /* The new stack pointer does not intersect with the + stack the exec server set up for us, so free that stack. */ + __vm_deallocate (__mach_task_self (), + _hurd_stack_base, _hurd_stack_size); + } + + if (__hurd_threadvar_stack_mask == 0) + { + /* We are not using cthreads, so we will have just a single allocated + area for the per-thread variables of the main user thread. */ + unsigned long int i; + __hurd_threadvar_stack_offset + = (unsigned long int) malloc (__hurd_threadvar_max * + sizeof (unsigned long int)); + if (__hurd_threadvar_stack_offset == 0) + __libc_fatal ("Can't allocate single-threaded per-thread variables."); + for (i = 0; i < __hurd_threadvar_max; ++i) + ((unsigned long int *) __hurd_threadvar_stack_offset)[i] = 0; + } + + + /* Turn the block of null-separated strings we were passed for the + arguments and environment into vectors of pointers to strings. */ + + if (! info->argv) + { + if (info->args) + /* Count up the arguments so we can allocate ARGV. */ + info->argc = _hurd_split_args (args, argslen, NULL); + if (! info->args || info->argc == 0) + { + /* No arguments passed; set argv to { NULL }. */ + info->argc = 0; + info->args = NULL; + info->argv = (char **) &info->args; + } + } + + if (! info->envp) + { + if (info->env) + /* Count up the environment variables so we can allocate ENVP. */ + envc = _hurd_split_args (info->env, info->envlen, NULL); + if (! info->env || envc == 0) + { + /* No environment passed; set __environ to { NULL }. */ + info->env = NULL; + info->envp = (char **) &env; + } + } + + if (! info->argv) + { + /* There were some arguments. + Allocate space for the vectors of pointers and fill them in. */ + info->argv = __alloca ((info->argc + 1) * sizeof (char *)); + _hurd_split_args (info->args, info->argslen, info->argv); + } + + if (! info->envp) + { + /* There was some environment. + Allocate space for the vectors of pointers and fill them in. */ + info->envp = __alloca ((envc + 1) * sizeof (char *)); + _hurd_split_args (info->env, info->envlen, info->envp); + } + + (*info->hurd_main) (info->argc, info->argv, info->envp, + info->portarray, info->portarraysize, + info->intarray, info->intarraysize); + + /* Should never get here. */ + LOSE; +} + +/* Split ARGSLEN bytes at ARGS into words, breaking at NUL characters. If + ARGV is not a null pointer, store a pointer to the start of each word in + ARGV[n], and null-terminate ARGV. Return the number of words split. */ + +int +_hurd_split_args (char *args, size_t argslen, char **argv) +{ + char *p = args; + size_t n = argslen; + int argc = 0; + + while (n > 0) + { + char *end = memchr (p, '\0', n); + + if (argv) + argv[argc] = p; + ++argc; + + if (end == NULL) + /* The last argument is unterminated. */ + break; + + n -= end + 1 - p; + p = end + 1; + } + + if (argv) + argv[argc] = NULL; + return argc; +} diff --git a/mach/Machrules b/mach/Machrules index 93916a0a27..f81017958d 100644 --- a/mach/Machrules +++ b/mach/Machrules @@ -195,4 +195,10 @@ ifdef interface-library $(interface-library)-routines = $(interface-routines) extra-libs += $(interface-library) +# Avoid -lmachuser requiring -lc, which may not be built yet. If the +# shared object is absent, ld may choose a static library someplace and +# produce a bogus libmachuser.so. +interface.so = $(interface-library:lib%=%.so) +LDFLAGS-$(interface.so) = -nostdlib + endif diff --git a/resolv/res_init.c b/resolv/res_init.c index 0092dbcfbc..98807ff771 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -177,8 +177,8 @@ res_init() _res.retrans = RES_TIMEOUT; if (!_res.retry) _res.retry = 4; - if (!_res.options) - _res.options = RES_DEFAULT; + if (!(_res.options & RES_INIT)) + _res.options |= RES_DEFAULT; #ifdef USELOOPBACK _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); 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; } |