summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-04-24 09:00:07 +0000
committerRoland McGrath <roland@gnu.org>1995-04-24 09:00:07 +0000
commit11872325e2cf0443e17d50eebbf883eb0c24ea27 (patch)
tree7b43aa9bc213e898d1f3add3cb6b6fec42503086
parentb96bdcd7d92fb44e9e2ad2458fdff03bda715151 (diff)
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--ChangeLog30
-rw-r--r--Makerules6
-rw-r--r--extra-lib.mk2
-rw-r--r--hurd/Makefile3
-rw-r--r--hurd/hurd.h17
-rw-r--r--hurd/hurdstartup.c302
-rw-r--r--mach/Machrules6
-rw-r--r--resolv/res_init.c4
-rw-r--r--sysdeps/mach/hurd/Makefile4
-rw-r--r--sysdeps/mach/hurd/fork.c171
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;
}