Mon Aug 14 16:51:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>

* hurd/thread-cancel.c: New file.
	* sysdeps/mach/hurd/i386/trampoline.c (_hurd_setup_sighandler): In
 	rpc_wait case, frob mach_msg args to set timeout on receive.
	(_hurdsig_rcv_interrupted_p): Function removed.
	* sysdeps/mach/hurd/alpha/trampoline.c: Likewise.
	* sysdeps/mach/hurd/hppa/trampoline.c: Likewise.
	* sysdeps/mach/hurd/mips/trampoline.c: Likewise.
	* hurd/intr-msg.c: New file.
	* hurd/hurd/signal.h (struct hurd_sigstate): New member `cancel'.
	(_hurdsig_rcv_interrupted_p): Declaration removed.
	(HURD_EINTR_RPC): Macro removed.
	(_hurd_longjmp_thread_state, _hurd_interrupted_rpc_timeout): Declare
	these.
	* hurd/intr-rpc.h: New file.
	* hurd/intr-rpc.defs: Just import intr-rpc.h.
	* hurd/hurdsig.c (_hurd_interrupted_rpc_timeout): New variable.
	(interrupted_reply_port_location): Take new flag arg; only catch
	faults if it's set.
	(abort_rpcs): Rename to _hurdsig_abort_rpcs; take same new flag arg.
	No longer use _hurdsig_rcv_interrupted_p; instead compare PC to
 	&_hurd_intr_rpc_msg_in_trap.  If before it, mutate state to simulate
 	MACH_SEND_INTERRUPTED return; on it, interrupt the operation.  All
 	callers changed.
	* hurd/hurd.h (hurd_thread_cancel, hurd_check_cancel): Declare these.
	* hurd/Makefile (distribute): Remove intr-rpc.awk.
	(sig): Add thread-cancel.
	(transform-user-stub, transform-user-stub-output): Variables removed.
	* sysdeps/mach/hurd/dl-sysdep.c: Change all RPCs from
 	`__hurd_intr_rpc_*' to `__*'.
	(_hurd_intr_rpc_mach_msg): New function.
	(_hurd_thread_sigstate): Function removed.
	* sysdeps/mach/hurd/ioctl.c: Use _hurd_intr_rpc_mach_msg function,
 	instead of __mach_msg inside HURD_EINTR_RPC macro.

	* sysdeps/generic/morecore.c [__GNU_LIBRARY__]: Declare `__sbrk'
 	to take ptrdiff_t arg.

	* sysdeps/mach/hurd/fork.c: Remove _hurd_longjmp_thread_state decl.

	* sysdeps/mach/hurd/kill.c (kill_pid): Don't make `inline'.

	* libc-symbols.h [GCC >= 2.7] (strong_alias, weak_symbol,
 	weak_alias): Use `extern' storage class.
This commit is contained in:
Roland McGrath 1995-08-14 22:49:23 +00:00
parent 047f282dd7
commit 54da5be39c
19 changed files with 490 additions and 336 deletions

View File

@ -1,3 +1,49 @@
Mon Aug 14 16:51:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* hurd/thread-cancel.c: New file.
* sysdeps/mach/hurd/i386/trampoline.c (_hurd_setup_sighandler): In
rpc_wait case, frob mach_msg args to set timeout on receive.
(_hurdsig_rcv_interrupted_p): Function removed.
* sysdeps/mach/hurd/alpha/trampoline.c: Likewise.
* sysdeps/mach/hurd/hppa/trampoline.c: Likewise.
* sysdeps/mach/hurd/mips/trampoline.c: Likewise.
* hurd/intr-msg.c: New file.
* hurd/hurd/signal.h (struct hurd_sigstate): New member `cancel'.
(_hurdsig_rcv_interrupted_p): Declaration removed.
(HURD_EINTR_RPC): Macro removed.
(_hurd_longjmp_thread_state, _hurd_interrupted_rpc_timeout): Declare
these.
* hurd/intr-rpc.h: New file.
* hurd/intr-rpc.defs: Just import intr-rpc.h.
* hurd/hurdsig.c (_hurd_interrupted_rpc_timeout): New variable.
(interrupted_reply_port_location): Take new flag arg; only catch
faults if it's set.
(abort_rpcs): Rename to _hurdsig_abort_rpcs; take same new flag arg.
No longer use _hurdsig_rcv_interrupted_p; instead compare PC to
&_hurd_intr_rpc_msg_in_trap. If before it, mutate state to simulate
MACH_SEND_INTERRUPTED return; on it, interrupt the operation. All
callers changed.
* hurd/hurd.h (hurd_thread_cancel, hurd_check_cancel): Declare these.
* hurd/Makefile (distribute): Remove intr-rpc.awk.
(sig): Add thread-cancel.
(transform-user-stub, transform-user-stub-output): Variables removed.
* sysdeps/mach/hurd/dl-sysdep.c: Change all RPCs from
`__hurd_intr_rpc_*' to `__*'.
(_hurd_intr_rpc_mach_msg): New function.
(_hurd_thread_sigstate): Function removed.
* sysdeps/mach/hurd/ioctl.c: Use _hurd_intr_rpc_mach_msg function,
instead of __mach_msg inside HURD_EINTR_RPC macro.
* sysdeps/generic/morecore.c [__GNU_LIBRARY__]: Declare `__sbrk'
to take ptrdiff_t arg.
* sysdeps/mach/hurd/fork.c: Remove _hurd_longjmp_thread_state decl.
* sysdeps/mach/hurd/kill.c (kill_pid): Don't make `inline'.
* libc-symbols.h [GCC >= 2.7] (strong_alias, weak_symbol,
weak_alias): Use `extern' storage class.
Wed Aug 9 14:25:35 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
* sysdeps/mach/hurd/setuid.c (__setuid): Switch the port-type and

View File

@ -28,7 +28,7 @@ headers = hurd.h $(interface-headers) \
$(addprefix hurd/,fd.h id.h port.h signal.h userlink.h \
resource.h threadvar.h)
distribute := hurdstartup.h hurdfault.h intr-rpc.awk intr-rpc.defs STATUS
distribute := hurdstartup.h hurdfault.h intr-rpc.defs STATUS
# The RPC interfaces go in a separate library.
interface-library := libhurduser
@ -53,7 +53,7 @@ routines = hurdstartup hurdinit \
$(sig) $(dtable) hurdinline port-cleanup
sig = hurdsig hurdfault faultexc siginfo hurd-raise preempt-sig \
trampoline longjmp-ts catch-exc exc2signal hurdkill sigunwind \
thread-self
thread-self thread-cancel
dtable = dtable port2fd new-fd alloc-fd intern-fd \
getdport openport \
fd-close fd-read fd-write hurdioctl ctty-input ctty-output
@ -88,25 +88,13 @@ include ../mach/Machrules
include ../Rules
# intr-rpc.defs defines the INTR_INTERFACE macro to make the generated RPC
# stubs send-interruptible, and to prefix them with `hurd_intr_rpc_'.
# stubs import <hurd/signal.h> and #define __mach_msg to
# _hurd_intr_rpc_mach_msg.
user-MIGFLAGS += -imacros intr-rpc.defs
# Run each generated user stub through intr-rpc.awk, which will detect
# stubs __hurd_intr_rpc_% and generate the user-callable function for the
# stub: this is a wrapper which calls __hurd_intr_rpc_% inside
# HURD_EINTR_RPC.
define transform-user-stub
gawk -v call=$${call} -f $(word 2,$^) \
$(objpfx)tmp_$${call}.c > $(objpfx)tmpi_$${call}.c; \
rm -f $(objpfx)tmp_$${call}.c;
endef
transform-user-stub-output = tmpi
$(foreach if,$(user-interfaces),$($(if)-calls:%=$(objpfx)RPC_%.o))): \
hurd/signal.h
$(user-interfaces:%=$(objpfx)%.ustamp): intr-rpc.awk
$(objpfx)fault%.c $(objpfx)fault%.h: $(mach-srcdir)/mach/%.defs
$(MIG) $(MIGFLAGS) -prefix _hurdsig_fault_ \
-server $(@:.h=.c) -sheader $(@:.c=.h) \

View File

@ -286,6 +286,16 @@ extern task_t __pid2task (pid_t pid), pid2task (pid_t pid);
extern thread_t hurd_thread_self (void);
/* Cancel pending operations on THREAD. If it is doing an interruptible RPC,
that RPC will now return EINTR; otherwise, the "cancelled" flag will be
set, causing the next `hurd_check_cancel' call to return nonzero or the
next interruptible RPC to return EINTR (whichever is called first). */
extern error_t hurd_thread_cancel (thread_t thread);
/* Test and clear the calling thread's "cancelled" flag. */
extern int hurd_check_cancel (void);
/* Return the io server port for file descriptor FD.
This adds a Mach user reference to the returned port.
On error, sets `errno' and returns MACH_PORT_NULL. */

View File

@ -84,6 +84,8 @@ struct hurd_sigstate
<hurd/userlink.h> for details. This member is only used by the
thread itself, and always inside a critical section. */
struct hurd_userlink *active_resources;
volatile int cancel; /* Flag set by hurd_thread_cancel. */
};
/* Linked list of states of all threads whose state has been asked for. */
@ -253,20 +255,14 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
extern void _hurd_msgport_receive (void);
/* STATE describes a thread that had intr_port set (meaning it was inside
HURD_EINTR_RPC), after it has been thread_abort'd. It it looks to have
just completed a mach_msg_trap system call that returned
MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
being waited on. */
extern int _hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
mach_port_t *port);
/* Set up STATE with a thread state that, when resumed, is
like `longjmp (_hurd_sigthread_fault_env, 1)'. */
extern void _hurd_initialize_fault_recovery_state (void *state);
/* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'. */
extern void _hurd_longjmp_thread_state (void *state, jmp_buf env, int value);
/* Function run for SIGINFO when its action is SIG_DFL and the current
process is the session leader. */
@ -274,50 +270,10 @@ extern void _hurd_initialize_fault_recovery_state (void *state);
extern void _hurd_siginfo_handler (int);
/* Perform interruptible RPC CALL on PORT.
The call should use
The args in CALL should be constant or local variable refs.
They may be evaluated many times, and must not change.
PORT must not be deallocated before this RPC is finished. */
#define HURD_EINTR_RPC(port, call) \
({ \
__label__ __do_call; /* Give this label block scope. */ \
error_t __err; \
struct hurd_sigstate *__ss = _hurd_self_sigstate (); \
__do_call: \
/* Tell the signal thread that we are doing an interruptible RPC on \
this port. If we get a signal and should return EINTR, the signal \
thread will set this variable to MACH_PORT_NULL. The RPC might \
return EINTR when some other thread gets a signal, in which case we \
want to restart our call. */ \
__ss->intr_port = (port); \
/* A signal may arrive here, after intr_port is set, but before the \
mach_msg system call. The signal handler might do an interruptible \
RPC, and clobber intr_port; then it would not be set properly when \
we actually did send the RPC, and a later signal wouldn't interrupt \
that RPC. So, _hurd_setup_sighandler saves intr_port in the \
sigcontext, and sigreturn restores it. */ \
switch (__err = (call)) \
{ \
case EINTR: /* RPC went out and was interrupted. */ \
case MACH_SEND_INTERRUPTED: /* RPC didn't get out. */ \
if (__ss->intr_port != MACH_PORT_NULL) \
/* If this signal was for us and it should interrupt calls, the \
signal thread will have cleared SS->intr_port. Since it's not \
cleared, the signal was for another thread, or SA_RESTART is \
set. Restart the interrupted call. */ \
goto __do_call; \
/* FALLTHROUGH */ \
case MACH_RCV_PORT_DIED: \
/* Server didn't respond to interrupt_operation, \
so the signal thread destroyed the reply port. */ \
__err = EINTR; \
break; \
default: /* Quiet -Wswitch-enum. */ \
} \
__ss->intr_port = MACH_PORT_NULL; \
__err; \
}) \
/* Milliseconds to wait for an interruptible RPC to return after
`interrupt_operation'. */
extern mach_msg_timeout_t _hurd_interrupted_rpc_timeout;
/* Mask of signals that cannot be caught, blocked, or ignored. */

View File

@ -41,6 +41,9 @@ thread_t _hurd_sigthread;
/* Linked-list of per-thread signal state. */
struct hurd_sigstate *_hurd_sigstates;
/* Timeout for RPC's after interrupt_operation. */
mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
static void
default_sigaction (struct sigaction actions[NSIG])
@ -76,9 +79,6 @@ _hurd_thread_sigstate (thread_t thread)
__sigemptyset (&ss->pending);
memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
ss->suspended = 0;
#ifdef noteven
__condition_init (&ss->arrived);
#endif
ss->intr_port = MACH_PORT_NULL;
ss->context = NULL;
@ -225,16 +225,17 @@ abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
}
/* Find the location of the MiG reply port cell in use by the thread whose
state is described by THREAD_STATE. Make sure that this location can be
set without faulting, or else return NULL. */
state is described by THREAD_STATE. If SIGTHREAD is nonzero, make sure
that this location can be set without faulting, or else return NULL. */
static mach_port_t *
interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
int sigthread)
{
mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
(_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
if (_hurdsig_catch_fault (SIGSEGV))
if (sigthread && _hurdsig_catch_fault (SIGSEGV))
{
assert (_hurdsig_fault_sigcode == (long int) portloc);
/* Faulted trying to read the stack. */
@ -244,7 +245,8 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
/* Fault now if this pointer is bogus. */
*(volatile mach_port_t *) portloc = *portloc;
_hurdsig_end_catch_fault ();
if (sigthread)
_hurdsig_end_catch_fault ();
return portloc;
}
@ -266,12 +268,14 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
be applied back to the thread if it might ever run again, else zero. */
static mach_port_t
abort_rpcs (struct hurd_sigstate *ss, int signo,
struct machine_thread_all_state *state, int *state_change,
mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,
int untraced)
_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
struct machine_thread_all_state *state, int *state_change,
mach_port_t *reply_port,
mach_msg_type_name_t reply_port_type,
int untraced)
{
mach_port_t msging_port;
extern const void _hurd_intr_rpc_msg_do_trap, _hurd_intr_rpc_msg_in_trap;
mach_port_t rcv_port = MACH_PORT_NULL;
mach_port_t intr_port;
*state_change = 0;
@ -285,71 +289,69 @@ abort_rpcs (struct hurd_sigstate *ss, int signo,
receive completes immediately or aborts. */
abort_thread (ss, state, reply_port, reply_port_type, untraced);
if (_hurdsig_rcv_interrupted_p (state, &msging_port))
if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
{
error_t err;
/* The RPC request message was sent and the thread was waiting for
the reply message; now the message receive has been aborted, so
the mach_msg_call will return MACH_RCV_INTERRUPTED. We must tell
the server to interrupt the pending operation. The thread must
wait for the reply message before running the signal handler (to
guarantee that the operation has finished being interrupted), so
our nonzero return tells the trampoline code to finish the message
receive operation before running the handler. */
err = __interrupt_operation (intr_port);
if (err)
{
mach_port_t *reply;
/* The interrupt didn't work.
Destroy the receive right the thread is blocked on. */
__mach_port_destroy (__mach_task_self (), msging_port);
/* The system call return value register now contains
MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
call. Since we have just destroyed the receive right, the
retry will fail with MACH_RCV_INVALID_NAME. Instead, just
change the return value here to EINTR so mach_msg will not
retry and the EINTR error code will propagate up. */
state->basic.SYSRETURN = EINTR;
*state_change = 1;
/* If that was the thread's MiG reply port (which I think should
always be the case), clear the reply port cell so it won't be
reused. */
reply = interrupted_reply_port_location (state);
if (reply != NULL && *reply == msging_port)
*reply = MACH_PORT_NULL;
}
/* All threads whose RPCs were interrupted by the interrupt_operation
call above will retry their RPCs unless we clear SS->intr_port.
So we clear it for the thread taking a signal when SA_RESTART is
clear, so that its call returns EINTR. */
if (!(ss->actions[signo].sa_flags & SA_RESTART))
ss->intr_port = MACH_PORT_NULL;
return err ? MACH_PORT_NULL : msging_port;
/* 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. */
MACHINE_THREAD_STATE_SET_PC (&state->basic,
&_hurd_intr_rpc_msg_in_trap);
state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
*state_change = 1;
}
else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
/* The thread was blocked in the system call. After thread_abort,
the return value register indicates what state the RPC was in
when interrupted. */
state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
{
/* The RPC request message was sent and the thread was waiting for
the reply message; now the message receive has been aborted, so
the mach_msg call will return MACH_RCV_INTERRUPTED. We must tell
the server to interrupt the pending operation. The thread must
wait for the reply message before running the signal handler (to
guarantee that the operation has finished being interrupted), so
our nonzero return tells the trampoline code to finish the message
receive operation before running the handler. */
/* One of the following is true:
mach_port_t *reply = interrupted_reply_port_location (state,
sigthread);
error_t err = __interrupt_operation (intr_port);
1. The RPC has not yet been sent. The thread will start its operation
after the signal has been handled.
if (err)
{
if (reply)
{
/* The interrupt didn't work.
Destroy the receive right the thread is blocked on. */
__mach_port_destroy (__mach_task_self (), *reply);
*reply = MACH_PORT_NULL;
}
2. The RPC has finished, but not yet cleared SS->intr_port.
The thread will clear SS->intr_port after running the handler.
/* The system call return value register now contains
MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
call. Since we have just destroyed the receive right, the
retry will fail with MACH_RCV_INVALID_NAME. Instead, just
change the return value here to EINTR so mach_msg will not
retry and the EINTR error code will propagate up. */
state->basic.SYSRETURN = EINTR;
*state_change = 1;
}
else if (reply)
rcv_port = *reply;
3. The RPC request message was being sent was aborted. The mach_msg
system call will return MACH_SEND_INTERRUPTED, and HURD_EINTR_RPC will
notice the interruption (either retrying the RPC or returning EINTR). */
/* All threads whose RPCs were interrupted by the interrupt_operation
call above will retry their RPCs unless we clear SS->intr_port.
So we clear it for the thread taking a signal when SA_RESTART is
clear, so that its call returns EINTR. */
if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
ss->intr_port = MACH_PORT_NULL;
}
return MACH_PORT_NULL;
return rcv_port;
}
/* Abort the RPCs being run by all threads but this one;
all other threads should be suspended. If LIVE is nonzero, those
threads may run again, so they should be adjusted as necessary to be
@ -387,8 +389,9 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
/* Abort any operation in progress with interrupt_operation.
Record the reply port the thread is waiting on.
We will wait for all the replies below. */
reply_ports[nthreads++] = abort_rpcs (ss, signo, state, &state_changed,
NULL, 0, 0);
reply_ports[nthreads++] = _hurdsig_abort_rpcs (ss, signo, 1,
state, &state_changed,
NULL, 0, 0);
if (state_changed && live)
/* Aborting the RPC needed to change this thread's state,
and it might ever run again. So write back its state. */
@ -403,11 +406,18 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
{
error_t err;
mach_msg_header_t head;
err = __mach_msg (&head, MACH_RCV_MSG, 0, sizeof head,
err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
reply_ports[nthreads],
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (err != MACH_RCV_TOO_LARGE)
assert_perror (err);
_hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
switch (err)
{
case MACH_RCV_TIMED_OUT:
case MACH_RCV_TOO_LARGE:
break;
default:
assert_perror (err);
}
}
}
@ -745,7 +755,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
if (! machine_get_basic_state (ss->thread, &thread_state))
goto sigbomb;
loc = interrupted_reply_port_location (&thread_state);
loc = interrupted_reply_port_location (&thread_state, 1);
if (loc && *loc != MACH_PORT_NULL)
/* This is the reply port for the context which called
sigreturn. Since we are abandoning that context entirely
@ -759,11 +769,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
}
else
{
wait_for_reply = (abort_rpcs (ss, signo,
&thread_state, &state_changed,
&reply_port, reply_port_type,
untraced)
!= MACH_PORT_NULL);
wait_for_reply
= (_hurdsig_abort_rpcs (ss, signo, 1,
&thread_state, &state_changed,
&reply_port, reply_port_type, untraced)
!= MACH_PORT_NULL);
if (ss->critical_section)
{
@ -790,7 +800,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
{
/* Fetch the thread variable for the MiG reply port,
and set it to MACH_PORT_NULL. */
mach_port_t *loc = interrupted_reply_port_location (&thread_state);
mach_port_t *loc = interrupted_reply_port_location (&thread_state,
1);
if (loc)
{
scp->sc_reply_port = *loc;

151
hurd/intr-msg.c Normal file
View File

@ -0,0 +1,151 @@
/* Replacement for mach_msg used in interruptible Hurd RPCs.
Copyright (C) 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 <mach.h>
#include <mach/mig_errors.h>
#include <hurd/signal.h>
error_t
_hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
mach_msg_option_t option,
mach_msg_size_t send_size,
mach_msg_size_t rcv_size,
mach_port_t rcv_name,
mach_msg_timeout_t timeout,
mach_port_t notify)
{
struct hurd_sigstate *ss = _hurd_self_sigstate ();
error_t err;
/* Tell the signal thread that we are doing an interruptible RPC on
this port. If we get a signal and should return EINTR, the signal
thread will set this variable to MACH_PORT_NULL. The RPC might
return EINTR when some other thread gets a signal, in which case we
want to restart our call. */
ss->intr_port = msg->msgh_remote_port;
/* A signal may arrive here, after intr_port is set, but before
the mach_msg system call. The signal handler might do an
interruptible RPC, and clobber intr_port; then it would not be
set properly when we actually did send the RPC, and a later
signal wouldn't interrupt that RPC. So,
_hurd_setup_sighandler saves intr_port in the sigcontext, and
sigreturn restores it. */
message:
if (ss->cancel)
{
err = EINTR;
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");
switch (err)
{
case MACH_SEND_INTERRUPTED: /* RPC didn't get out. */
if (ss->intr_port != MACH_PORT_NULL)
/* If this signal was for us and it should interrupt calls, the
signal thread will have cleared SS->intr_port.
Since it's not cleared, the signal was for another thread,
or SA_RESTART is set. Restart the interrupted call. */
goto message;
/* FALLTHROUGH */
case MACH_RCV_PORT_DIED:
/* Server didn't respond to interrupt_operation,
so the signal thread destroyed the reply port. */
/* FALLTHROUGH */
case MACH_RCV_TIMED_OUT:
/* The operation was supposedly interrupted, but still has
not returned. Declare it interrupted. */
err = EINTR;
/* The EINTR return indicates cancellation, so clear the flag. */
ss->cancel = 0;
break;
case MACH_RCV_INTERRUPTED: /* RPC sent; no reply. */
option &= ~MACH_SEND_MSG; /* Don't send again. */
if (ss->intr_port == MACH_PORT_NULL)
{
/* This signal or cancellation was for us. We need to wait for
the reply, but not hang forever. */
option |= MACH_RCV_TIMEOUT;
timeout = _hurd_interrupted_rpc_timeout;
}
goto message; /* Retry the receive. */
case MACH_MSG_SUCCESS:
if (option & MACH_RCV_MSG)
{
/* We got a reply. Was it EINTR? */
mig_reply_header_t *const reply = (void *) msg;
const union
{
mach_msg_type_t t;
int i;
} check =
{ t: {
MACH_MSG_TYPE_INTEGER_32,
32,
1,
TRUE,
FALSE,
FALSE,
0
} };
if (msg->msgh_size == sizeof *reply &&
!(msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
*(int *) &reply->RetCodeType == check.i &&
reply->RetCode == EINTR)
{
/* It is indeed EINTR. Is the interrupt for us? */
if (ss->intr_port != MACH_PORT_NULL)
/* Nope; repeat the RPC.
XXX Resources moved? */
goto message;
else
/* The EINTR return indicates cancellation, so clear the
flag. */
ss->cancel = 0;
}
}
break;
default: /* Quiet -Wswitch-enum. */
}
ss->intr_port = MACH_PORT_NULL;
return err;
}

View File

@ -1,5 +1,5 @@
/* Special MiG definitions for interruptible RPC stubs.
Copyright (C) 1994 Free Software Foundation, Inc.
Copyright (C) 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
@ -17,11 +17,7 @@ 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. */
/* Set the MiG options for an interruptible RPC interface.
We rename each MiG-generated function to hurd_intr_rpc_CALL and
give it the option to return on an interrupted message send. */
#define INTR_INTERFACE \
msgoption MACH_SEND_INTERRUPT;\
userprefix hurd_intr_rpc_;
/* Cause user stubs for interruptible RPCs to import a special header to
modify their behavior. */
#define INTR_INTERFACE uimport "intr-rpc.h";

25
hurd/intr-rpc.h Normal file
View File

@ -0,0 +1,25 @@
/* Special MiG definitions for interruptible RPC stubs.
Copyright (C) 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. */
/* This file is imported by the MiG-generated user stubs for interruptible
RPCs. We modify them to use our own function in place of mach_msg. */
#include <hurd/signal.h>
#define __mach_msg _hurd_intr_rpc_mach_msg

86
hurd/thread-cancel.c Normal file
View File

@ -0,0 +1,86 @@
/* Thread cancellation support.
Copyright (C) 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 <hurd/signal.h>
#include <hurd/interrupt.h>
#include <assert.h>
#include <thread_state.h>
/* See hurdsig.c. */
extern mach_port_t _hurdsig_abort_rpcs (struct hurd_sigstate *ss,
int signo, int sigthread,
struct machine_thread_all_state *,
int *state_change,
mach_port_t *reply_port,
mach_msg_type_name_t reply_port_type,
int untraced);
error_t
hurd_thread_cancel (thread_t thread)
{
struct hurd_sigstate *ss = _hurd_thread_sigstate (thread);
struct machine_thread_all_state state;
int state_change;
error_t err;
if (! ss)
return EINVAL;
__spin_lock (&ss->lock);
assert (! ss->critical_section);
ss->critical_section = 1;
err = __thread_suspend (thread);
__spin_unlock (&ss->lock);
if (! err)
{
/* Set the flag telling the thread its operation is being cancelled. */
ss->cancel = 1;
/* Interrupt any interruptible RPC now in progress. */
state.set = 0;
_hurdsig_abort_rpcs (ss, 0, 0, &state, &state_change, NULL, 0, 0);
if (state_change)
err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
(natural_t *) &state.basic,
MACHINE_THREAD_STATE_COUNT);
__thread_resume (thread);
}
_hurd_critical_section_unlock (ss);
return err;
}
int
hurd_check_cancel (void)
{
struct hurd_sigstate *ss = _hurd_self_sigstate ();
int cancel;
__spin_lock (&ss->lock);
assert (! ss->critical_section);
cancel = ss->cancel;
ss->cancel = 0;
__spin_unlock (&ss->lock);
return cancel;
}

View File

@ -141,15 +141,15 @@ Cambridge, MA 02139, USA. */
are better clued in to what we are doing. */
#undef strong_alias
#define strong_alias(name, aliasname) \
__typeof (name) aliasname __attribute__ ((alias (#name)));
extern __typeof (name) aliasname __attribute__ ((alias (#name)));
#ifdef HAVE_WEAK_SYMBOLS
#undef weak_symbol
#define weak_symbol(name) \
__typeof (name) name __attribute__ ((weak));
extern __typeof (name) name __attribute__ ((weak));
#undef weak_alias
#define weak_alias(name, aliasname) \
__typeof (name) aliasname __attribute__ ((weak, alias (#name)));
extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
#endif /* HAVE_WEAK_SYMBOLS. */
#endif /* Not ASSEMBLER, and GCC 2.7 or later. */

View File

@ -27,7 +27,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef __GNU_LIBRARY__
/* It is best not to declare this and cast its result on foreign operating
systems with potentially hostile include files. */
extern __ptr_t __sbrk __P ((int increment));
#include <stddef.h>
extern __ptr_t __sbrk __P ((ptrdiff_t increment));
#endif
#ifndef NULL

View File

@ -1,5 +1,5 @@
/* Set thread_state for sighandler, and sigcontext to recover. Alpha version.
Copyright (C) 1994 Free Software Foundation, Inc.
Copyright (C) 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
@ -160,6 +160,12 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
calls we retry need only wait to receive the reply message. */
args->option &= ~MACH_SEND_MSG;
/* Limit the time to receive the reply message, in case the server
claimed that `interrupt_operation' succeeded but in fact the RPC
is hung. */
args->option |= MACH_RCV_TIMEOUT;
args->timeout = _hurd_interrupted_rpc_timeout;
state->basic.pc = (long int) &&rpc_wait_trampoline;
/* After doing the message receive, the trampoline code will need to
update the v0 ($0) value to be restored by sigreturn. To simplify
@ -245,42 +251,3 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
/* NOTREACHED */
return NULL;
}
/* STATE describes a thread that had intr_port set (meaning it was inside
HURD_EINTR_RPC), after it has been thread_abort'd. If it looks to have
just completed a mach_msg_trap system call that returned
MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
being waited on. */
int
_hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
mach_port_t *port)
{
if (state->basic.r0 == MACH_RCV_INTERRUPTED)
{
const unsigned int *pc = (void *) state->basic.pc;
struct mach_msg_trap_args *args = (void *) &state->basic.r16;
if (_hurdsig_catch_fault (SIGSEGV))
{
assert (_hurdsig_fault_sigcode == (long int) (pc - 1) ||
_hurdsig_fault_sigcode == (long int) &args->rcv_name);
/* We got a fault trying to read the PC or stack. */
return 0;
}
else
{
if (pc[-1] == ((alpha_instruction) { pal_format:
{ opcode: op_pal,
function: op_chmk } }).bits)
{
/* We did just return from a mach_msg_trap system call
doing a message receive that was interrupted.
Examine the parameters to find the receive right. */
*port = args->rcv_name;
return 1;
}
}
}
return 0;
}

View File

@ -125,6 +125,7 @@ fmh(); /* XXX */
_hurd_startup (start_argptr, &go);
LOSE;
abort ();
}
int
@ -137,7 +138,6 @@ _dl_sysdep_open_zero_fill (void)
void
_dl_sysdep_fatal (const char *msg, ...)
{
extern __typeof (__io_write) __hurd_intr_rpc_io_write;
va_list ap;
va_start (ap, msg);
@ -147,8 +147,7 @@ _dl_sysdep_fatal (const char *msg, ...)
mach_msg_type_number_t nwrote;
do
{
if (__hurd_intr_rpc_io_write (_hurd_init_dtable[2],
msg, len, -1, &nwrote))
if (__io_write (_hurd_init_dtable[2], msg, len, -1, &nwrote))
break;
len -= nwrote;
msg += nwrote;
@ -169,8 +168,6 @@ _dl_sysdep_fatal (const char *msg, ...)
int
open (const char *file_name, int mode, ...)
{
extern __typeof (__dir_lookup) __hurd_intr_rpc_dir_lookup;
extern __typeof (__io_reauthenticate) __hurd_intr_rpc_io_reauthenticate;
enum retry_type doretry;
char retryname[1024]; /* XXX string_t LOSES! */
file_t startdir, newpt, fileport;
@ -187,7 +184,7 @@ open (const char *file_name, int mode, ...)
while (file_name[0] == '/')
file_name++;
if (errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
if (errno = __dir_lookup (startdir, file_name, mode, 0,
&doretry, retryname, &fileport))
return -1;
@ -207,7 +204,7 @@ open (const char *file_name, int mode, ...)
case FS_RETRY_REAUTH:
{
mach_port_t ref = __mach_reply_port ();
errno = __hurd_intr_rpc_io_reauthenticate
errno = __io_reauthenticate
(fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! errno)
errno = __auth_user_authenticate
@ -236,14 +233,12 @@ open (const char *file_name, int mode, ...)
if (retryname[0] == '\0')
{
mach_port_t memobj_rd, memobj_wr;
extern __typeof (__io_map) __hurd_intr_rpc_io_map;
dealloc_dir = 1;
opened:
/* We have the file open. Now map it. */
errno = __hurd_intr_rpc_io_map (fileport,
&memobj_rd, &memobj_wr);
errno = __io_map (fileport, &memobj_rd, &memobj_wr);
if (dealloc_dir)
__mach_port_deallocate (__mach_task_self (), fileport);
if (errno)
@ -359,7 +354,7 @@ open (const char *file_name, int mode, ...)
if (! err)
{
mach_port_t ref = __mach_reply_port ();
err = __hurd_intr_rpc_io_reauthenticate
err = __io_reauthenticate
(unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! err)
err = __auth_user_authenticate
@ -404,8 +399,8 @@ open (const char *file_name, int mode, ...)
return -1;
}
errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
&doretry, retryname, &fileport);
errno = __dir_lookup (startdir, file_name, mode, 0,
&doretry, retryname, &fileport);
}
}
@ -445,9 +440,8 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
void
_exit (int status)
{
extern __typeof (__proc_mark_exit) __hurd_intr_rpc_proc_mark_exit;
__hurd_intr_rpc_proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
W_EXITCODE (status, 0));
__proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
W_EXITCODE (status, 0));
while (__task_terminate (__mach_task_self ()))
__mach_task_self_ = (__mach_task_self) ();
}
@ -513,11 +507,21 @@ longjmp (jmp_buf env, int val) { __longjmp (env[0].__jmpbuf, val); }
weak_symbol (longjmp)
/* Stub out this function that is called by interruptible RPC stubs. It
should never get called during initial dynamic linking, because we use
only the raw MiG stub functions __hurd_intr_rpc_*. Since this defn is
/* This function is called by interruptible RPC stubs. For initial
dynamic linking, just use the normal mach_msg. Since this defn is
weak, the real defn in libc.so will override it if we are linked into
the user program (-ldl). */
struct hurd_sigstate *
_hurd_thread_sigstate (thread_t thread) { thread = thread; abort (); }
weak_symbol (_hurd_thread_sigstate)
error_t
_hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
mach_msg_option_t option,
mach_msg_size_t send_size,
mach_msg_size_t rcv_size,
mach_port_t rcv_name,
mach_msg_timeout_t timeout,
mach_port_t notify)
{
return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
timeout, notify);
}
weak_symbol (_hurd_intr_rpc_mach_msg)

View File

@ -27,9 +27,6 @@ Cambridge, MA 02139, USA. */
#include <assert.h>
#include "hurdmalloc.h" /* XXX */
extern void _hurd_longjmp_thread_state (struct machine_thread_state *,
jmp_buf env, int value);
/* Things that want to be locked while forking. */
struct

View File

@ -144,6 +144,12 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
calls we retry need only wait to receive the reply message. */
args->option &= ~MACH_SEND_MSG;
/* Limit the time to receive the reply message, in case the server
claimed that `interrupt_operation' succeeded but in fact the RPC
is hung. */
args->option |= MACH_RCV_TIMEOUT;
args->timeout = _hurd_interrupted_rpc_timeout;
_hurdsig_end_catch_fault ();
MACHINE_THREAD_STATE_SET_PC (&state->basic, &&rpc_wait_trampoline);
@ -222,37 +228,3 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
/* NOTREACHED */
return NULL;
}
/* STATE describes a thread that had intr_port set (meaning it was inside
HURD_EINTR_RPC), after it has been thread_abort'd. It it looks to have
just completed a mach_msg_trap system call that returned
MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
being waited on. */
int
_hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
mach_port_t *port)
{
const unsigned int *volatile pc
= MACHINE_THREAD_STATE_PC (&state->basic);
const mach_port_t *rcv_name
= (void *) state->r30 -32-20; /* VA_ARG4 from <mach/machine/asm.h>. */
if (_hurdsig_catch_fault (SIGSEGV))
assert (_hurdsig_fault_sigcode == (long int) pc ||
_hurdsig_fault_sigcode == (long int) rcv_name);
else
{
int rcving = (state->basic.r28 == MACH_RCV_INTERRUPTED &&
pc == ???unfinished???);
if (rcving)
/* We did just return from a mach_msg_trap system call
doing a message receive that was interrupted.
Examine the parameters to find the receive right. */
*port = *rcv_name;
_hurdsig_end_catch_fault ();
if (rcving)
return 1;
}
return 0;
}

View File

@ -181,6 +181,12 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
calls we retry need only wait to receive the reply message. */
args->option &= ~MACH_SEND_MSG;
/* Limit the time to receive the reply message, in case the server
claimed that `interrupt_operation' succeeded but in fact the RPC
is hung. */
args->option |= MACH_RCV_TIMEOUT;
args->timeout = _hurd_interrupted_rpc_timeout;
_hurdsig_end_catch_fault ();
state->basic.eip = (int) &&rpc_wait_trampoline;
@ -250,39 +256,3 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
/* NOTREACHED */
return NULL;
}
/* STATE describes a thread that had intr_port set (meaning it was inside
HURD_EINTR_RPC), after it has been thread_abort'd. It it looks to have
just completed a mach_msg_trap system call that returned
MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
being waited on. */
int
_hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
mach_port_t *port)
{
static const unsigned char syscall[] = { 0x9a, 0, 0, 0, 0, 7, 0 };
const unsigned char *volatile pc
= (void *) state->basic.eip - sizeof syscall;
if (_hurdsig_catch_fault (SIGSEGV))
assert (_hurdsig_fault_sigcode >= (long int) pc &&
_hurdsig_fault_sigcode < (long int) (pc + sizeof syscall));
else
{
int rcving = (state->basic.eax == MACH_RCV_INTERRUPTED &&
!memcmp (pc, &syscall, sizeof syscall));
_hurdsig_end_catch_fault ();
if (rcving)
{
/* We did just return from a mach_msg_trap system call
doing a message receive that was interrupted.
Examine the parameters to find the receive right. */
struct mach_msg_trap_args *args = (void *) state->basic.uesp;
*port = args->rcv_name;
return 1;
}
}
return 0;
}

View File

@ -79,11 +79,11 @@ DEFUN(__ioctl, (fd, request),
m->msgh_id = msgid;
m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_MAKE_SEND_ONCE);
err = HURD_EINTR_RPC (ioport, __mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
m->msgh_size, sizeof (msg),
m->msgh_local_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL));
err = _hurd_intr_rpc_mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
m->msgh_size, sizeof (msg),
m->msgh_local_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
switch (err)
{
case MACH_MSG_SUCCESS:

View File

@ -37,8 +37,6 @@ __kill (pid_t pid, int sig)
inline void kill_pid (pid_t pid) /* Kill one PID. */
{
/* SIGKILL is not delivered as a normal signal.
Sending SIGKILL to a process means to terminate its task. */
if (sig == SIGKILL)

View File

@ -150,6 +150,12 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
calls we retry need only wait to receive the reply message. */
args->option &= ~MACH_SEND_MSG;
/* Limit the time to receive the reply message, in case the server
claimed that `interrupt_operation' succeeded but in fact the RPC
is hung. */
args->option |= MACH_RCV_TIMEOUT;
args->timeout = _hurd_interrupted_rpc_timeout;
state->basic.pc = (int) &&rpc_wait_trampoline;
state->basic.r29 = (int) sigsp; /* $29 is the stack pointer register. */
/* After doing the message receive, the trampoline code will need to
@ -227,34 +233,3 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
return NULL;
}
/* STATE describes a thread that had intr_port set (meaning it was inside
HURD_EINTR_RPC), after it has been thread_abort'd. It it looks to have
just completed a mach_msg_trap system call that returned
MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
being waited on. */
int
_hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
mach_port_t *port)
{
const unsigned int *const pc = (void *) state->basic.pc;
if (_hurdsig_catch_fault (SIGSEGV))
assert (_hurdsig_fault_sigcode == (long int) pc);
else
{
if (state->basic.r2 == MACH_RCV_INTERRUPTED &&
pc[-1] == 0xc) /* syscall */
{
/* We did just return from a mach_msg_trap system call
doing a message receive that was interrupted.
Examine the parameters to find the receive right. */
struct mach_msg_trap_args *args = (void *) &state->basic.r4;
*port = args->rcv_name;
return 1;
}
}
return 0;
}