From 16de69f4d41a3105a3e14720f9ec81efaae5a78e Mon Sep 17 00:00:00 2001
From: "Neal H. Walfield" <neal@gnu.org>
Date: Sat, 1 Mar 2008 13:07:25 +0000
Subject: 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.
---
 Makefile.am                                     |  33 ++-
 headers.m4                                      |   1 +
 pthread/pt-internal.h                           |   8 +
 pthread/pt-self.c                               |   7 +-
 signal/README                                   |   4 +
 signal/TODO                                     |  29 +++
 signal/kill.c                                   |  70 ++++++
 signal/pt-kill-siginfo-np.c                     |  88 ++++++++
 signal/sig-internal.c                           |  26 +++
 signal/sig-internal.h                           | 177 +++++++++++++++
 signal/sigaction.c                              |  72 +++++++
 signal/sigaltstack.c                            |  69 ++++++
 signal/signal-dispatch.c                        | 117 ++++++++++
 signal/signal.h                                 | 275 ++++++++++++++++++++++++
 signal/sigpending.c                             |  38 ++++
 signal/sigsuspend.c                             |  29 +++
 signal/sigtimedwait.c                           |  30 +++
 signal/sigwaiter.c                              |  91 ++++++++
 signal/sigwaitinfo.c                            |  74 +++++++
 sysdeps/generic/killpg.c                        |  27 +++
 sysdeps/generic/pt-kill.c                       |  32 +++
 sysdeps/generic/pt-mutex-transfer-np.c          |  54 +++++
 sysdeps/generic/raise.c                         |  41 ++++
 sysdeps/generic/sigaddset.c                     |  35 +++
 sysdeps/generic/sigdelset.c                     |  35 +++
 sysdeps/generic/sigemptyset.c                   |  29 +++
 sysdeps/generic/sigfillset.c                    |  29 +++
 sysdeps/generic/siginterrupt.c                  |  36 ++++
 sysdeps/generic/sigismember.c                   |  36 ++++
 sysdeps/generic/signal.c                        |  44 ++++
 sysdeps/generic/sigwait.c                       |  34 +++
 sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c | 213 ++++++++++++++++++
 sysdeps/l4/hurd/pt-sigstate-init.c              |  18 +-
 sysdeps/l4/hurd/pt-sigstate.c                   |  52 ++++-
 sysdeps/l4/hurd/pt-sysdep.c                     |   9 +-
 sysdeps/l4/hurd/sig-sysdep.h                    |  69 ++++++
 sysdeps/l4/hurd/sigprocmask.c                   |  41 ++++
 37 files changed, 2057 insertions(+), 15 deletions(-)
 create mode 100644 signal/README
 create mode 100644 signal/TODO
 create mode 100644 signal/kill.c
 create mode 100644 signal/pt-kill-siginfo-np.c
 create mode 100644 signal/sig-internal.c
 create mode 100644 signal/sig-internal.h
 create mode 100644 signal/sigaction.c
 create mode 100644 signal/sigaltstack.c
 create mode 100644 signal/signal-dispatch.c
 create mode 100644 signal/signal.h
 create mode 100644 signal/sigpending.c
 create mode 100644 signal/sigsuspend.c
 create mode 100644 signal/sigtimedwait.c
 create mode 100644 signal/sigwaiter.c
 create mode 100644 signal/sigwaitinfo.c
 create mode 100644 sysdeps/generic/killpg.c
 create mode 100644 sysdeps/generic/pt-kill.c
 create mode 100644 sysdeps/generic/pt-mutex-transfer-np.c
 create mode 100644 sysdeps/generic/raise.c
 create mode 100644 sysdeps/generic/sigaddset.c
 create mode 100644 sysdeps/generic/sigdelset.c
 create mode 100644 sysdeps/generic/sigemptyset.c
 create mode 100644 sysdeps/generic/sigfillset.c
 create mode 100644 sysdeps/generic/siginterrupt.c
 create mode 100644 sysdeps/generic/sigismember.c
 create mode 100644 sysdeps/generic/signal.c
 create mode 100644 sysdeps/generic/sigwait.c
 create mode 100644 sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c
 create mode 100644 sysdeps/l4/hurd/sig-sysdep.h
 create mode 100644 sysdeps/l4/hurd/sigprocmask.c

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);
+}
-- 
cgit v1.2.3