diff options
author | Neal H. Walfield <neal@gnu.org> | 2008-03-01 13:07:25 +0000 |
---|---|---|
committer | Thomas Schwinge <tschwinge@gnu.org> | 2009-04-07 23:15:17 +0200 |
commit | 16de69f4d41a3105a3e14720f9ec81efaae5a78e (patch) | |
tree | d4b2afe3fbb1df6bb1eb2c8126d9cf924c75df65 | |
parent | 57f2488654f1407bb6f00a9551a799643b87c903 (diff) |
2008-03-01 Neal H. Walfield <neal@gnu.org>
Add signal implementation.
* Makefile.am (SYSDEP_PATH): Add $(srcdir)/signal.
(libpthread_a_SOURCES): Add pt-mutex-transfer-np.c, kill.c,
killpg.c, pt-kill-siginfo-np.c, raise.c, sigaction.c, sigaddset.c,
sigaltstack.c, sigdelset.c, sigemptyset.c, sigfillset.c,
sig-internal.c, sig-internal.h, siginterrupt.c, sigismember.c,
signal.c, signal-dispatch.c, signal.h, sigpending.c,
sigprocmask.c, sigsuspend.c, sigtimedwait.c, sigwait.c,
sigwaiter.c, sigwaitinfo.c, signal-dispatch-lowlevel.c, and
sigprocmask.c.
* headers.m4: Link libpthread/signal/signal.h into ../include.
* sysdeps/generic/pt-mutex-transfer-np.c: New file.
* signal/README: New file.
* signal/TODO: Likewise.
* signal/kill.c: Likewise.
* signal/pt-kill-siginfo-np.c: Likewise.
* signal/sig-internal.c: Likewise.
* signal/sig-internal.h: Likewise.
* signal/sigaction.c: Likewise.
* signal/sigaltstack.c: Likewise.
* signal/signal-dispatch.c: Likewise.
* signal/signal.h: Likewise.
* signal/sigpending.c: Likewise.
* signal/sigsuspend.c: Likewise.
* signal/sigtimedwait.c: Likewise.
* signal/sigwaiter.c: Likewise.
* signal/sigwaitinfo.c: Likewise.
* sysdeps/l4/hurd/sig-sysdep.h: Likewise.
* sysdeps/l4/hurd/sigprocmask.c: Likewise.
* sysdeps/generic/killpg.c: Likewise.
* sysdeps/generic/pt-kill.c: Likewise.
* sysdeps/generic/raise.c: Likewise.
* sysdeps/generic/sigaddset.c: Likewise.
* sysdeps/generic/sigdelset.c: Likewise.
* sysdeps/generic/sigemptyset.c: Likewise.
* sysdeps/generic/sigfillset.c: Likewise.
* sysdeps/generic/siginterrupt.c: Likewise.
* sysdeps/generic/sigismember.c: Likewise.
* sysdeps/generic/signal.c: Likewise.
* sysdeps/generic/sigwait.c: Likewise.
* sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c: Likewise.
* sysdeps/l4/hurd/pt-sysdep.c (sigprocmask): Remove function.
* sysdeps/l4/hurd/pt-sigstate.c (__pthread_sigstate): Implement
it.
* sysdeps/l4/hurd/pt-sigstate-init.c: Include <sig-internal.h>.
(__pthread_sigstate_init): Initialize THREAD->SS.
* sysdeps/l4/hurd/pt-kill.c: Remove file.
* pthread/pt-internal.h: Include <sig-internal.h>.
(PTHREAD_SIGNAL_MEMBERS) [! PTHREAD_SIGNAL_MEMBERS]: Define.
(struct __pthread): Add PTHREAD_SIGNAL_MEMBERS.
* pthread/pt-self.c (pthread_self): Assert that SELF is not NULL.
37 files changed, 2057 insertions, 15 deletions
diff --git a/Makefile.am b/Makefile.am index df146dff..89f4f297 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ if ARCH_POWERPC arch=powerpc endif -# The source files is scattered over several directories. Add +# The source files are scattered over several directories. Add # all these directories to the vpath. SYSDEP_PATH = $(srcdir)/sysdeps/l4/hurd/${arch} \ $(srcdir)/sysdeps/l4/${arch} \ @@ -35,6 +35,7 @@ SYSDEP_PATH = $(srcdir)/sysdeps/l4/hurd/${arch} \ $(srcdir)/sysdeps/generic \ $(srcdir)/sysdeps/posix \ $(srcdir)/pthread \ + $(srcdir)/signal \ $(srcdir)/include vpath %.c $(SYSDEP_PATH) @@ -87,6 +88,7 @@ libpthread_a_SOURCES = pt-attr.c pt-attr-destroy.c pt-attr-getdetachstate.c \ pt-mutex-init.c pt-mutex-destroy.c \ pt-mutex-lock.c pt-mutex-trylock.c pt-mutex-timedlock.c \ pt-mutex-unlock.c \ + pt-mutex-transfer-np.c \ pt-mutex-getprioceiling.c pt-mutex-setprioceiling.c \ pt-rwlock-attr.c \ pt-rwlockattr-init.c pt-rwlockattr-destroy.c \ @@ -129,4 +131,31 @@ libpthread_a_SOURCES = pt-attr.c pt-attr-destroy.c pt-attr-getdetachstate.c \ pt-getschedparam.c pt-setschedparam.c pt-setschedprio.c \ sem-close.c sem-init.c sem-timedwait.c sem-wait.c \ sem-destroy.c sem-open.c sem-trywait.c sem-getvalue.c \ - sem-post.c sem-unlink.c + sem-post.c sem-unlink.c \ + \ + kill.c \ + killpg.c \ + pt-kill-siginfo-np.c \ + raise.c \ + sigaction.c \ + sigaddset.c \ + sigaltstack.c \ + sigdelset.c \ + sigemptyset.c \ + sigfillset.c \ + sig-internal.c \ + sig-internal.h \ + siginterrupt.c \ + sigismember.c \ + signal.c \ + signal-dispatch.c \ + signal.h \ + sigpending.c \ + sigprocmask.c \ + sigsuspend.c \ + sigtimedwait.c \ + sigwait.c \ + sigwaiter.c \ + sigwaitinfo.c \ + signal-dispatch-lowlevel.c \ + sigprocmask.c @@ -33,4 +33,5 @@ AC_CONFIG_LINKS([ include/bits/pthread-np.h:libpthread/sysdeps/l4/bits/pthread-np.h include/semaphore.h:libpthread/include/semaphore.h include/bits/semaphore.h:libpthread/sysdeps/generic/bits/semaphore.h + include/signal.h:libpthread/signal/signal.h ]) diff --git a/pthread/pt-internal.h b/pthread/pt-internal.h index 6d34be13..41fbc830 100644 --- a/pthread/pt-internal.h +++ b/pthread/pt-internal.h @@ -33,6 +33,8 @@ #include <pt-sysdep.h> #include <pt-machdep.h> +#include <sig-internal.h> + /* Thread state. */ enum pthread_state { @@ -50,6 +52,10 @@ enum pthread_state # define PTHREAD_SYSDEP_MEMBERS #endif +#ifndef PTHREAD_SIGNAL_MEMBERS +# define PTHREAD_SIGNAL_MEMBERS +#endif + /* This structure describes a POSIX thread. */ struct __pthread { @@ -85,6 +91,8 @@ struct __pthread PTHREAD_SYSDEP_MEMBERS + PTHREAD_SIGNAL_MEMBERS + struct __pthread *next, **prevp; }; diff --git a/pthread/pt-self.c b/pthread/pt-self.c index e14fe1eb..49768643 100644 --- a/pthread/pt-self.c +++ b/pthread/pt-self.c @@ -1,5 +1,5 @@ /* Get calling thread's ID. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2008 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 @@ -25,5 +25,8 @@ pthread_t pthread_self (void) { - return _pthread_self()->thread; + struct __pthread *self = _pthread_self (); + assert (self); + + return self->thread; } diff --git a/signal/README b/signal/README new file mode 100644 index 00000000..5487e2e3 --- /dev/null +++ b/signal/README @@ -0,0 +1,4 @@ +This directory provides a signal implementation, which is appropriate +for operating systems where signals are managed at user-level. It is +up to the run-time to catch the signals and forward them to the +implementation via, e.g., the pthread_kill_info_np call. diff --git a/signal/TODO b/signal/TODO new file mode 100644 index 00000000..1148abb3 --- /dev/null +++ b/signal/TODO @@ -0,0 +1,29 @@ +Unimplemented Functionality +--------------------------- + +We don't support interruptible functions. That is, if a signal is +delivered when a thread is in e.g. the write system call, then the +write function should be interrupted and return EINTR when the signal +handler is finished. To realize this behavior, we could have a thread +local interruptible flag and a setjmp buffer. A function that is +interruptible would fill the jump buffer and set the interruptible +flag. If a signal comes in and the interruptible flag is set, rather +than resuming the thread, we longjmp to the buffer. + +If a signal action has set the SA_SIGINFO, the third argument must be +a pointer to a ucontext describing the thread's interrupted state; +this implementation passes NULL. This isn't as bad as it sounds as +the the ucontext family of functions are marked obsolete in SUSv3 with +the advisory that any use of them should be replaced by the use of +pthread functionality (cf. makecontext rationale). + +stop and continue signals are not implemented (as we need to stop all +threads, this requires being in bed with libpthread). + +Implementation is not yet cancellation-safe. + +There are not even stubs for sighold, sigingore, sigpause, sigrelse, +however, according to posix: "Use of any of these functions is +unspecified in a multi-threaded process." + +Implement sigtimedwait, sigqueue.
\ No newline at end of file diff --git a/signal/kill.c b/signal/kill.c new file mode 100644 index 00000000..27c9c32a --- /dev/null +++ b/signal/kill.c @@ -0,0 +1,70 @@ +/* kill.c - Generic kill implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +kill (pid_t pid, int signo) +{ + if (pid != getpid ()) + { + errno = EOPNOTSUPP; + return -1; + } + + /* "Signals generated for the process shall be delivered to exactly + one of those threads within the process which is in a call to a + sigwait() function selecting that signal or has not blocked + delivery of the signal. If there are no threads in a call to a + sigwait() function selecting that signal, and if all threads + within the process block delivery of the signal, the signal shall + remaing pending on the process" (2.4.1). */ + + /* First, see if there is a waiter, which is interested in this + signal. */ + pthread_mutex_lock (&sig_lock); + + struct sigwaiter *waiter; + for (waiter = sigwaiters; waiter; waiter = waiter->next) + if ((waiter->signals & sigmask (signo))) + /* Got a winner. */ + { + sigdelset (&process_pending, signo); + + pthread_mutex_lock (&waiter->ss->lock); + sigdelset (&waiter->ss->pending, signo); + + memset (&waiter->info, 0, sizeof (waiter->info)); + waiter->info.si_signo = signo; + + sigwaiter_unblock (waiter); + + return 0; + } + + pthread_mutex_unlock (&sig_lock); + + /* XXX: We just generate the signal for the current thread. If the + current thread has blocked the signal, the correct thing to do is + to iterate over all the other threads and find on that hasn't + blocked it. */ + return pthread_kill (pthread_self (), signo); +} + diff --git a/signal/pt-kill-siginfo-np.c b/signal/pt-kill-siginfo-np.c new file mode 100644 index 00000000..9bdf6cc4 --- /dev/null +++ b/signal/pt-kill-siginfo-np.c @@ -0,0 +1,88 @@ +/* pthread-kill-siginfo-np.c - Generic pthread_kill_siginfo_np implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "pt-internal.h" +#include "sig-internal.h" + +int +pthread_kill_siginfo_np (pthread_t tid, siginfo_t si) +{ + int sig = si.si_signo; + + if (sig < 0 || sig >= NSIG) + return EINVAL; + + if (sig == 0) + return 0; + + struct signal_state *ss = &__pthread_getid (tid)->ss; + + pthread_mutex_lock (&sig_lock); + pthread_mutex_lock (&ss->lock); + + if (ss->sigwaiter && (ss->sigwaiter->signals & sigmask (si.si_signo))) + /* The thread is in a call to sigwait. */ + { + ss->sigwaiter->info = si; + sigwaiter_unblock (ss->sigwaiter); + return 0; + } + + pthread_mutex_unlock (&sig_lock); + + if (ss->actions[sig - 1].sa_handler == (void *) SIG_IGN + || (ss->actions[sig - 1].sa_handler == (void *) SIG_DFL + && default_action (sig) == sig_ignore)) + /* It is unclear (to me) what is supposed to happen when a signal + is generated for a thread, which is blocking that signal and + ignoring it. POSIX does say that when the action associated + with a pending, blocked signal is set to SIG_IGN, the pending + signal is to be cleared. Thus, it makes sense that any signal + set to ignore is discarded at generation. */ + { + pthread_mutex_unlock (&ss->lock); + return 0; + } + + + if ((sigmask (sig) & ss->blocked)) + /* The signal is blocked. Mark it pending. */ + { + ss->pending |= sigmask (sig); + pthread_mutex_unlock (&ss->lock); + return 0; + } + + if (pthread_self () == tid + && (! (ss->actions[si.si_signo - 1].sa_flags & SA_ONSTACK) + || (ss->stack.ss_flags & SS_DISABLE) + || (ss->stack.ss_flags & SS_ONSTACK))) + /* We are sending a signal to ourself and we don't use an + alternate stack. */ + signal_dispatch (ss, &si); + else + signal_dispatch_lowlevel (ss, tid, si); + + /* Don't unlock ss: signal_dispatch and signal_dispatch_lowlevel + assume ownership of the lock. */ + + return 0; +} + diff --git a/signal/sig-internal.c b/signal/sig-internal.c new file mode 100644 index 00000000..f73f38b4 --- /dev/null +++ b/signal/sig-internal.c @@ -0,0 +1,26 @@ +/* sig-internal.c - Signal state functions. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +pthread_mutex_t sig_lock = PTHREAD_MUTEX_INITIALIZER; + +sigset_t process_pending; +siginfo_t process_pending_info[NSIG]; diff --git a/signal/sig-internal.h b/signal/sig-internal.h new file mode 100644 index 00000000..6c86c796 --- /dev/null +++ b/signal/sig-internal.h @@ -0,0 +1,177 @@ +/* sig-internal.h - Internal signal handling interface. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef SIG_INTERNAL_H +#define SIG_INTERNAL_H + +#include <signal.h> + +#include <sig-sysdep.h> + +#define sigmask(sig) (1ULL << (sig - 1)) +#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \ + sigmask (SIGSTOP) | sigmask (SIGTSTP)) + +/* General lock. Protects PROCESS_PENDING, PROCESS_PENDING_INFO, + SIGWAITERS. */ +extern pthread_mutex_t sig_lock; + +/* "Signals generated for the process shall be delivered to exactly + one of those threads within the process which is in a call to a + sigwait() function selecting that signal or has not blocked + delivery of the signal. If there are no threads in a call to a + sigwait() function selecting that signal, and if all threads within + the process block delivery of the signal, the signal shall remaing + pending on the process" (2.4.1). + + This variable is protected by SIG_LOCK. */ +extern sigset_t process_pending; +extern siginfo_t process_pending_info[NSIG]; + +struct sigwaiter; + +/* The per-thread signal state. */ +struct signal_state +{ + /* Protects the following fields. STACK.SA_FLAGS may be accessed + using atomic operations. */ + pthread_mutex_t lock; + + /* Pending signals. */ + sigset_t pending; + + /* Blocked signals (i.e., the signal mask). */ + sigset_t blocked; + + stack_t stack; + struct sigaction actions[NSIG]; + siginfo_t info[NSIG]; + + /* If the thread is blocked in a call to sigwait. */ + struct sigwaiter *sigwaiter; +}; + +#define PTHREAD_SIGNAL_MEMBERS struct signal_state ss; + +/* Arranges for thread TID to call signal_dispatch. Must not be + called if TID is the caller and an alternate stack is not required. + In this case, the caller should call signal_dispatch directly. */ +extern void signal_dispatch_lowlevel (struct signal_state *ss, + pthread_t tid, siginfo_t si); + +/* This is the signal handler entry point. A thread is forced into + this state when it receives a signal. We need to save the thread's + state and then invoke the high-level signal dispatcher. SS->LOCK + is locked by the caller. */ +extern void signal_dispatch (struct signal_state *ss, siginfo_t *si); + +#ifndef SIGNAL_DISPATCH_ENTRY +#define SIGNAL_DISPATCH_ENTRY +#endif + +#ifndef SIGNAL_DISPATCH_EXIT +#define SIGNAL_DISPATCH_EXIT +#endif + +/* When a thread calls sigwait and a requested signal is not pending, + it allocates the following structure, fills it in, adds it to + sigwaiters and sleeps. */ +struct sigwaiter +{ + struct sigwaiter *next; + struct sigwaiter *prev; + + /* Thread's signal state. */ + struct signal_state *ss; + + /* Signals this thread is waiting for. */ + sigset_t signals; + + /* The selected signal is returned here. The waiter also + futex_waits on this info.si_signo. */ + siginfo_t info; +}; + +/* This variable is protected by SIG_LOCK. */ +extern struct sigwaiter *sigwaiters; + +/* Block the caller waiting for a signal in set SET. SIG_LOCK and + SS->LOCK must be held and will be unlocked by this function before + blocking. */ +extern siginfo_t sigwaiter_block (struct signal_state *ss, + const sigset_t *restrict set); + +/* Unblock the waiter WAITER. SIG_LOCK and WAITER->SS->LOCK must be + held. Both will be dropped on return. */ +extern void sigwaiter_unblock (struct sigwaiter *waiter); + +enum sig_action { sig_core, sig_terminate, sig_ignore, sig_cont, sig_stop }; + +static inline enum sig_action +default_action (int signo) +{ + switch (signo) + { + case SIGABRT: + case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGQUIT: + case SIGSEGV: + case SIGSTKFLT: + case SIGSYS: + case SIGTRAP: + case SIGXCPU: + case SIGXFSZ: + return sig_core; + + case SIGALRM: + case SIGHUP: + case SIGINT: + case SIGIO: /* Perhaps ignore? */ + case SIGKILL: + case SIGPIPE: + case SIGPROF: + case SIGTERM: + case SIGUSR1: + case SIGUSR2: + case SIGVTALRM: + return sig_terminate; + + case SIGCHLD: + case SIGPWR: + case SIGURG: + case SIGWINCH: + return sig_ignore; + + case SIGCONT: + return sig_cont; + + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + return sig_stop; + } + + panic ("Unknown signal number: %d", signo); +} + +#endif diff --git a/signal/sigaction.c b/signal/sigaction.c new file mode 100644 index 00000000..0126c99d --- /dev/null +++ b/signal/sigaction.c @@ -0,0 +1,72 @@ +/* sigaction.c - Generic sigaction implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" +#include "pt-internal.h" + +int +sigaction (int sig, const struct sigaction *restrict sa, + struct sigaction *restrict osa) +{ + if (sig <= 0 || sig >= NSIG) + { + errno = EINVAL; + return -1; + } + + struct signal_state *ss = &_pthread_self ()->ss; + + pthread_mutex_lock (&ss->lock); + + if (osa) + *osa = ss->actions[sig - 1]; + + if (sa) + { + ss->actions[sig - 1] = *sa; + + /* "The SIGKILL and SIGSTOP signals shall not be added to the + signal mask using this mechanism; this restriction shall be + enforced by the system without causing an error to be + indicated" (sigaction). */ + sigdelset (&ss->blocked, SIGKILL); + sigdelset (&ss->blocked, SIGSTOP); + + /* A "signal shall remain pending on the process until it is + unblocked, it is accepted when ..., or the action associated + with it is set to ignore the signal" (2.4.1). + + "Setting a signal action to SIG_DFL for a signal that is + pending, and whose default action is to ignore the signal, + ..., shall cause the pending signal to be discarded, whether + or not it is blocked" (2.4.3). */ + if (sa->sa_handler == SIG_IGN + || (sa->sa_handler == SIG_DFL && default_action (sig) == sig_ignore)) + { + sigdelset (&ss->pending, sig); + sigdelset (&process_pending, sig); + } + } + + pthread_mutex_unlock (&ss->lock); + + return 0; +} + diff --git a/signal/sigaltstack.c b/signal/sigaltstack.c new file mode 100644 index 00000000..8334811a --- /dev/null +++ b/signal/sigaltstack.c @@ -0,0 +1,69 @@ +/* sigaltstack.c - Generic sigaltstack implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" +#include "pt-internal.h" + +int +sigaltstack (const stack_t *restrict stack, stack_t *restrict old) +{ + int err = 0; + struct signal_state *ss = &_pthread_self ()->ss; + + pthread_mutex_lock (&ss->lock); + + if (old) + *old = ss->stack; + + if (stack) + { + if (stack->ss_size < MINSIGSTKSZ) + { + err = ENOMEM; + goto out; + } + + if ((stack->ss_flags & ~(SS_DISABLE))) + /* Flags contains a value other than SS_DISABLE. */ + { + err = EINVAL; + goto out; + } + + if ((ss->stack.ss_flags & SS_ONSTACK)) + /* Stack in use. */ + { + err = EPERM; + goto out; + } + + ss->stack = *stack; + } + + out: + pthread_mutex_unlock (&ss->lock); + + if (err) + { + errno = err; + return -1; + } + return 0; +} diff --git a/signal/signal-dispatch.c b/signal/signal-dispatch.c new file mode 100644 index 00000000..40440b70 --- /dev/null +++ b/signal/signal-dispatch.c @@ -0,0 +1,117 @@ +/* signal-dispatch.c - Signal dispatcher. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +/* This is the signal handler entry point. A thread is forced into + this state when it receives a signal. We need to save the thread's + state and then invoke the high-level signal dispatcher. SS->LOCK + is locked by the caller. */ +void +signal_dispatch (struct signal_state *ss, siginfo_t *si) +{ + SIGNAL_DISPATCH_ENTRY; + + int signo = si->si_signo; + + assert (signo > 0 && signo < NSIG); + assert (pthread_mutex_trylock (&ss->lock) == EBUSY); + + do + { + if ((sigmask (signo) & STOPSIGS)) + /* Stop signals clear a pending SIGCONT even if they + are handled or ignored (but not if preempted). */ + { + sigdelset (&ss->pending, SIGCONT); + sigdelset (&process_pending, SIGCONT); + } + else if ((signo == SIGCONT)) + /* Even if handled or ignored (but not preempted), SIGCONT + clears stop signals and resumes the process. */ + { + ss->pending &= ~STOPSIGS; + process_pending &= ~STOPSIGS; + } + + void (*handler)(int, siginfo_t *, void *) + = ss->actions[signo - 1].sa_sigaction; + + /* Reset to SIG_DFL if requested. SIGILL and SIGTRAP cannot + be automatically reset when delivered; the system silently + enforces this restriction (sigaction). */ + if (ss->actions[signo - 1].sa_flags & SA_RESETHAND + && signo != SIGILL && signo != SIGTRAP) + ss->actions[signo - 1].sa_handler = SIG_DFL; + + sigset_t orig_blocked = ss->blocked; + /* Block requested signals while running the handler. */ + ss->blocked |= ss->actions[signo - 1].sa_mask; + + /* Block SIGNO unless we're asked not to. */ + if (! (ss->actions[signo - 1].sa_flags & (SA_RESETHAND | SA_NODEFER))) + sigaddset (&ss->blocked, signo); + + sigdelset (&ss->pending, signo); + pthread_mutex_unlock (&ss->lock); + + pthread_mutex_lock (&sig_lock); + sigdelset (&process_pending, signo); + pthread_mutex_unlock (&sig_lock); + + if (handler == (void *) SIG_DFL) + { + enum sig_action action = default_action (signo); + + if (action == sig_terminate || action == sig_core) + _exit (128 + signo); + + if (action == sig_stop) + /* XXX: Implement me. */ + panic ("Stopping process unimplemented."); + + if (action == sig_cont) + /* XXX: Implement me. */; + panic ("Continuing process unimplemented."); + } + else if (handler == (void *) SIG_IGN) + ; + else + handler (signo, si, NULL); + + pthread_mutex_lock (&ss->lock); + + /* "When a thread's signal mask is changed in a signal-catching + function that is installed by sigaction(), the restoration of + the signal mask on return from the signal-catching function + overrides that change (see sigaction())" (sigprocmask). */ + ss->blocked = orig_blocked; + + sigset_t pending = ~ss->blocked & ss->pending; + if (! pending) + pending = ~ss->blocked & process_pending; + signo = l4_lsb64 (pending); + } + while (signo); + + pthread_mutex_unlock (&ss->lock); + + SIGNAL_DISPATCH_EXIT; +} diff --git a/signal/signal.h b/signal/signal.h new file mode 100644 index 00000000..a33d995c --- /dev/null +++ b/signal/signal.h @@ -0,0 +1,275 @@ +/* signal.h - Signal handling interface. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SIGNAL_H +#define _SIGNAL_H 1 + +#include <stdint.h> +#include <sys/types.h> + +typedef volatile int sig_atomic_t; + +typedef uint64_t sigset_t; + +int sigaddset (sigset_t *, int); +int sigdelset (sigset_t *, int); +int sigemptyset (sigset_t *); +int sigfillset (sigset_t *); +int sigismember (const sigset_t *, int); + +/* These values are consistent with Linux. */ +#define SIGRTMIN 34 +#define SIGRTMAX 64 + +enum + { + SIGHUP = 1, +#define SIGHUP SIGHUP + SIGINT, +#define SIGINT SIGINT + SIGQUIT, +#define SIGQUIT SIGQUIT + SIGILL, +#define SIGILL SIGILL + SIGTRAP, +#define SIGTRAP SIGTRAP + SIGABRT, +#define SIGABRT SIGABRT + SIGBUS, +#define SIGBUS SIGBUS + SIGFPE, +#define SIGFPE SIGFPE + SIGKILL, +#define SIGKILL SIGKILL + SIGUSR1, +#define SIGUSR1 SIGUSR1 + SIGSEGV, +#define SIGSEGV SIGSEGV + SIGUSR2, +#define SIGUSR2 SIGUSR2 + SIGPIPE, +#define SIGPIPE SIGPIPE + SIGALRM, +#define SIGALRM SIGALRM + SIGTERM, +#define SIGTERM SIGTERM + SIGSTKFLT, +#define SIGSTKFLT SIGSTKFLT + SIGCHLD, +#define SIGCHLD SIGCHLD + SIGCONT, +#define SIGCONT SIGCONT + SIGSTOP, +#define SIGSTOP SIGSTOP + SIGTSTP, +#define SIGTSTP SIGTSTP + SIGTTIN, +#define SIGTTIN SIGTTIN + SIGTTOU, +#define SIGTTOU SIGTTOU + SIGURG, +#define SIGURG SIGURG + SIGXCPU, +#define SIGXCPU SIGXCPU + SIGXFSZ, +#define SIGXFSZ SIGXFSZ + SIGVTALRM, +#define SIGVTALRM SIGVTALRM + SIGPROF, +#define SIGPROF SIGPROF + SIGWINCH, +#define SIGWINCH SIGWINCH + SIGIO, +#define SIGIO SIGIO + SIGPWR, +#define SIGPWR SIGPWR + SIGSYS, +#define SIGSYS SIGSYS + NSIG + }; + +/* The resulting set is the union of the current set and the signal + set pointed to by the argument set. */ +#define SIG_BLOCK 1 +/* The resulting set is the intersection of the current set and the + complement of the signal set pointed to by the argument set. */ +#define SIG_UNBLOCK 2 +/* The resulting set is the signal set pointed to by the argument + set. */ +#define SIG_SETMASK 3 + +int pthread_sigmask (int how, const sigset_t *mask, sigset_t *old); +int sigprocmask (int how, const sigset_t *restrict mask, + sigset_t *restrict old); + +/* Return set of pending signals. */ +int sigpending(sigset_t *set); + +union sigval +{ + int sival_int; + void *sival_ptr; +}; + +#define SIG_DFL ((void (*)(int)) (0)) +#define SIG_ERR ((void (*)(int)) (-1)) +#define SIG_IGN ((void (*)(int)) (1)) + +/* Causes signal delivery to occur on an alternate stack. */ +#define SA_ONSTACK (1 << 0) +/* Do not generate SIGCHLD when children stop or stopped children + continue. */ +#define SA_NOCLDSTOP (1 << 1) +/* Causes signal dispositions to be set to SIG_DFL on entry to signal + handlers. */ +#define SA_RESETHAND (1 << 2) +/* Causes certain functions to become restartable. */ +#define SA_RESTART (1 << 3) +/* Causes extra information to be passed to signal handlers at the + time of receipt of a signal. */ +#define SA_SIGINFO (1 << 4) +/* Causes implementations not to create zombie processes on child + death. */ +#define SA_NOCLDWAIT (1 << 5) +/* Causes signal not to be automatically blocked on entry to + signal handler. */ +#define SA_NODEFER (1 << 6) + +typedef struct +{ + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + long si_band; + union sigval si_value; +} siginfo_t; + +struct sigaction +{ + union + { + /* Pointer to a signal-catching function or one of the macros + SIG_IGN or SIG_DFL. */ + void (*sa_handler)(int); + + /* Pointer to a signal-catching function. */ + void (*sa_sigaction)(int, siginfo_t *, void *); + }; + + /* Set of signals to be blocked during execution of the signal + handling function. */ + sigset_t sa_mask; + + /* Special flags. */ + int sa_flags; +}; + +int sigaction (int signo, const struct sigaction *restrict newaction, + struct sigaction *restrict oldaction); + +void (*signal (int signo, void (*handler)(int)))(int); +void (*bsd_signal (int signo, void (*handler)(int)))(int); + +/* Process is executing on an alternate signal stack. */ +#define SS_ONSTACK (1 << 0) +/* Alternate signal stack is disabled. */ +#define SS_DISABLE (1 << 1) + +/* Minimum stack size for a signal handler. */ +#define MINSIGSTKSZ PAGESIZE +/* Default size in bytes for the alternate signal stack. */ +#define SIGSTKSZ (16 * PAGESIZE) + +typedef struct +{ + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +int sigaltstack(const stack_t *restrict stack, stack_t *restrict old); + +#include <pthread.h> + +/* Send SIGNO to the process PID. */ +int kill(pid_t pid, int signo); + +/* Send SIGNO to the process group PG. */ +int killpg(pid_t pg, int signo); + +/* Send SIGNO to thread TID. */ +int pthread_kill(pthread_t tid, int signo); + +/* Send a signal to thread TID using SIGINFO. */ +int pthread_kill_siginfo_np (pthread_t tid, siginfo_t siginfo); + +/* Send SIGNO to the calling thread. */ +int raise(int signo); + +typedef struct sigevent +{ + /* Notification type. */ + int sigev_notify; + + /* Signal number. */ + int sigev_signo; + + /* Signal value. */ + union sigval sigev_value; + + /* Notification function. */ + void (*sigev_notify_function) (union sigval); + + /* Notification attributes. */ + pthread_attr_t *sigev_notify_attributes; +} sigevent_t; + +enum + { + SIGEV_NONE = 0, +#define SIGEV_NONE SIGEV_NONE + SIGEV_SIGNAL, +#define SIGEV_SIGNAL SIGEV_SIGNAL + SIGEV_THREAD +#define SIGEV_THREAD SIGEV_THREAD + }; + +#define SIG_HOLD + +int sighold (int); +int sigignore (int); +int siginterrupt (int, int); +int sigpause (int); +int sigqueue (pid_t, int, const union sigval); +int sigrelse (int); +void (*sigset (int, void (*)(int)))(int); +int sigsuspend (const sigset_t *); + +/* Wait for a signal. */ +int sigwait (const sigset_t *restrict set, int *restrict signo); +int sigwaitinfo (const sigset_t *restrict set, siginfo_t *restrict info); +int sigtimedwait (const sigset_t *restrict set, siginfo_t *restrict info, + const struct timespec *restrict timespec); + +#endif diff --git a/signal/sigpending.c b/signal/sigpending.c new file mode 100644 index 00000000..609b55d6 --- /dev/null +++ b/signal/sigpending.c @@ -0,0 +1,38 @@ +/* sigpending.c - Generic sigpending implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <sig-internal.h> +#include <pt-internal.h> + +int +sigpending (sigset_t *set) +{ + struct signal_state *ss = &_pthread_self ()->ss; + + pthread_mutex_lock (&ss->lock); + + /* There is no need to lock SIG_LOCK for process_pending since we + just read it, which is atomic. */ + *set = (ss->pending | process_pending) & ss->blocked; + + pthread_mutex_unlock (&ss->lock); + + return 0; +} diff --git a/signal/sigsuspend.c b/signal/sigsuspend.c new file mode 100644 index 00000000..73cf12a1 --- /dev/null +++ b/signal/sigsuspend.c @@ -0,0 +1,29 @@ +/* sigsuspend.c - Generic sigsuspend implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigsuspend (const sigset_t *set) +{ + /* XXX: Implement me. */ + errno = EOPNOTSUPP; + return -1; +} diff --git a/signal/sigtimedwait.c b/signal/sigtimedwait.c new file mode 100644 index 00000000..52cd0176 --- /dev/null +++ b/signal/sigtimedwait.c @@ -0,0 +1,30 @@ +/* sigtimedwait.c - Generic sigtimedwait implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigtimedwait (const sigset_t *restrict set, siginfo_t *restrict info, + const struct timespec *restrict timeout) +{ + errno = EOPNOTSUPP; + return -1; +} + diff --git a/signal/sigwaiter.c b/signal/sigwaiter.c new file mode 100644 index 00000000..8d041ac1 --- /dev/null +++ b/signal/sigwaiter.c @@ -0,0 +1,91 @@ +/* sigwaiter.c - Signal handling functions. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +#include <hurd/futex.h> + +struct sigwaiter *sigwaiters; + +siginfo_t +sigwaiter_block (struct signal_state *ss, const sigset_t *restrict set) +{ + assert (pthread_mutex_trylock (&sig_lock) == EBUSY); + assert (pthread_mutex_trylock (&ss->lock) == EBUSY); + + assert (! ss->sigwaiter); + + struct sigwaiter waiter; + + waiter.next = sigwaiters; + if (waiter.next) + { + assert (! waiter.next->prev); + waiter.next->prev = &waiter; + } + waiter.prev = 0; + sigwaiters = &waiter; + + waiter.ss = ss; + waiter.info.si_signo = 0; + waiter.signals = *set; + + ss->sigwaiter = &waiter; + + pthread_mutex_unlock (&ss->lock); + pthread_mutex_unlock (&sig_lock); + + futex_wait (&waiter.info.si_signo, 0); + +#ifndef NDEBUG + pthread_mutex_lock (&ss->lock); + ss->sigwaiter = 0; + pthread_mutex_unlock (&ss->lock); +#endif + + assert (waiter.info.si_signo); + return waiter.info; +} + +void +sigwaiter_unblock (struct sigwaiter *waiter) +{ + assert (pthread_mutex_trylock (&sig_lock) == EBUSY); + assert (pthread_mutex_trylock (&waiter->ss->lock) == EBUSY); + + struct sigwaiter *prev = waiter->prev; + struct sigwaiter *next = waiter->next; + + if (next) + next->prev = prev; + + if (prev) + prev->next = next; + else + sigwaiters = next; + + sigdelset (&process_pending, waiter->info.si_signo); + sigdelset (&waiter->ss->pending, waiter->info.si_signo); + + pthread_mutex_unlock (&waiter->ss->lock); + pthread_mutex_unlock (&sig_lock); + + futex_wake (&waiter->info.si_signo, 1); +} diff --git a/signal/sigwaitinfo.c b/signal/sigwaitinfo.c new file mode 100644 index 00000000..1b47079e --- /dev/null +++ b/signal/sigwaitinfo.c @@ -0,0 +1,74 @@ +/* sigwaitinfo.c - Generic sigwaitinfo implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <sig-internal.h> +#include <pt-internal.h> + +int +sigwaitinfo (const sigset_t *restrict set, siginfo_t *restrict info) +{ + pthread_mutex_lock (&sig_lock); + + struct signal_state *ss = &_pthread_self ()->ss; + + pthread_mutex_lock (&ss->lock); + + if ((process_pending & *set) || (ss->pending & *set)) + /* There is at least one signal pending. */ + { + bool local = true; + sigset_t extant = process_pending & *set; + if (! extant) + { + local = false; + extant = ss->pending & *set; + } + + assert (extant); + + int signo = l4_msb64 (extant); + + if (info) + { + if (local) + *info = ss->info[signo - 1]; + else + *info = process_pending_info[signo - 1]; + info->si_signo = signo; + } + + sigdelset (&process_pending, signo); + sigdelset (&ss->pending, signo); + + pthread_mutex_unlock (&ss->lock); + pthread_mutex_unlock (&sig_lock); + return 0; + } + + siginfo_t i = sigwaiter_block (ss, set); + assert (i.si_signo); + assert ((sigmask (i.si_signo) & *set)); + + if (info) + *info = i; + + return 0; +} + diff --git a/sysdeps/generic/killpg.c b/sysdeps/generic/killpg.c new file mode 100644 index 00000000..7f7ed87d --- /dev/null +++ b/sysdeps/generic/killpg.c @@ -0,0 +1,27 @@ +/* killpg.c - Generic killpg implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +killpg (pid_t pid, int sig) +{ + return kill (-pid, sig); +} diff --git a/sysdeps/generic/pt-kill.c b/sysdeps/generic/pt-kill.c new file mode 100644 index 00000000..0dfac344 --- /dev/null +++ b/sysdeps/generic/pt-kill.c @@ -0,0 +1,32 @@ +/* pthread-kill.c - Generic pthread-kill implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +pthread_kill (pthread_t tid, int signo) +{ + siginfo_t si; + memset (&si, 0, sizeof (si)); + si.si_signo = signo; + + return pthread_kill_siginfo_np (tid, si); +} + diff --git a/sysdeps/generic/pt-mutex-transfer-np.c b/sysdeps/generic/pt-mutex-transfer-np.c new file mode 100644 index 00000000..bcb809dd --- /dev/null +++ b/sysdeps/generic/pt-mutex-transfer-np.c @@ -0,0 +1,54 @@ +/* Transfer ownership of a mutex. Generic version. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <assert.h> + +#include <pt-internal.h> + +int +__pthread_mutex_transfer_np (struct __pthread_mutex *mutex, pthread_t tid) +{ + assert (mutex->owner == _pthread_self ()); + + struct __pthread *thread = __pthread_getid (tid); + if (! thread) + return ESRCH; + + if (thread == _pthread_self ()) + return 0; + + if (mutex->attr && mutex->attr->mutex_type == PTHREAD_MUTEX_ERRORCHECK) + { + + if (mutex->owner != _pthread_self ()) + return EPERM; + + mutex->owner = thread; + } + +#ifndef NDEBUG + mutex->owner = thread; +#endif + + return 0; +} + +strong_alias (__pthread_mutex_transfer_np, pthread_mutex_transfer_np) diff --git a/sysdeps/generic/raise.c b/sysdeps/generic/raise.c new file mode 100644 index 00000000..410f557d --- /dev/null +++ b/sysdeps/generic/raise.c @@ -0,0 +1,41 @@ +/* raise.c - Generic raise implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +raise (int signo) +{ + /* According to POSIX, if we implement threads (and we do), then + "the effect of the raise() function shall be equivalent to + calling: pthread_kill(pthread_self(), sig);" */ + +debug (0, ""); + int err = pthread_kill (pthread_self (), signo); +debug (0, ""); + if (err) + { + errno = err; + return -1; + } + + return 0; +} + diff --git a/sysdeps/generic/sigaddset.c b/sysdeps/generic/sigaddset.c new file mode 100644 index 00000000..14edb71c --- /dev/null +++ b/sysdeps/generic/sigaddset.c @@ -0,0 +1,35 @@ +/* sigaddset.c - Generic sigaddset implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigaddset (sigset_t *sigset, int signo) +{ + if (signo <= 0 || signo >= NSIG) + { + errno = EINVAL; + return -1; + } + + *sigset |= sigmask (signo); + return 0; +} + diff --git a/sysdeps/generic/sigdelset.c b/sysdeps/generic/sigdelset.c new file mode 100644 index 00000000..5456467f --- /dev/null +++ b/sysdeps/generic/sigdelset.c @@ -0,0 +1,35 @@ +/* sigdelset.c - Generic sigdelset implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigdelset (sigset_t *sigset, int signo) +{ + if (signo <= 0 || signo >= NSIG) + { + errno = EINVAL; + return -1; + } + + *sigset &= ~sigmask (signo); + return 0; +} + diff --git a/sysdeps/generic/sigemptyset.c b/sysdeps/generic/sigemptyset.c new file mode 100644 index 00000000..690c15b6 --- /dev/null +++ b/sysdeps/generic/sigemptyset.c @@ -0,0 +1,29 @@ +/* sigemptyset.c - Generic sigemptyset implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> + +int +sigemptyset (sigset_t *sigset) +{ + *sigset = 0; + return 0; +} + diff --git a/sysdeps/generic/sigfillset.c b/sysdeps/generic/sigfillset.c new file mode 100644 index 00000000..f0ac0781 --- /dev/null +++ b/sysdeps/generic/sigfillset.c @@ -0,0 +1,29 @@ +/* sigfillset.c - Generic sigfillset implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> + +int +sigfillset (sigset_t *sigset) +{ + *sigset = (1ULL << (NSIG - 1)) - 1; + return 0; +} + diff --git a/sysdeps/generic/siginterrupt.c b/sysdeps/generic/siginterrupt.c new file mode 100644 index 00000000..0899efbb --- /dev/null +++ b/sysdeps/generic/siginterrupt.c @@ -0,0 +1,36 @@ +/* siginterrupt.c - Generic siginterrupt implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +siginterrupt (int sig, int flag) +{ + int ret; + struct sigaction act; + + sigaction (sig, NULL, &act); + if (flag) + act.sa_flags &= ~SA_RESTART; + else + act.sa_flags |= SA_RESTART; + ret = sigaction(sig, &act, NULL); + return ret; +} diff --git a/sysdeps/generic/sigismember.c b/sysdeps/generic/sigismember.c new file mode 100644 index 00000000..b3d65c97 --- /dev/null +++ b/sysdeps/generic/sigismember.c @@ -0,0 +1,36 @@ +/* sigismember.c - Generic sigismember implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigismember (const sigset_t *sigset, int signo) +{ + if (signo <= 0 || signo >= NSIG) + { + errno = EINVAL; + return -1; + } + + if (*sigset & sigmask (signo)) + return 1; + else + return 0; +} diff --git a/sysdeps/generic/signal.c b/sysdeps/generic/signal.c new file mode 100644 index 00000000..7555d0a1 --- /dev/null +++ b/sysdeps/generic/signal.c @@ -0,0 +1,44 @@ +/* signal.c - Generic signal implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +void (*signal (int sig, void (*handler)(int)))(int) +{ + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = SA_RESTART; + + if (sigemptyset (&sa.sa_mask) < 0 + || sigaddset (&sa.sa_mask, sig) < 0) + return SIG_ERR; + + struct sigaction osa; + if (sigaction (sig, &sa, &osa) < 0) + return SIG_ERR; + + return osa.sa_handler; +} + +void (*bsd_signal (int sig, void (*func)(int)))(int) +{ + return signal (sig, func); +} diff --git a/sysdeps/generic/sigwait.c b/sysdeps/generic/sigwait.c new file mode 100644 index 00000000..7d10bf8b --- /dev/null +++ b/sysdeps/generic/sigwait.c @@ -0,0 +1,34 @@ +/* sigwait.c - Generic sigwait implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "sig-internal.h" + +int +sigwait (const sigset_t *restrict set, int *restrict signo) +{ + siginfo_t info; + + if (sigwaitinfo (set, &info) < 0) + return -1; + + *signo = info.si_signo; + return 0; +} + diff --git a/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c b/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c new file mode 100644 index 00000000..bb6ac2a5 --- /dev/null +++ b/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c @@ -0,0 +1,213 @@ +/* signal-dispatch-lowlevel.c - ia32 specific signal handling functions. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <pt-internal.h> +#include <sig-internal.h> + +#include <hurd/thread.h> +#include <pthread.h> +#include <stdint.h> +#include <atomic.h> + +extern char _signal_dispatch_entry; +/* - 0(%esp) a pointer to the thread's struct signal_state. + - 4(%esp) a pointer to a siginfo_t. + - 8(%esp) is a pointer to the ss_flags field (or NULL). + - 12(%esp)+4 is the value of the sp when the thread was interrupted (intr_sp) + - 0(intr_sp) is the value of the ip when the thread was interrupted. + - 16(%esp) - 16 byte register save area +*/ +__asm__ ("\n\ + .globl _signal_dispatch_entry\n\ +_signal_dispatch_entry:\n\ + /* Save caller saved registers (16 bytes). */\n\ + mov %eax, 16(%esp)\n\ + mov %ecx, 16+4(%esp)\n\ + mov %edx, 16+8(%esp)\n\ + pushf\n\ + popl %eax\n\ + mov %eax, 16+12(%esp)\n\ +\n\ + /* Reset EFLAGS. */\n\ + cld\n\ + call signal_dispatch\n\ +\n\ + /* Get the original stack and begin restoration. */\n\ + mov 12(%esp), %edx\n\ +\n\ + /* Move the saved registers to the user stack. */\n\ + sub $16, %edx\n\ + /* eax. */\n\ + mov 16+0(%esp), %ecx\n\ + mov %ecx, 0(%edx)\n\ + /* ecx. */\n\ + mov 16+4(%esp), %ecx\n\ + mov %ecx, 4(%edx)\n\ + /* edx. */\n\ + mov 16+8(%esp), %ecx\n\ + mov %ecx, 8(%edx)\n\ + /* eflags. */\n\ + mov 16+12(%esp), %ecx\n\ + mov %ecx, 12(%edx)\n\ +\n\ + /* Get the pointer to the sigaltstack flags. */\n\ + mov 8(%esp), %ecx\n\ +\n\ + /* Restore the user stack. */\n\ + mov %edx, %esp\n\ +\n\ + /* Clear the SA_ONSTACK flag. */\n\ + and %ecx, %ecx\n\ + jz after_clear\n\ + lock; and $~1, 0(%ecx)\n\ +after_clear:\n\ +\n\ + /* Restore eflags, the scratch regs and the original sp and ip. */\n\ + popl %eax\n\ + popl %ecx\n\ + popl %edx\n\ + popf\n\ + ret\n"); + +extern char _signal_dispatch_entry_self; +/* - 0(%esp) is the return address (we ignore it) + - 4(%esp) is the sp to load + + Since we are returning to signal_dispatch_lowlevel's caller, we + also need to restore its frame pointer. */ +__asm__ ("\n\ + .globl _signal_dispatch_entry_self\n\ +_signal_dispatch_entry_self:\n\ + mov 0(%ebp), %ebp\n\ + mov 4(%esp), %esp\n\ + jmp _signal_dispatch_entry\n"); + +void +signal_dispatch_lowlevel (struct signal_state *ss, pthread_t tid, + siginfo_t si) +{ + assert (pthread_mutex_trylock (&ss->lock) == EBUSY); + + struct __pthread *thread = __pthread_getid (tid); + + bool self = tid == pthread_self (); + + uintptr_t intr_sp; + + if (self) + { + /* The return address is just before the first argument. */ + intr_sp = (uintptr_t) &ss - 4; + assert (* (void **) intr_sp == __builtin_return_address (0)); + } + else + { + struct hurd_thread_exregs_in in; + memset (&in, 0, sizeof (in)); + struct hurd_thread_exregs_out out; + + error_t err; + err = rm_thread_exregs (ADDR_VOID, thread->object.addr, + HURD_EXREGS_STOP | HURD_EXREGS_ABORT_IPC + | HURD_EXREGS_GET_REGS, + in, &out); + if (err) + panic ("Failed to modify thread " ADDR_FMT, + ADDR_PRINTF (thread->object.addr)); + + intr_sp = out.sp; + + /* Push the ip on the user stack. */ + intr_sp -= 4; + * (uintptr_t *) intr_sp = out.ip; + } + + bool altstack = false; + uintptr_t sp; + if (! (ss->actions[si.si_signo - 1].sa_flags & SA_ONSTACK) + || (ss->stack.ss_flags & SS_DISABLE) + || (ss->stack.ss_flags & SS_ONSTACK)) + { + assert (! self); + sp = intr_sp; + } + else + { + /* The stack grows down. */ + sp = (uintptr_t) ss->stack.ss_sp + ss->stack.ss_size; + + /* We know intimately that SS_ONSTACK is the least significant + bit. */ + assert (SS_ONSTACK == 1); + atomic_bit_set (&ss->stack.ss_flags, 0); + + altstack = true; + } + + /* Set up the call frame for a call to signal_dispatch_entry. */ + + /* Allocate a siginfo structure on the stack. */ + sp = sp - sizeof (siginfo_t); + siginfo_t *sip = (void *) sp; + /* Copy the user supplied values. */ + *sip = si; + + /* Add space for the 4 caller saved registers. */ + sp -= 4 * sizeof (uintptr_t); + + /* Save the interrupted sp. */ + sp -= 4; + * (uintptr_t *) sp = intr_sp; + + /* Address of the ss_flags. */ + sp -= 4; + if (altstack) + * (uintptr_t *) sp = (uintptr_t) &ss->stack.ss_flags; + else + * (uintptr_t *) sp = 0; + + /* Push the parameters to signal_dispatch. */ + + /* signal info structure. */ + sp -= 4; + * (uintptr_t *) sp = (uintptr_t) sip; + + /* The ss. */ + sp -= 4; + * (uintptr_t *) sp = (uintptr_t) ss; + + pthread_mutex_transfer_np (&ss->lock, tid); + + if (self) + ((void (*) (uintptr_t)) &_signal_dispatch_entry_self) ((uintptr_t) sp); + else + { + struct hurd_thread_exregs_in in; + struct hurd_thread_exregs_out out; + + in.sp = sp; + in.ip = (uintptr_t) &_signal_dispatch_entry; + + rm_thread_exregs (ADDR_VOID, thread->object.addr, + HURD_EXREGS_SET_SP_IP + | HURD_EXREGS_START | HURD_EXREGS_ABORT_IPC, + in, &out); + } +} diff --git a/sysdeps/l4/hurd/pt-sigstate-init.c b/sysdeps/l4/hurd/pt-sigstate-init.c index 25a3920c..4c40fdb3 100644 --- a/sysdeps/l4/hurd/pt-sigstate-init.c +++ b/sysdeps/l4/hurd/pt-sigstate-init.c @@ -1,5 +1,5 @@ /* Initialize the signal state. Hurd on L4 version. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2008 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 @@ -20,9 +20,25 @@ #include <pthread.h> #include <pt-internal.h> +#include <sig-internal.h> error_t __pthread_sigstate_init (struct __pthread *thread) { + struct signal_state *ss = &thread->ss; + + memset (ss, 0, sizeof (*ss)); + + ss->stack.ss_flags = SS_DISABLE; + + int signo; + for (signo = 1; signo < NSIG; ++signo) + { + sigemptyset (&ss->actions[signo - 1].sa_mask); + ss->actions[signo - 1].sa_flags = SA_RESTART; + ss->actions[signo - 1].sa_handler = SIG_DFL; + ss->lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + } + return 0; } diff --git a/sysdeps/l4/hurd/pt-sigstate.c b/sysdeps/l4/hurd/pt-sigstate.c index 8ab80347..66dd08cf 100644 --- a/sysdeps/l4/hurd/pt-sigstate.c +++ b/sysdeps/l4/hurd/pt-sigstate.c @@ -1,5 +1,5 @@ /* Set a thread's signal state. Hurd on L4 version. - Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2008 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 @@ -28,6 +28,54 @@ __pthread_sigstate (struct __pthread *thread, int how, const sigset_t *set, sigset_t *oset, int clear_pending) { - /* FIXME: Do the right thing here. */ + struct signal_state *ss = &thread->ss; + pthread_mutex_lock (&ss->lock); + + if (oset) + *oset = ss->blocked; + + if (set) + { + /* Mask out SIGKILL and SIGSTOP. */ + sigset_t s = *set; + sigdelset (&s, SIGKILL); + sigdelset (&s, SIGSTOP); + + switch (how) + { + case SIG_BLOCK: + ss->blocked |= s; + break; + case SIG_UNBLOCK: + ss->blocked &= ~s; + break; + case SIG_SETMASK: + ss->blocked = s; + break; + default: + errno = EINVAL; + pthread_mutex_unlock (&ss->lock); + return -1; + } + } + + if (clear_pending) + sigemptyset (&ss->pending); + + /* A "signal shall remain pending until it is unblocked" (2.4.1). + + "If there are any pending unblocked signals after the call to + sigprocmask(), at least one of those signals shall be delivered + before the call to sigprocmask() returns." + (pthread_sigmask). */ + sigset_t extant = ~ss->blocked & ss->pending; + if (! extant) + extant = ~ss->blocked & process_pending; + + pthread_mutex_unlock (&ss->lock); + + if (extant) + raise (l4_lsb64 (extant)); + return 0; } diff --git a/sysdeps/l4/hurd/pt-sysdep.c b/sysdeps/l4/hurd/pt-sysdep.c index 604f5bf2..c23364c7 100644 --- a/sysdeps/l4/hurd/pt-sysdep.c +++ b/sysdeps/l4/hurd/pt-sysdep.c @@ -1,5 +1,5 @@ /* System dependent pthreads code. Hurd version. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2008 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 @@ -30,13 +30,6 @@ sched_yield (void) return 0; } -int -sigprocmask (int HOW, const sigset_t *restrict SET, sigset_t *restrict OLDSET) -{ - /* Just ignore for now. */ - return 0; -} - /* Forward. */ static void init_routine (void (*) (void *), void *) __attribute__ ((noreturn)); diff --git a/sysdeps/l4/hurd/sig-sysdep.h b/sysdeps/l4/hurd/sig-sysdep.h new file mode 100644 index 00000000..33e13857 --- /dev/null +++ b/sysdeps/l4/hurd/sig-sysdep.h @@ -0,0 +1,69 @@ +/* sig-sysdep.h - Hurd system specific header file. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <l4.h> +#include <string.h> + +struct utcb +{ + l4_word_t saved_sender; + l4_word_t saved_receiver; + l4_word_t saved_timeout; + l4_word_t saved_error_code; + l4_word_t saved_flags; + l4_word_t saved_br0; + l4_msg_t saved_message; +}; + +static inline void +utcb_state_save (struct utcb *buffer) +{ + l4_word_t *utcb = _L4_utcb (); + + buffer->saved_sender = utcb[_L4_UTCB_SENDER]; + buffer->saved_receiver = utcb[_L4_UTCB_RECEIVER]; + buffer->saved_timeout = utcb[_L4_UTCB_TIMEOUT]; + buffer->saved_error_code = utcb[_L4_UTCB_ERROR_CODE]; + buffer->saved_flags = utcb[_L4_UTCB_FLAGS]; + buffer->saved_br0 = utcb[_L4_UTCB_BR0]; + memcpy (&buffer->saved_message, + utcb, L4_NUM_MRS * sizeof (l4_word_t)); +} + +static inline void +utcb_state_restore (struct utcb *buffer) +{ + l4_word_t *utcb = _L4_utcb (); + + utcb[_L4_UTCB_SENDER] = buffer->saved_sender; + utcb[_L4_UTCB_RECEIVER] = buffer->saved_receiver; + utcb[_L4_UTCB_TIMEOUT] = buffer->saved_timeout; + utcb[_L4_UTCB_ERROR_CODE] = buffer->saved_error_code; + utcb[_L4_UTCB_FLAGS] = buffer->saved_flags; + utcb[_L4_UTCB_BR0] = buffer->saved_br0; + memcpy (utcb, &buffer->saved_message, + L4_NUM_MRS * sizeof (l4_word_t)); +} + +#define SIGNAL_DISPATCH_ENTRY \ + struct utcb buffer; utcb_state_save (&buffer); + +#define SIGNAL_DISPATCH_EXIT \ + utcb_state_restore (&buffer); diff --git a/sysdeps/l4/hurd/sigprocmask.c b/sysdeps/l4/hurd/sigprocmask.c new file mode 100644 index 00000000..a38b3795 --- /dev/null +++ b/sysdeps/l4/hurd/sigprocmask.c @@ -0,0 +1,41 @@ +/* sigprocmask.c - Generic sigprocmask implementation. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Neal H. Walfield <neal@gnu.org>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 3 of + the License, or (at your option) any later version. + + The GNU Hurd 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 this program. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <pt-internal.h> +#include <sig-internal.h> + +int +sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict old) +{ + struct __pthread *thread = _pthread_self (); + if (! thread) + /* Library is initializing. */ + { + assert (__pthread_num_threads == 1); + + /* We should get the default mask from the startup data structure. */ + if (old) + *old = 0; + + return 0; + } + + return pthread_sigmask (how, set, old); +} |