diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | Makeconfig | 11 | ||||
-rw-r--r-- | hurd/hurdsig.c | 6 | ||||
-rw-r--r-- | hurd/intr-msg.c | 16 | ||||
-rw-r--r-- | sysdeps/mach/hurd/fork.c | 72 | ||||
-rw-r--r-- | sysdeps/mach/hurd/i386/trampoline.c | 29 |
6 files changed, 119 insertions, 37 deletions
@@ -1,3 +1,25 @@ +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. + Wed Aug 16 17:04:26 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> * hurd/intr-msg.c: Fixed calculation of syscall %esp. @@ -267,11 +267,18 @@ endif # Command for linking programs with the C library. ifndef +link -+link = $(CC) -nostdlib $(LDFLAGS) -o $@ \ ++link = $(CC) -nostdlib -nostartfiles $(LDFLAGS) -o $@ \ $(addprefix $(csu-objpfx),start.o $(+preinit)) \ - $(^:lib=$(common-objpfx)libc.a) $(gnulib) $(common-objpfx)libc.a \ + $(^:$(common-objpfx)libc.a=$(link-libc)) \ $(addprefix $(csu-objpfx),$(+postinit)) endif +ifndef link-libc +ifeq (yes,$(build-shared)) +link-libc = -L$(common-objdir) -lc $(gnulib) +else +link-libc = $(common-objpfx)libc.a $(gnulib) $(common-objpfx)libc.a +endif +endif ifndef gnulib gnulib := -lgcc endif diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c index 10dbceb..ca4e229 100644 --- a/hurd/hurdsig.c +++ b/hurd/hurdsig.c @@ -250,7 +250,8 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state, return portloc; } - + +#include "intr-msg.h" /* SS->thread is suspended. @@ -274,7 +275,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread, mach_msg_type_name_t reply_port_type, int untraced) { - extern const void _hurd_intr_rpc_msg_do_trap, _hurd_intr_rpc_msg_in_trap; + extern const void _hurd_intr_rpc_msg_in_trap; mach_port_t rcv_port = MACH_PORT_NULL; mach_port_t intr_port; @@ -294,6 +295,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread, /* The thread is about to do the RPC, but hasn't yet entered mach_msg. Mutate the thread's state so it knows not to try the RPC. */ + INTR_MSG_BACK_OUT (&state->basic); MACHINE_THREAD_STATE_SET_PC (&state->basic, &_hurd_intr_rpc_msg_in_trap); state->basic.SYSRETURN = MACH_SEND_INTERRUPTED; diff --git a/hurd/intr-msg.c b/hurd/intr-msg.c index 6f670b5..024cbfb 100644 --- a/hurd/intr-msg.c +++ b/hurd/intr-msg.c @@ -21,6 +21,9 @@ Cambridge, MA 02139, USA. */ #include <mach/mig_errors.h> #include <hurd/signal.h> +#include "intr-msg.h" + + error_t _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, mach_msg_option_t option, @@ -56,17 +59,8 @@ _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, ss->cancel = 0; } else - /* err = intr_msg_trap (msg, option, send_size, - rcv_size, rcv_name, timeout, notify); - */ - asm (".globl _hurd_intr_rpc_msg_do_trap\n" - ".globl _hurd_intr_rpc_msg_in_trap\n" - " movl %%esp, %%ecx\n" - " leal %1, %%esp\n" - " movl $-25, %%eax\n" - "_hurd_intr_rpc_msg_do_trap: lcall $7, $0 # status in %0\n" - "_hurd_intr_rpc_msg_in_trap: movl %%ecx, %%esp" - : "=a" (err) : "m" ((&msg)[-1]) : "%ecx"); + err = INTR_MSG_TRAP (msg, option, send_size, + rcv_size, rcv_name, timeout, notify); switch (err) { 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 |