summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@gnu.org>2008-03-01 13:07:25 +0000
committerThomas Schwinge <tschwinge@gnu.org>2009-04-07 23:15:17 +0200
commit16de69f4d41a3105a3e14720f9ec81efaae5a78e (patch)
treed4b2afe3fbb1df6bb1eb2c8126d9cf924c75df65
parent57f2488654f1407bb6f00a9551a799643b87c903 (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.
-rw-r--r--Makefile.am33
-rw-r--r--headers.m41
-rw-r--r--pthread/pt-internal.h8
-rw-r--r--pthread/pt-self.c7
-rw-r--r--signal/README4
-rw-r--r--signal/TODO29
-rw-r--r--signal/kill.c70
-rw-r--r--signal/pt-kill-siginfo-np.c88
-rw-r--r--signal/sig-internal.c26
-rw-r--r--signal/sig-internal.h177
-rw-r--r--signal/sigaction.c72
-rw-r--r--signal/sigaltstack.c69
-rw-r--r--signal/signal-dispatch.c117
-rw-r--r--signal/signal.h275
-rw-r--r--signal/sigpending.c38
-rw-r--r--signal/sigsuspend.c29
-rw-r--r--signal/sigtimedwait.c30
-rw-r--r--signal/sigwaiter.c91
-rw-r--r--signal/sigwaitinfo.c74
-rw-r--r--sysdeps/generic/killpg.c27
-rw-r--r--sysdeps/generic/pt-kill.c32
-rw-r--r--sysdeps/generic/pt-mutex-transfer-np.c54
-rw-r--r--sysdeps/generic/raise.c41
-rw-r--r--sysdeps/generic/sigaddset.c35
-rw-r--r--sysdeps/generic/sigdelset.c35
-rw-r--r--sysdeps/generic/sigemptyset.c29
-rw-r--r--sysdeps/generic/sigfillset.c29
-rw-r--r--sysdeps/generic/siginterrupt.c36
-rw-r--r--sysdeps/generic/sigismember.c36
-rw-r--r--sysdeps/generic/signal.c44
-rw-r--r--sysdeps/generic/sigwait.c34
-rw-r--r--sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c213
-rw-r--r--sysdeps/l4/hurd/pt-sigstate-init.c18
-rw-r--r--sysdeps/l4/hurd/pt-sigstate.c52
-rw-r--r--sysdeps/l4/hurd/pt-sysdep.c9
-rw-r--r--sysdeps/l4/hurd/sig-sysdep.h69
-rw-r--r--sysdeps/l4/hurd/sigprocmask.c41
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
diff --git a/headers.m4 b/headers.m4
index 3c907880..c04d3502 100644
--- a/headers.m4
+++ b/headers.m4
@@ -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);
+}