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.
This commit is contained in:
Roland McGrath 1995-08-17 22:55:22 +00:00
parent 191abc516c
commit 3fe9de0da5
6 changed files with 119 additions and 37 deletions

View File

@ -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> Wed Aug 16 17:04:26 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* hurd/intr-msg.c: Fixed calculation of syscall %esp. * hurd/intr-msg.c: Fixed calculation of syscall %esp.

View File

@ -267,11 +267,18 @@ endif
# Command for linking programs with the C library. # Command for linking programs with the C library.
ifndef +link ifndef +link
+link = $(CC) -nostdlib $(LDFLAGS) -o $@ \ +link = $(CC) -nostdlib -nostartfiles $(LDFLAGS) -o $@ \
$(addprefix $(csu-objpfx),start.o $(+preinit)) \ $(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)) $(addprefix $(csu-objpfx),$(+postinit))
endif 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 ifndef gnulib
gnulib := -lgcc gnulib := -lgcc
endif endif

View File

@ -250,7 +250,8 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
return portloc; return portloc;
} }
#include "intr-msg.h"
/* SS->thread is suspended. /* 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, mach_msg_type_name_t reply_port_type,
int untraced) 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 rcv_port = MACH_PORT_NULL;
mach_port_t intr_port; 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 /* 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 mach_msg. Mutate the thread's state so it knows not to try
the RPC. */ the RPC. */
INTR_MSG_BACK_OUT (&state->basic);
MACHINE_THREAD_STATE_SET_PC (&state->basic, MACHINE_THREAD_STATE_SET_PC (&state->basic,
&_hurd_intr_rpc_msg_in_trap); &_hurd_intr_rpc_msg_in_trap);
state->basic.SYSRETURN = MACH_SEND_INTERRUPTED; state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;

View File

@ -21,6 +21,9 @@ Cambridge, MA 02139, USA. */
#include <mach/mig_errors.h> #include <mach/mig_errors.h>
#include <hurd/signal.h> #include <hurd/signal.h>
#include "intr-msg.h"
error_t error_t
_hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
mach_msg_option_t option, mach_msg_option_t option,
@ -56,17 +59,8 @@ _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
ss->cancel = 0; ss->cancel = 0;
} }
else else
/* err = intr_msg_trap (msg, option, send_size, err = INTR_MSG_TRAP (msg, option, send_size,
rcv_size, rcv_name, timeout, notify); 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");
switch (err) switch (err)
{ {

View File

@ -29,11 +29,7 @@ Cambridge, MA 02139, USA. */
/* Things that want to be locked while forking. */ /* Things that want to be locked while forking. */
struct symbol_set_declare (_hurd_fork_locks)
{
size_t n;
struct mutex *locks[0];
} _hurd_fork_locks;
/* Things that want to be called before we fork, to prepare the parent for /* Things that want to be called before we fork, to prepare the parent for
@ -62,7 +58,6 @@ __fork (void)
pid_t pid; pid_t pid;
size_t i; size_t i;
error_t err; error_t err;
thread_t thread_self = __mach_thread_self ();
struct hurd_sigstate *volatile ss; struct hurd_sigstate *volatile ss;
ss = _hurd_self_sigstate (); ss = _hurd_self_sigstate ();
@ -87,14 +82,32 @@ __fork (void)
mach_msg_type_number_t nporttypes = 0; mach_msg_type_number_t nporttypes = 0;
thread_t *threads = NULL; thread_t *threads = NULL;
mach_msg_type_number_t nthreads = 0; 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 things that prepare for forking before we create the task. */
RUN_HOOK (_hurd_fork_prepare_hook, ()); RUN_HOOK (_hurd_fork_prepare_hook, ());
/* Lock things that want to be locked before we fork. */ /* 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); __mutex_lock (&_hurd_siglock);
newtask = MACH_PORT_NULL; newtask = MACH_PORT_NULL;
@ -108,8 +121,16 @@ __fork (void)
__spin_lock (&_hurd_ports[i].lock); __spin_lock (&_hurd_ports[i].lock);
ports_locked = 1; ports_locked = 1;
/* Create the child task. It will inherit a copy of our memory. */ /* Stop all other threads while copying the address space,
err = __task_create (__mach_task_self (), 1, &newtask); 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 /* Unlock the global signal state lock, so we do not
block the signal thread any longer than necessary. */ block the signal thread any longer than necessary. */
@ -263,7 +284,7 @@ __fork (void)
if (err = __proc_task2proc (portnames[i], newtask, &insert)) if (err = __proc_task2proc (portnames[i], newtask, &insert))
LOSE; 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 /* For the name we use for our own thread port, we will
insert the thread port for the child main user thread insert the thread port for the child main user thread
@ -372,6 +393,10 @@ __fork (void)
__spin_unlock (&_hurd_ports[i].lock); __spin_unlock (&_hurd_ports[i].lock);
ports_locked = 0; 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. */ /* Create the child main user thread and signal thread. */
if ((err = __thread_create (newtask, &thread)) || if ((err = __thread_create (newtask, &thread)) ||
(err = __thread_create (newtask, &sigthread))) (err = __thread_create (newtask, &sigthread)))
@ -381,8 +406,8 @@ __fork (void)
dead name rights with the names we want to give the thread ports 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 in the child as placeholders. Now deallocate them so we can use
the names. */ the names. */
if ((err = __mach_port_deallocate (newtask, thread_self)) || if ((err = __mach_port_deallocate (newtask, ss->thread)) ||
(err = __mach_port_insert_right (newtask, thread_self, (err = __mach_port_insert_right (newtask, ss->thread,
thread, MACH_MSG_TYPE_COPY_SEND))) thread, MACH_MSG_TYPE_COPY_SEND)))
LOSE; LOSE;
/* We have one extra user reference created at the beginning of this /* 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 accounted for in the child below). This extra right gets consumed
in the child by the store into _hurd_sigthread in the child fork. */ in the child by the store into _hurd_sigthread in the child fork. */
if (thread_refs > 1 && if (thread_refs > 1 &&
(err = __mach_port_mod_refs (newtask, thread_self, (err = __mach_port_mod_refs (newtask, ss->thread,
MACH_PORT_RIGHT_SEND, MACH_PORT_RIGHT_SEND,
thread_refs - 1))) thread_refs)))
LOSE; LOSE;
if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none. */ if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none. */
&& ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) || && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) ||
@ -474,6 +499,8 @@ __fork (void)
for (i = 0; i < _hurd_nports; ++i) for (i = 0; i < _hurd_nports; ++i)
__spin_unlock (&_hurd_ports[i].lock); __spin_unlock (&_hurd_ports[i].lock);
resume_threads ();
if (newtask != MACH_PORT_NULL) if (newtask != MACH_PORT_NULL)
{ {
if (err) if (err)
@ -486,8 +513,6 @@ __fork (void)
__mach_port_deallocate (__mach_task_self (), sigthread); __mach_port_deallocate (__mach_task_self (), sigthread);
if (newproc != MACH_PORT_NULL) if (newproc != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), newproc); __mach_port_deallocate (__mach_task_self (), newproc);
if (thread_self != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), thread_self);
if (portnames) if (portnames)
__vm_deallocate (__mach_task_self (), __vm_deallocate (__mach_task_self (),
@ -525,7 +550,7 @@ __fork (void)
/* We are the only thread in this new task, so we will /* We are the only thread in this new task, so we will
take the task-global signals. */ take the task-global signals. */
_hurd_sigthread = thread_self; _hurd_sigthread = ss->thread;
/* Unchain the sigstate structures for threads that existed in the /* Unchain the sigstate structures for threads that existed in the
parent task but don't exist in this task (the child process). 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. /* Unlock things we locked before creating the child task.
They are locked in both the parent and child tasks. */ 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); _hurd_critical_section_unlock (ss);

View File

@ -45,6 +45,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
struct machine_thread_all_state *state) struct machine_thread_all_state *state)
{ {
__label__ trampoline, rpc_wait_trampoline, firewall; __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; void *volatile sigsp;
struct sigcontext *scp; struct sigcontext *scp;
struct struct
@ -80,6 +83,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
if (! machine_get_basic_state (ss->thread, state)) if (! machine_get_basic_state (ss->thread, state))
return NULL; 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) && if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
!(ss->sigaltstack.ss_flags & (SA_DISABLE|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 /* XXX need to set up base of new stack for
per-thread variables, cthreads. */ 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 else
sigsp = (char *) state->basic.uesp; 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 message reception, since the request message has already been
sent. */ 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)) 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; state->basic.eip = (int) &&rpc_wait_trampoline;
/* The reply-receiving trampoline code runs initially on the original /* The reply-receiving trampoline code runs initially on the original
user stack. We pass it the signal stack pointer in %ebx. */ 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; state->basic.ebx = (int) sigsp;
/* After doing the message receive, the trampoline code will need to /* After doing the message receive, the trampoline code will need to
update the %eax value to be restored by sigreturn. To simplify update the %eax value to be restored by sigreturn. To simplify