add directory gnu
This commit is contained in:
486
gnu/glibc/glibc-1.03/hurd/hurdsig.c
Normal file
486
gnu/glibc/glibc-1.03/hurd/hurdsig.c
Normal file
@@ -0,0 +1,486 @@
|
||||
/* Copyright (C) 1991, 1992 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.h>
|
||||
#include <gnu-stabs.h>
|
||||
|
||||
struct mutex _hurd_siglock;
|
||||
int _hurd_stopped;
|
||||
|
||||
/* Port that receives signals and other miscellaneous messages. */
|
||||
mach_port_t _hurd_sigport;
|
||||
|
||||
/* Thread which receives task-global signals. */
|
||||
thread_t _hurd_sigthread;
|
||||
|
||||
/* Linked-list of per-thread signal state. */
|
||||
struct _hurd_sigstate *_hurd_sigstates;
|
||||
|
||||
struct _hurd_sigstate *
|
||||
_hurd_thread_sigstate (thread_t thread)
|
||||
{
|
||||
struct _hurd_sigstate *ss;
|
||||
__mutex_lock (&_hurd_siglock);
|
||||
for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
|
||||
if (ss->thread == thread)
|
||||
break;
|
||||
if (ss == NULL)
|
||||
{
|
||||
ss = calloc (1, sizeof (*ss)); /* Zero-initialized. */
|
||||
if (ss == NULL)
|
||||
__libc_fatal ("hurd: Can't allocate thread sigstate\n");
|
||||
ss->thread = thread;
|
||||
__mutex_init (&ss->lock);
|
||||
ss->next = _hurd_sigstates;
|
||||
_hurd_sigstates = ss;
|
||||
}
|
||||
__mutex_lock (&ss->lock);
|
||||
__mutex_unlock (&_hurd_siglock);
|
||||
return ss;
|
||||
}
|
||||
|
||||
#include <hurd/core.h>
|
||||
|
||||
/* Limit on size of core files. */
|
||||
int _hurd_core_limit;
|
||||
|
||||
/* Call the core server to mummify us before we die.
|
||||
Returns nonzero if a core file was written. */
|
||||
static inline int
|
||||
write_corefile (int signo, int sigcode)
|
||||
{
|
||||
error_t err;
|
||||
mach_port_t coreserver;
|
||||
int dealloc_crdir, dealloc_ccdir;
|
||||
file_t crdir, ccdir;
|
||||
|
||||
if (_hurd_core_limit == 0)
|
||||
/* User doesn't want a core. */
|
||||
return 0;
|
||||
|
||||
coreserver = __path_lookup (_SERVERS_CORE, 0, 0);
|
||||
if (coreserver == MACH_PORT_NULL)
|
||||
return 0;
|
||||
|
||||
ccdir = _hurd_port_get (&_hurd_ccdir, &dealloc_ccdir);
|
||||
|
||||
crdir = _hurd_port_get (&_hurd_crdir, &dealloc_crdir);
|
||||
err = __hurd_path_lookup (crdir, ccdir, "core"
|
||||
FS_LOOKUP_WRITE|FS_LOOKUP_CREATE,
|
||||
0666 & ~_hurd_umask,
|
||||
&file);
|
||||
_hurd_port_free (crdir, &dealloc_crdir);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
err = __core_dump_task (coreserver,
|
||||
__mach_task_self (),
|
||||
file,
|
||||
signo, sigcode,
|
||||
getenv ("GNUTARGET"));
|
||||
__mach_port_deallocate (__mach_task_self (), coreserver);
|
||||
if (!err && _hurd_core_limit != RLIM_INFINITY)
|
||||
{
|
||||
io_statbuf_t stb;
|
||||
err = __io_stat (file, &stb);
|
||||
if (!err && stb.stb_size > _hurd_core_limit)
|
||||
err = EFBIG;
|
||||
}
|
||||
__mach_port_deallocate (__mach_task_self (), file);
|
||||
if (err)
|
||||
(void) __dir_unlink (ccdir, "core");
|
||||
}
|
||||
|
||||
_hurd_port_free (ccdir, &dealloc_ccdir);
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
||||
|
||||
extern const size_t _hurd_thread_state_count;
|
||||
|
||||
/* How long to give servers to respond to
|
||||
interrupt_operation before giving up on them. */
|
||||
mach_msg_timeout_t _hurd_interrupt_timeout = 1000; /* One second. */
|
||||
|
||||
/* SS->thread is suspended. Fills STATE in with its registers.
|
||||
SS->lock is held and kept. */
|
||||
static inline void
|
||||
abort_rpcs (struct _hurd_sigstate *ss, int signo, void *state)
|
||||
{
|
||||
if (ss->intr_port != MACH_PORT_NULL)
|
||||
{
|
||||
/* This is the address the PC will be at if the thread
|
||||
is waiting for a mach_msg syscall to return. */
|
||||
extern const int __mach_msg_trap_syscall_pc;
|
||||
extern error_t _hurd_thread_state (thread_t, void *state);
|
||||
extern int *_hurd_thread_pc (void *state);
|
||||
|
||||
/* Abort whatever the thread is doing.
|
||||
If it is in the mach_msg syscall doing the send,
|
||||
the syscall will return MACH_SEND_INTERRUPTED. */
|
||||
__thread_abort (ss->thread);
|
||||
_hurd_thread_state (ss->thread, state);
|
||||
|
||||
if (_hurd_thread_pc (state) == &__mach_msg_trap_syscall_pc)
|
||||
{
|
||||
/* The thread was waiting for the RPC to return.
|
||||
Abort the operation. The RPC will return EINTR. */
|
||||
|
||||
struct
|
||||
{
|
||||
mach_msg_header_t header;
|
||||
mach_msg_type_t type;
|
||||
kern_return_t retcode;
|
||||
} msg;
|
||||
kern_return_t err;
|
||||
|
||||
msg.header.msgh_request_port = ss->intr_port;
|
||||
msg.header.msgh_reply_port = __mach_reply_port ();
|
||||
msg.header.msgh_seqno = 0;
|
||||
msg.header.msgh_id = 33000; /* interrupt_operation XXX */
|
||||
err = __mach_msg (&msg.header,
|
||||
MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT,
|
||||
sizeof (msg.header), sizeof (msg),
|
||||
msg.header.msgh_reply_port,
|
||||
_hurd_interrupt_timeout,
|
||||
MACH_PORT_NULL);
|
||||
if (err != MACH_MSG_SUCCESS)
|
||||
/* The interrupt didn't work.
|
||||
Destroy the receive right the thread is blocked on. */
|
||||
__mach_port_destroy (__mach_task_self (),
|
||||
/* XXX */
|
||||
_hurd_thread_reply_port (ss->thread));
|
||||
else
|
||||
/* In case the server returned something screwy. */
|
||||
__mach_msg_destroy (&msg.header);
|
||||
|
||||
/* Tell the thread whether it should restart the
|
||||
operation or return EINTR when it wakes up. */
|
||||
ss->intr_restart = ss->actions[signo].sa_flags & SA_RESTART;
|
||||
}
|
||||
|
||||
/* If the thread is anywhere before the system call trap,
|
||||
it will start the operation after the signal is handled.
|
||||
|
||||
If the thread is after the system call trap, but before it has
|
||||
cleared SS->intr_port, the operation is already finished. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Abort the RPCs being run by all threads but this one;
|
||||
all other threads should be suspended. */
|
||||
static inline void
|
||||
abort_all_rpcs (int signo, void *state)
|
||||
{
|
||||
thread_t me = __mach_thread_self ();
|
||||
thread_t *threads;
|
||||
size_t nthreads, i;
|
||||
|
||||
__task_threads (__mach_task_self (), &threads, &nthreads);
|
||||
for (i = 0; i < nthreads; ++i)
|
||||
{
|
||||
if (threads[i] != me)
|
||||
{
|
||||
struct _hurd_sigstate *ss = _hurd_thread_sigstate (*nthreads);
|
||||
abort_rpcs (ss, signo, state);
|
||||
__mutex_unlock (&ss->lock);
|
||||
}
|
||||
__mach_port_deallocate (__mach_task_self (), threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Deliver a signal.
|
||||
SS->lock is held on entry and released before return. */
|
||||
error_t
|
||||
_hurd_internal_post_signal (reply_port_t reply,
|
||||
struct _hurd_sigstate *ss,
|
||||
int signo,
|
||||
int sigcode,
|
||||
sigset_t *restore_blocked)
|
||||
{
|
||||
char thread_state[_hurd_thread_state_count];
|
||||
enum { stop, ignore, core, term } act;
|
||||
|
||||
if (ss->actions[signo].sa_handler == SIG_DFL)
|
||||
switch (signo)
|
||||
{
|
||||
case 0:
|
||||
/* A sig_post msg with SIGNO==0 is sent to
|
||||
tell us to check for pending signals. */
|
||||
act = ignore;
|
||||
break;
|
||||
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGSTOP:
|
||||
case SIGTSTP:
|
||||
ss->pending &= ~sigmask (SIGCONT);
|
||||
act = stop;
|
||||
break;
|
||||
|
||||
case SIGCONT:
|
||||
ss->pending &= ~(sigmask (SIGSTOP) | sigmask (SIGTSTP) |
|
||||
sigmask (SIGTTIN) | sigmask (SIGTTOU));
|
||||
/* Fall through. */
|
||||
case SIGIO:
|
||||
case SIGURG:
|
||||
case SIGCHLD:
|
||||
case SIGWINCH:
|
||||
act = ignore;
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
case SIGIOT:
|
||||
case SIGEMT:
|
||||
case SIGFPE:
|
||||
case SIGBUS:
|
||||
case SIGSEGV:
|
||||
case SIGSYS:
|
||||
act = core;
|
||||
break;
|
||||
|
||||
default:
|
||||
act = term;
|
||||
break;
|
||||
}
|
||||
else if (ss->actions[signo].sa_handler == SIG_IGN)
|
||||
act = ignore;
|
||||
else
|
||||
act = handle;
|
||||
if (_hurd_orphaned && (signo == SIGTTIN || signo == SIGTTOU) && act == stop)
|
||||
{
|
||||
sigcode = signo;
|
||||
signo = SIGKILL;
|
||||
act = term;
|
||||
}
|
||||
|
||||
/* Handle receipt of a blocked signal. */
|
||||
if ((__sigismember (signo, &ss->blocked) && act != ignore) ||
|
||||
(signo != SIGKILL && _hurd_stopped))
|
||||
{
|
||||
__sigaddmember (signo, &ss->pending);
|
||||
/* Save the code to be given to the handler when SIGNO is unblocked. */
|
||||
ss->sigcodes[signo] = sigcode;
|
||||
act = ignore;
|
||||
}
|
||||
|
||||
if (restore_blocked != NULL)
|
||||
ss->blocked = *restore_blocked;
|
||||
|
||||
switch (act)
|
||||
{
|
||||
case stop:
|
||||
if (reply != MACH_PORT_NULL)
|
||||
__sig_post_reply (reply, POSIX_SUCCESS);
|
||||
_HURD_PORT_USE
|
||||
(&_hurd_proc,
|
||||
({
|
||||
/* Hold the siglock while stopping other threads to be
|
||||
sure it is not held by another thread afterwards. */
|
||||
__mutex_unlock (&ss->lock);
|
||||
__mutex_lock (&_hurd_siglock);
|
||||
__proc_dostop (port, __mach_thread_self ());
|
||||
__mutex_unlock (&_hurd_siglock);
|
||||
abort_all_rpcs (signo, thread_state);
|
||||
__proc_markstop (port, signo);
|
||||
}));
|
||||
_hurd_stopped = 1;
|
||||
|
||||
__mutex_lock (&ss->lock);
|
||||
if (ss->suspended)
|
||||
/* There is a sigsuspend waiting. Tell it to wake up. */
|
||||
__condition_signal (&ss->arrived);
|
||||
else
|
||||
__mutex_unlock (&ss->lock);
|
||||
|
||||
return MIG_NO_REPLY; /* Already replied. */
|
||||
|
||||
case ignore:
|
||||
if (reply != MACH_PORT_NULL)
|
||||
__sig_post_reply (reply, POSIX_SUCCESS);
|
||||
break;
|
||||
|
||||
case core:
|
||||
case term:
|
||||
if (reply != MACH_PORT_NULL)
|
||||
__sig_post_reply (reply, POSIX_SUCCESS);
|
||||
_HURD_PORT_USE
|
||||
(&_hurd_proc,
|
||||
({
|
||||
__proc_dostop (port, __mach_thread_self ());
|
||||
abort_all_rpcs (signo, thread_state);
|
||||
__proc_exit (port,
|
||||
(W_EXITCODE (0, signo) |
|
||||
(act == core && write_corefile (signo, sigcode) ?
|
||||
WCOREDUMP : 0)))
|
||||
}));
|
||||
__task_terminate (__mach_task_self ());
|
||||
return MIG_NO_REPLY; /* Yeah, right. */
|
||||
|
||||
case handle:
|
||||
if (reply != MACH_PORT_NULL)
|
||||
__sig_post_reply (reply, POSIX_SUCCESS);
|
||||
__thread_suspend (ss->thread);
|
||||
abort_rpcs (ss, signo, thread_state);
|
||||
{
|
||||
const sigset_t blocked = ss->blocked;
|
||||
ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
|
||||
_hurd_run_sighandler (ss->thread, signo, sigcode,
|
||||
ss->actions[signo].sa_handler,
|
||||
ss->actions[signo].sa_flags,
|
||||
blocked,
|
||||
&ss->sigstack,
|
||||
thread_state);
|
||||
}
|
||||
__thread_resume (ss->thread);
|
||||
}
|
||||
|
||||
/* We get here only if we are handling or ignoring the signal;
|
||||
otherwise we are stopped or dead by now. We still hold SS->lock.
|
||||
Check for pending signals, and loop to post them. */
|
||||
for (signo = 1; signo < NSIG; ++signo)
|
||||
if (__sigismember (signo, &ss->pending))
|
||||
{
|
||||
__sigdelmember (signo, &ss->pending);
|
||||
return _hurd_internal_post_signal (MACH_PORT_NULL, ss,
|
||||
signo, ss->sigcodes[signo],
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (ss->suspended)
|
||||
/* There is a sigsuspend waiting. Tell it to wake up. */
|
||||
__condition_signal (&ss->arrived);
|
||||
else
|
||||
__mutex_unlock (&ss->lock);
|
||||
|
||||
return MIG_NO_REPLY;
|
||||
}
|
||||
|
||||
/* Called by the proc server to send a signal. */
|
||||
error_t
|
||||
__sig_post (sigthread_t me,
|
||||
mig_reply_port_t reply,
|
||||
int signo,
|
||||
mach_port_t refport)
|
||||
{
|
||||
struct _hurd_sigstate *ss;
|
||||
|
||||
if (signo < 0 || signo >= NSIG)
|
||||
return EINVAL;
|
||||
|
||||
if (refport == __mach_task_self ())
|
||||
/* Can send any signal. */
|
||||
goto win;
|
||||
else if (refport == _hurd_cttyport)
|
||||
switch (signo)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGQUIT:
|
||||
case SIGTSTP:
|
||||
case SIGHUP:
|
||||
goto win;
|
||||
}
|
||||
else
|
||||
{
|
||||
static mach_port_t sessport = MACH_PORT_NULL;
|
||||
if (sessport == MACH_PORT_NULL)
|
||||
_HURD_PORT_USE (&_hurd_proc,
|
||||
__proc_getsidport (port, &sessport));
|
||||
if (sessport != MACH_PORT_NULL &&
|
||||
refport == sessport && signo == SIGCONT)
|
||||
goto win;
|
||||
}
|
||||
|
||||
/* XXX async io? */
|
||||
return EPERM;
|
||||
|
||||
win:
|
||||
ss = _hurd_thread_sigstate (_hurd_sigthread);
|
||||
return _hurd_internal_post_signal (reply, ss, signo, 0, NULL);
|
||||
}
|
||||
|
||||
/* Called by the exception handler to take a signal. */
|
||||
void
|
||||
_hurd_exc_post_signal (thread_t thread, int signo, int sigcode)
|
||||
{
|
||||
(void) _hurd_internal_post_signal (MACH_PORT_NULL,
|
||||
_hurd_thread_sigstate (thread),
|
||||
signo, sigcode, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_hurdsig_init (void)
|
||||
{
|
||||
thread_t sigthread;
|
||||
|
||||
__mutex_init (&_hurd_siglock);
|
||||
|
||||
if (_hurd_sigport == MACH_PORT_NULL)
|
||||
if (err = __mach_port_allocate (__mach_task_self (),
|
||||
MACH_PORT_RIGHT_RECEIVE,
|
||||
&_hurd_sigport))
|
||||
__libc_fatal ("hurd: Can't create signal port receive right\n");
|
||||
|
||||
if (err = __thread_create (__mach_task_self (), &sigthread))
|
||||
__libc_fatal ("hurd: Can't create signal thread\n");
|
||||
if (err = _hurd_start_sigthread (sigthread, _hurd_sigport_receive))
|
||||
__libc_fatal ("hurd: Can't start signal thread\n");
|
||||
_hurd_sigport_thread = sigthread;
|
||||
|
||||
/* Make a send right to the signal port. */
|
||||
if (err = __mach_port_insert_right (__mach_task_self (),
|
||||
_hurd_sigport,
|
||||
MACH_PORT_RIGHT_MAKE_SEND))
|
||||
__libc_fatal ("hurd: Can't create send right to signal port\n");
|
||||
|
||||
/* Receive exceptions on the signal port. */
|
||||
__task_set_special_port (__mach_task_self (),
|
||||
TASK_EXCEPTION,
|
||||
_hurd_sigport);
|
||||
}
|
||||
|
||||
/* Make PROCSERVER be our proc server port.
|
||||
Tell the proc server that we exist. */
|
||||
|
||||
void
|
||||
_hurd_proc_init (process_t procserver, char **argv)
|
||||
{
|
||||
mach_port_t oldsig, oldtask;
|
||||
|
||||
_hurd_port_init (&_hurd_proc, procserver);
|
||||
|
||||
/* Tell the proc server where our args and environment are. */
|
||||
__proc_setprocargs (procserver, argv, __environ);
|
||||
|
||||
/* Initialize the signal code; Mach exceptions will become signals.
|
||||
This sets _hurd_sigport; it must be run before _hurd_proc_init. */
|
||||
_hurdsig_init ();
|
||||
|
||||
/* Give the proc server our task and signal ports. */
|
||||
__proc_setports (procserver,
|
||||
_hurd_sigport, __mach_task_self (),
|
||||
&oldsig, &oldtask);
|
||||
if (oldsig != MACH_PORT_NULL)
|
||||
__mach_port_deallocate (__mach_task_self (), oldsig);
|
||||
if (oldtask != MACH_PORT_NULL)
|
||||
__mach_port_deallocate (__mach_task_self (), oldtask);
|
||||
}
|
||||
Reference in New Issue
Block a user