mirror of
https://sourceware.org/git/glibc.git
synced 2025-12-24 17:51:17 +03:00
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user