mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
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:
parent
047f282dd7
commit
54da5be39c
46
ChangeLog
46
ChangeLog
@ -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
|
||||
|
@ -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) \
|
||||
|
10
hurd/hurd.h
10
hurd/hurd.h
@ -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. */
|
||||
|
@ -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. */
|
||||
|
175
hurd/hurdsig.c
175
hurd/hurdsig.c
@ -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
151
hurd/intr-msg.c
Normal 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;
|
||||
}
|
@ -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
25
hurd/intr-rpc.h
Normal 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
86
hurd/thread-cancel.c
Normal 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;
|
||||
}
|
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user