mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 07:10:06 +00:00
21297437bb
or <machine/ndr_def.h> and add -DNDR_DEF_HEADER=... to DEFINES. * sysdeps/mach/configure: Regenerated. * mach/mach_init.c [NDR_DEF_HEADER]: #include it. * hurd/hurdfault.c (_hurdsig_fault_init): Add a cast. * hurd/hurd/signal.h: Include <setjmp.h> for `jmp_buf' decl. * mach/msgserver.c (__mach_msg_server_timeout) [! MACH_RCV_LARGE]: Double MAX_SIZE and don't retry on MACH_RCV_TOO_LARGE. * sysdeps/mach/hurd/times.c [NO_CREATION_TIME] (startup_time): New static variable. [NO_CREATION_TIME] (times_init): New static function in __libc_subinit. (__times) [NO_CREATION_TIME]: Use startup_time in lieu of task creation_time from task_basic_info. (__times): Use __gettimeofday instead of __host_get_time. * hurd/intr-msg.c (_hurd_intr_rpc_mach_msg) [! MACH_MSG_TYPE_BIT]: Use untyped Mach IPC message format. * hurd/catch-exc.c: Include <assert.h>, missing from last change.
364 lines
13 KiB
C
364 lines
13 KiB
C
/* Implementing POSIX.1 signals under the Hurd.
|
||
Copyright (C) 1993,94,95,96,98,99,2002 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 Lesser General Public
|
||
License as published by the Free Software Foundation; either
|
||
version 2.1 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
|
||
Lesser General Public License for more details.
|
||
|
||
You should have received a copy of the GNU Lesser General Public
|
||
License along with the GNU C Library; if not, write to the Free
|
||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||
02111-1307 USA. */
|
||
|
||
#ifndef _HURD_SIGNAL_H
|
||
|
||
#define _HURD_SIGNAL_H 1
|
||
#include <features.h>
|
||
/* Make sure <signal.h> is going to define NSIG. */
|
||
#ifndef __USE_GNU
|
||
#error "Must have `_GNU_SOURCE' feature test macro to use this file"
|
||
#endif
|
||
|
||
#define __need_NULL
|
||
#include <stddef.h>
|
||
|
||
#include <mach/mach_types.h>
|
||
#include <mach/port.h>
|
||
#include <mach/message.h>
|
||
#include <hurd/hurd_types.h>
|
||
#include <signal.h>
|
||
#include <errno.h>
|
||
#include <hurd/msg.h>
|
||
|
||
#include <cthreads.h> /* For `struct mutex'. */
|
||
#include <setjmp.h> /* For `jmp_buf'. */
|
||
#include <spin-lock.h>
|
||
#include <hurd/threadvar.h> /* We cache sigstate in a threadvar. */
|
||
struct hurd_signal_preemptor; /* <hurd/sigpreempt.h> */
|
||
|
||
|
||
/* Full details of a signal. */
|
||
struct hurd_signal_detail
|
||
{
|
||
/* Codes from origination Mach exception_raise message. */
|
||
integer_t exc, exc_code, exc_subcode;
|
||
/* Sigcode as passed or computed from exception codes. */
|
||
integer_t code;
|
||
/* Error code as passed or extracted from exception codes. */
|
||
error_t error;
|
||
};
|
||
|
||
|
||
/* Per-thread signal state. */
|
||
|
||
struct hurd_sigstate
|
||
{
|
||
spin_lock_t critical_section_lock; /* Held if in critical section. */
|
||
|
||
spin_lock_t lock; /* Locks most of the rest of the structure. */
|
||
|
||
thread_t thread;
|
||
struct hurd_sigstate *next; /* Linked-list of thread sigstates. */
|
||
|
||
sigset_t blocked; /* What signals are blocked. */
|
||
sigset_t pending; /* Pending signals, possibly blocked. */
|
||
struct sigaction actions[NSIG];
|
||
struct sigaltstack sigaltstack;
|
||
|
||
/* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>.
|
||
Each element of this chain is in local stack storage, and the chain
|
||
parallels the stack: the head of this chain is in the innermost
|
||
stack frame, and each next element in an outermore frame. */
|
||
struct hurd_signal_preemptor *preemptors;
|
||
|
||
/* For each signal that may be pending, the details to deliver it with. */
|
||
struct hurd_signal_detail pending_data[NSIG];
|
||
|
||
/* If `suspended' is set when this thread gets a signal,
|
||
the signal thread sends an empty message to it. */
|
||
mach_port_t suspended;
|
||
|
||
/* The following members are not locked. They are used only by this
|
||
thread, or by the signal thread with this thread suspended. */
|
||
|
||
volatile mach_port_t intr_port; /* Port interruptible RPC was sent on. */
|
||
|
||
/* If this is not null, the thread is in sigreturn awaiting delivery of
|
||
pending signals. This context (the machine-dependent portions only)
|
||
will be passed to sigreturn after running the handler for a pending
|
||
signal, instead of examining the thread state. */
|
||
struct sigcontext *context;
|
||
|
||
/* This is the head of the thread's list of active resources; see
|
||
<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;
|
||
|
||
/* These are locked normally. */
|
||
int cancel; /* Flag set by hurd_thread_cancel. */
|
||
void (*cancel_hook) (void); /* Called on cancellation. */
|
||
};
|
||
|
||
/* Linked list of states of all threads whose state has been asked for. */
|
||
|
||
extern struct hurd_sigstate *_hurd_sigstates;
|
||
|
||
extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates. */
|
||
|
||
/* Get the sigstate of a given thread, taking its lock. */
|
||
|
||
extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t);
|
||
|
||
/* Get the sigstate of the current thread.
|
||
This uses a per-thread variable to optimize the lookup. */
|
||
|
||
extern struct hurd_sigstate *_hurd_self_sigstate (void)
|
||
/* This declaration tells the compiler that the value is constant.
|
||
We assume this won't be called twice from the same stack frame
|
||
by different threads. */
|
||
__attribute__ ((__const__));
|
||
|
||
#ifndef _HURD_SIGNAL_H_EXTERN_INLINE
|
||
#define _HURD_SIGNAL_H_EXTERN_INLINE extern __inline
|
||
#endif
|
||
|
||
_HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
|
||
_hurd_self_sigstate (void)
|
||
{
|
||
struct hurd_sigstate **location =
|
||
(void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
|
||
if (*location == NULL)
|
||
*location = _hurd_thread_sigstate (__mach_thread_self ());
|
||
return *location;
|
||
}
|
||
|
||
/* Thread listening on our message port; also called the "signal thread". */
|
||
|
||
extern thread_t _hurd_msgport_thread;
|
||
|
||
/* Our message port. We hold the receive right and _hurd_msgport_thread
|
||
listens for messages on it. We also hold a send right, for convenience. */
|
||
|
||
extern mach_port_t _hurd_msgport;
|
||
|
||
|
||
/* Thread to receive process-global signals. */
|
||
|
||
extern thread_t _hurd_sigthread;
|
||
|
||
|
||
/* Resource limit on core file size. Enforced by hurdsig.c. */
|
||
extern int _hurd_core_limit;
|
||
|
||
/* Critical sections.
|
||
|
||
A critical section is a section of code which cannot safely be interrupted
|
||
to run a signal handler; for example, code that holds any lock cannot be
|
||
interrupted lest the signal handler try to take the same lock and
|
||
deadlock result. */
|
||
|
||
_HURD_SIGNAL_H_EXTERN_INLINE void *
|
||
_hurd_critical_section_lock (void)
|
||
{
|
||
struct hurd_sigstate **location =
|
||
(void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
|
||
struct hurd_sigstate *ss = *location;
|
||
if (ss == NULL)
|
||
{
|
||
/* The thread variable is unset; this must be the first time we've
|
||
asked for it. In this case, the critical section flag cannot
|
||
possible already be set. Look up our sigstate structure the slow
|
||
way; this locks the sigstate lock. */
|
||
ss = *location = _hurd_thread_sigstate (__mach_thread_self ());
|
||
__spin_unlock (&ss->lock);
|
||
}
|
||
|
||
if (! __spin_try_lock (&ss->critical_section_lock))
|
||
/* We are already in a critical section, so do nothing. */
|
||
return NULL;
|
||
|
||
/* With the critical section lock held no signal handler will run.
|
||
Return our sigstate pointer; this will be passed to
|
||
_hurd_critical_section_unlock to unlock it. */
|
||
return ss;
|
||
}
|
||
|
||
_HURD_SIGNAL_H_EXTERN_INLINE void
|
||
_hurd_critical_section_unlock (void *our_lock)
|
||
{
|
||
if (our_lock == NULL)
|
||
/* The critical section lock was held when we began. Do nothing. */
|
||
return;
|
||
else
|
||
{
|
||
/* It was us who acquired the critical section lock. Unlock it. */
|
||
struct hurd_sigstate *ss = our_lock;
|
||
sigset_t pending;
|
||
__spin_lock (&ss->lock);
|
||
__spin_unlock (&ss->critical_section_lock);
|
||
pending = ss->pending & ~ss->blocked;
|
||
__spin_unlock (&ss->lock);
|
||
if (! __sigisemptyset (&pending))
|
||
/* There are unblocked signals pending, which weren't
|
||
delivered because we were in the critical section.
|
||
Tell the signal thread to deliver them now. */
|
||
__msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
|
||
}
|
||
}
|
||
|
||
/* Convenient macros for simple uses of critical sections.
|
||
These two must be used as a pair at the same C scoping level. */
|
||
|
||
#define HURD_CRITICAL_BEGIN \
|
||
{ void *__hurd_critical__ = _hurd_critical_section_lock ()
|
||
#define HURD_CRITICAL_END \
|
||
_hurd_critical_section_unlock (__hurd_critical__); } while (0)
|
||
|
||
/* Initialize the signal code, and start the signal thread.
|
||
Arguments give the "init ints" from exec_startup. */
|
||
|
||
extern void _hurdsig_init (const int *intarray, size_t intarraysize);
|
||
|
||
/* Initialize proc server-assisted fault recovery for the signal thread. */
|
||
|
||
extern void _hurdsig_fault_init (void);
|
||
|
||
/* Raise a signal as described by SIGNO an DETAIL, on the thread whose
|
||
sigstate SS points to. If SS is a null pointer, this instead affects
|
||
the calling thread. */
|
||
|
||
extern void _hurd_raise_signal (struct hurd_sigstate *ss, int signo,
|
||
const struct hurd_signal_detail *detail);
|
||
|
||
/* Translate a Mach exception into a signal (machine-dependent). */
|
||
|
||
extern void _hurd_exception2signal (struct hurd_signal_detail *detail,
|
||
int *signo);
|
||
|
||
|
||
/* Make the thread described by SS take the signal described by SIGNO and
|
||
DETAIL. If the process is traced, this will in fact stop with a SIGNO
|
||
as the stop signal unless UNTRACED is nonzero. When the signal can be
|
||
considered delivered, sends a sig_post reply message on REPLY_PORT
|
||
indicating success. SS is not locked. */
|
||
|
||
extern void _hurd_internal_post_signal (struct hurd_sigstate *ss,
|
||
int signo,
|
||
struct hurd_signal_detail *detail,
|
||
mach_port_t reply_port,
|
||
mach_msg_type_name_t reply_port_type,
|
||
int untraced);
|
||
|
||
/* Set up STATE and SS to handle signal SIGNO by running HANDLER. If
|
||
RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to
|
||
finish before running the signal handler. The handler is passed SIGNO,
|
||
SIGCODE, and the returned `struct sigcontext' (which resides on the
|
||
stack the handler will use, and which describes the state of the thread
|
||
encoded in STATE before running the handler). */
|
||
|
||
struct machine_thread_all_state;
|
||
extern struct sigcontext *
|
||
_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
||
int signo, struct hurd_signal_detail *detail,
|
||
int rpc_wait, struct machine_thread_all_state *state);
|
||
|
||
/* Function run by the signal thread to receive from the signal port. */
|
||
|
||
extern void _hurd_msgport_receive (void);
|
||
|
||
/* 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. */
|
||
|
||
extern void _hurd_siginfo_handler (int);
|
||
|
||
/* Replacement for mach_msg used in RPCs to provide Hurd interruption
|
||
semantics. Args are all the same as for mach_msg. intr-rpc.h arranges
|
||
for this version to be used automatically by the RPC stubs the library
|
||
builds in place of the normal mach_msg. */
|
||
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);
|
||
|
||
|
||
/* 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. */
|
||
#define _SIG_CANT_MASK (__sigmask (SIGSTOP) | __sigmask (SIGKILL))
|
||
|
||
/* Do an RPC to a process's message port.
|
||
|
||
Each argument is an expression which returns an error code; each
|
||
expression may be evaluated several times. FETCH_MSGPORT_EXPR should
|
||
fetch the appropriate message port and store it in the local variable
|
||
`msgport'; it will be deallocated after use. FETCH_REFPORT_EXPR should
|
||
fetch the appropriate message port and store it in the local variable
|
||
`refport' (if no reference port is needed in the call, then
|
||
FETCH_REFPORT_EXPR should be simply KERN_SUCCESS or 0); if
|
||
DEALLOC_REFPORT evaluates to nonzero it will be deallocated after use,
|
||
otherwise the FETCH_REFPORT_EXPR must take care of user references to
|
||
`refport'. RPC_EXPR should perform the desired RPC operation using
|
||
`msgport' and `refport'.
|
||
|
||
The reason for the complexity is that a process's message port and
|
||
reference port may change between fetching those ports and completing an
|
||
RPC using them (usually they change only when a process execs). The RPC
|
||
will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can
|
||
send the RPC request; or with MIG_SERVER_DIED if the msgport was
|
||
destroyed after we sent the RPC request but before it was serviced. In
|
||
either of these cases, we retry the entire operation, discarding the old
|
||
message and reference ports and fetch them anew. */
|
||
|
||
#define HURD_MSGPORT_RPC(fetch_msgport_expr, \
|
||
fetch_refport_expr, dealloc_refport, \
|
||
rpc_expr) \
|
||
({ \
|
||
error_t __err; \
|
||
mach_port_t msgport, refport = MACH_PORT_NULL; \
|
||
do \
|
||
{ \
|
||
/* Get the message port. */ \
|
||
if (__err = (fetch_msgport_expr)) \
|
||
break; \
|
||
/* Get the reference port. */ \
|
||
if (__err = (fetch_refport_expr)) \
|
||
{ \
|
||
/* Couldn't get it; deallocate MSGPORT and fail. */ \
|
||
__mach_port_deallocate (__mach_task_self (), msgport); \
|
||
break; \
|
||
} \
|
||
__err = (rpc_expr); \
|
||
__mach_port_deallocate (__mach_task_self (), msgport); \
|
||
if ((dealloc_refport) && refport != MACH_PORT_NULL) \
|
||
__mach_port_deallocate (__mach_task_self (), refport); \
|
||
} while (__err == MACH_SEND_INVALID_DEST || \
|
||
__err == MIG_SERVER_DIED); \
|
||
__err; \
|
||
})
|
||
|
||
|
||
#endif /* hurd/signal.h */
|