aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-08-17 22:55:22 +0000
committerRoland McGrath <roland@gnu.org>1995-08-17 22:55:22 +0000
commit3fe9de0da5e8ad28a8ba86cc26ae6057984bde10 (patch)
tree248915736b58d19467d401ad3295c7113aee56cf /sysdeps
parent191abc516c6f0ecd02f84ec98994b223252b48d7 (diff)
downloadglibc-3fe9de0da5e8ad28a8ba86cc26ae6057984bde10.zip
glibc-3fe9de0da5e8ad28a8ba86cc26ae6057984bde10.tar.gz
glibc-3fe9de0da5e8ad28a8ba86cc26ae6057984bde10.tar.bz2
Thu Aug 17 16:18:38 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* hurd/intr-msg.c: Use INTR_MSG_TRAP macro from machine-dependent "intr-msg.h" for special syscall code, instead of i386-specific asm. * hurd/hurdsig.c: Use INTR_MSG_BACK_OUT macro from machine-dependent "intr-msg.h" before mutating thread state to skip RPC. * sysdeps/mach/hurd/i386/trampoline.c: If PC is inside _hurd_intr_rpc_mach_msg special syscall code, use real SP saved in %ecx. * Makeconfig (link-libc): New variable; use shared library if available. (+link): Use it. * sysdeps/mach/hurd/fork.c (_hurd_fork_locks): Variable removed. Instead, declare with `symbol_set_declare'. (fork): Use symbol_set_* macros for _hurd_fork_locks. Use SS->thread instead of __mach_thread_self (). Suspend all other threads during task_create and port copying.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/mach/hurd/fork.c72
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c29
2 files changed, 79 insertions, 22 deletions
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index b8b1574..66b1ba8 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -29,11 +29,7 @@ Cambridge, MA 02139, USA. */
/* Things that want to be locked while forking. */
-struct
- {
- size_t n;
- struct mutex *locks[0];
- } _hurd_fork_locks;
+symbol_set_declare (_hurd_fork_locks)
/* Things that want to be called before we fork, to prepare the parent for
@@ -62,7 +58,6 @@ __fork (void)
pid_t pid;
size_t i;
error_t err;
- thread_t thread_self = __mach_thread_self ();
struct hurd_sigstate *volatile ss;
ss = _hurd_self_sigstate ();
@@ -87,14 +82,32 @@ __fork (void)
mach_msg_type_number_t nporttypes = 0;
thread_t *threads = NULL;
mach_msg_type_number_t nthreads = 0;
- int ports_locked = 0;
+ int ports_locked = 0, stopped = 0;
+
+ void resume_threads (void)
+ {
+ if (! stopped)
+ return;
+
+ assert (threads);
+
+ for (i = 0; i < nthreads; ++i)
+ if (threads[i] != ss->thread)
+ __thread_resume (threads[i]);
+ stopped = 0;
+ }
/* Run things that prepare for forking before we create the task. */
RUN_HOOK (_hurd_fork_prepare_hook, ());
/* 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]);
+ {
+ void *const *p;
+ for (p = symbol_set_first_element (_hurd_fork_locks);
+ ! symbol_set_end_p (_hurd_fork_locks, p);
+ ++p)
+ __mutex_lock (*p);
+ }
__mutex_lock (&_hurd_siglock);
newtask = MACH_PORT_NULL;
@@ -108,8 +121,16 @@ __fork (void)
__spin_lock (&_hurd_ports[i].lock);
ports_locked = 1;
- /* Create the child task. It will inherit a copy of our memory. */
- err = __task_create (__mach_task_self (), 1, &newtask);
+ /* Stop all other threads while copying the address space,
+ so nothing changes. */
+ err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread);
+ if (!err)
+ {
+ stopped = 1;
+
+ /* Create the child task. It will inherit a copy of our memory. */
+ 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. */
@@ -263,7 +284,7 @@ __fork (void)
if (err = __proc_task2proc (portnames[i], newtask, &insert))
LOSE;
}
- else if (portnames[i] == thread_self)
+ else if (portnames[i] == ss->thread)
{
/* For the name we use for our own thread port, we will
insert the thread port for the child main user thread
@@ -372,6 +393,10 @@ __fork (void)
__spin_unlock (&_hurd_ports[i].lock);
ports_locked = 0;
+ /* All state has now been copied from the parent. It is safe to
+ resume other parent threads. */
+ resume_threads ();
+
/* Create the child main user thread and signal thread. */
if ((err = __thread_create (newtask, &thread)) ||
(err = __thread_create (newtask, &sigthread)))
@@ -381,8 +406,8 @@ __fork (void)
dead name rights with the names we want to give the thread ports
in the child as placeholders. Now deallocate them so we can use
the names. */
- if ((err = __mach_port_deallocate (newtask, thread_self)) ||
- (err = __mach_port_insert_right (newtask, thread_self,
+ if ((err = __mach_port_deallocate (newtask, ss->thread)) ||
+ (err = __mach_port_insert_right (newtask, ss->thread,
thread, MACH_MSG_TYPE_COPY_SEND)))
LOSE;
/* We have one extra user reference created at the beginning of this
@@ -390,9 +415,9 @@ __fork (void)
accounted for in the child below). This extra right gets consumed
in the child by the store into _hurd_sigthread in the child fork. */
if (thread_refs > 1 &&
- (err = __mach_port_mod_refs (newtask, thread_self,
+ (err = __mach_port_mod_refs (newtask, ss->thread,
MACH_PORT_RIGHT_SEND,
- thread_refs - 1)))
+ thread_refs)))
LOSE;
if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none. */
&& ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) ||
@@ -474,6 +499,8 @@ __fork (void)
for (i = 0; i < _hurd_nports; ++i)
__spin_unlock (&_hurd_ports[i].lock);
+ resume_threads ();
+
if (newtask != MACH_PORT_NULL)
{
if (err)
@@ -486,8 +513,6 @@ __fork (void)
__mach_port_deallocate (__mach_task_self (), sigthread);
if (newproc != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), newproc);
- if (thread_self != MACH_PORT_NULL)
- __mach_port_deallocate (__mach_task_self (), thread_self);
if (portnames)
__vm_deallocate (__mach_task_self (),
@@ -525,7 +550,7 @@ __fork (void)
/* We are the only thread in this new task, so we will
take the task-global signals. */
- _hurd_sigthread = thread_self;
+ _hurd_sigthread = ss->thread;
/* Unchain the sigstate structures for threads that existed in the
parent task but don't exist in this task (the child process).
@@ -575,8 +600,13 @@ __fork (void)
/* Unlock things we locked before creating the child task.
They are locked in both the parent and child tasks. */
- for (i = 0; i < _hurd_fork_locks.n; ++i)
- __mutex_unlock (_hurd_fork_locks.locks[i]);
+ {
+ void *const *p;
+ for (p = symbol_set_first_element (_hurd_fork_locks);
+ ! symbol_set_end_p (_hurd_fork_locks, p);
+ ++p)
+ __mutex_unlock (*p);
+ }
_hurd_critical_section_unlock (ss);
diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
index 7adffc4..9e947a4 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -45,6 +45,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
struct machine_thread_all_state *state)
{
__label__ trampoline, rpc_wait_trampoline, firewall;
+ extern const void _hurd_intr_rpc_msg_in_trap;
+ extern const void _hurd_intr_rpc_msg_cx_sp;
+ extern const void _hurd_intr_rpc_msg_sp_restored;
void *volatile sigsp;
struct sigcontext *scp;
struct
@@ -80,6 +83,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
if (! machine_get_basic_state (ss->thread, state))
return NULL;
+ /* Save the original SP in the gratuitous `esp' slot.
+ We may need to reset the SP (the `uesp' slot) to avoid clobbering an
+ interrupted RPC frame. */
+ state->basic.esp = state->basic.uesp;
+
if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
!(ss->sigaltstack.ss_flags & (SA_DISABLE|SA_ONSTACK)))
{
@@ -88,6 +96,24 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
/* XXX need to set up base of new stack for
per-thread variables, cthreads. */
}
+ /* This code has intimate knowledge of the special mach_msg system call
+ done in intr-msg.c; that code does:
+ movl %esp, %ecx
+ leal ARGS, %esp
+ _hurd_intr_rpc_msg_cx_sp: movl $-25, %eax
+ _hurd_intr_rpc_msg_do_trap: lcall $7, $0
+ _hurd_intr_rpc_msg_in_trap: movl %ecx, %esp
+ _hurd_intr_rpc_msg_sp_restored:
+ We must check for the window during which %esp points at the
+ mach_msg arguments. The space below until %ecx is used by
+ the _hurd_intr_rpc_mach_msg frame, and must not be clobbered. */
+ else if (state->basic.eip >= (int) &_hurd_intr_rpc_msg_cx_sp &&
+ state->basic.eip < (int) &_hurd_intr_rpc_msg_sp_restored)
+ /* The SP now points at the mach_msg args, but there is more stack
+ space used below it. The real SP is saved in %ecx; we must push the
+ new frame below there, and restore that value as the SP on
+ sigreturn. */
+ sigsp = (char *) (state->basic.uesp = state->basic.ecx);
else
sigsp = (char *) state->basic.uesp;
@@ -166,7 +192,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
message reception, since the request message has already been
sent. */
- struct mach_msg_trap_args *args = (void *) state->basic.uesp;
+ struct mach_msg_trap_args *args = (void *) state->basic.esp;
if (_hurdsig_catch_fault (SIGSEGV))
{
@@ -192,6 +218,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
state->basic.eip = (int) &&rpc_wait_trampoline;
/* The reply-receiving trampoline code runs initially on the original
user stack. We pass it the signal stack pointer in %ebx. */
+ state->basic.uesp = state->basic.esp; /* Restore mach_msg syscall SP. */
state->basic.ebx = (int) sigsp;
/* After doing the message receive, the trampoline code will need to
update the %eax value to be restored by sigreturn. To simplify