summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore1
-rw-r--r--libpthread/ChangeLog6
-rw-r--r--libpthread/Makefile249
-rw-r--r--libpthread/Makefile.am168
-rw-r--r--libpthread/TODO177
-rw-r--r--libpthread/headers.m445
-rw-r--r--libpthread/include/libc-symbols.h395
-rw-r--r--libpthread/include/pthread.h7
-rw-r--r--libpthread/include/pthread/pthread.h755
-rw-r--r--libpthread/include/pthread/pthreadtypes.h125
-rw-r--r--libpthread/include/semaphore.h69
-rw-r--r--libpthread/include/set-hooks.h72
-rw-r--r--libpthread/libpthread.a20
-rw-r--r--libpthread/libpthread_pic.a20
-rw-r--r--libpthread/lockfile.c65
-rw-r--r--libpthread/not-in-libc.h11
-rw-r--r--libpthread/pt-yield.c26
-rw-r--r--libpthread/pthread/Versions15
-rw-r--r--libpthread/pthread/cthreads-compat.c104
-rw-r--r--libpthread/pthread/pt-alloc.c215
-rw-r--r--libpthread/pthread/pt-cancel.c40
-rw-r--r--libpthread/pthread/pt-cleanup.c28
-rw-r--r--libpthread/pthread/pt-create.c217
-rw-r--r--libpthread/pthread/pt-dealloc.c64
-rw-r--r--libpthread/pthread/pt-detach.c92
-rw-r--r--libpthread/pthread/pt-exit.c122
-rw-r--r--libpthread/pthread/pt-getattr.c49
-rw-r--r--libpthread/pthread/pt-initialize.c33
-rw-r--r--libpthread/pthread/pt-internal.h317
-rw-r--r--libpthread/pthread/pt-join.c88
-rw-r--r--libpthread/pthread/pt-self.c32
-rw-r--r--libpthread/pthread/pt-setcancelstate.c43
-rw-r--r--libpthread/pthread/pt-setcanceltype.c43
-rw-r--r--libpthread/pthread/pt-sigmask.c33
-rw-r--r--libpthread/pthread/pt-spin-inlines.c34
-rw-r--r--libpthread/pthread/pt-testcancel.c31
-rw-r--r--libpthread/signal/README4
-rw-r--r--libpthread/signal/TODO29
-rw-r--r--libpthread/signal/kill.c70
-rw-r--r--libpthread/signal/pt-kill-siginfo-np.c88
-rw-r--r--libpthread/signal/sig-internal.c26
-rw-r--r--libpthread/signal/sig-internal.h177
-rw-r--r--libpthread/signal/sigaction.c72
-rw-r--r--libpthread/signal/sigaltstack.c69
-rw-r--r--libpthread/signal/signal-dispatch.c117
-rw-r--r--libpthread/signal/signal.h275
-rw-r--r--libpthread/signal/sigpending.c38
-rw-r--r--libpthread/signal/sigsuspend.c29
-rw-r--r--libpthread/signal/sigtimedwait.c30
-rw-r--r--libpthread/signal/sigwaiter.c91
-rw-r--r--libpthread/signal/sigwaitinfo.c74
-rw-r--r--libpthread/sysdeps/generic/bits/barrier-attr.h32
-rw-r--r--libpthread/sysdeps/generic/bits/barrier.h39
-rw-r--r--libpthread/sysdeps/generic/bits/cancelation.h51
-rw-r--r--libpthread/sysdeps/generic/bits/condition-attr.h34
-rw-r--r--libpthread/sysdeps/generic/bits/condition.h39
-rw-r--r--libpthread/sysdeps/generic/bits/mutex-attr.h41
-rw-r--r--libpthread/sysdeps/generic/bits/mutex.h75
-rw-r--r--libpthread/sysdeps/generic/bits/once.h34
-rw-r--r--libpthread/sysdeps/generic/bits/pthread-np.h27
-rw-r--r--libpthread/sysdeps/generic/bits/pthread.h38
-rw-r--r--libpthread/sysdeps/generic/bits/pthreadtypes.h29
-rw-r--r--libpthread/sysdeps/generic/bits/rwlock-attr.h32
-rw-r--r--libpthread/sysdeps/generic/bits/rwlock.h46
-rw-r--r--libpthread/sysdeps/generic/bits/semaphore.h43
-rw-r--r--libpthread/sysdeps/generic/bits/thread-attr.h44
-rw-r--r--libpthread/sysdeps/generic/bits/thread-specific.h25
-rw-r--r--libpthread/sysdeps/generic/killpg.c27
-rw-r--r--libpthread/sysdeps/generic/pt-atfork.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getdetachstate.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getguardsize.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getinheritsched.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getschedparam.c32
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getschedpolicy.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getscope.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getstack.c31
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getstackaddr.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-getstacksize.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-init.c28
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setdetachstate.c38
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setguardsize.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setinheritsched.c38
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setschedparam.c38
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setschedpolicy.c42
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setscope.c41
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setstack.c51
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setstackaddr.c29
-rw-r--r--libpthread/sysdeps/generic/pt-attr-setstacksize.c41
-rw-r--r--libpthread/sysdeps/generic/pt-attr.c41
-rw-r--r--libpthread/sysdeps/generic/pt-barrier-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-barrier-init.c53
-rw-r--r--libpthread/sysdeps/generic/pt-barrier-wait.c61
-rw-r--r--libpthread/sysdeps/generic/pt-barrier.c26
-rw-r--r--libpthread/sysdeps/generic/pt-barrierattr-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-barrierattr-getpshared.c29
-rw-r--r--libpthread/sysdeps/generic/pt-barrierattr-init.c28
-rw-r--r--libpthread/sysdeps/generic/pt-barrierattr-setpshared.c39
-rw-r--r--libpthread/sysdeps/generic/pt-cond-brdcast.c42
-rw-r--r--libpthread/sysdeps/generic/pt-cond-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-cond-init.c45
-rw-r--r--libpthread/sysdeps/generic/pt-cond-signal.c54
-rw-r--r--libpthread/sysdeps/generic/pt-cond-timedwait.c106
-rw-r--r--libpthread/sysdeps/generic/pt-cond-wait.c37
-rw-r--r--libpthread/sysdeps/generic/pt-cond.c29
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-getclock.c31
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-getpshared.c29
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-init.c28
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-setclock.c33
-rw-r--r--libpthread/sysdeps/generic/pt-condattr-setpshared.c39
-rw-r--r--libpthread/sysdeps/generic/pt-destroy-specific.c28
-rw-r--r--libpthread/sysdeps/generic/pt-equal.c29
-rw-r--r--libpthread/sysdeps/generic/pt-getconcurrency.c27
-rw-r--r--libpthread/sysdeps/generic/pt-getcpuclockid.c34
-rw-r--r--libpthread/sysdeps/generic/pt-getschedparam.c28
-rw-r--r--libpthread/sysdeps/generic/pt-getspecific.c27
-rw-r--r--libpthread/sysdeps/generic/pt-init-specific.c27
-rw-r--r--libpthread/sysdeps/generic/pt-key-create.c27
-rw-r--r--libpthread/sysdeps/generic/pt-key-delete.c27
-rw-r--r--libpthread/sysdeps/generic/pt-key.h22
-rw-r--r--libpthread/sysdeps/generic/pt-kill.c32
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-destroy.c39
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-getprioceiling.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-init.c50
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-lock.c37
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-setprioceiling.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-timedlock.c187
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-transfer-np.c66
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-trylock.c112
-rw-r--r--libpthread/sysdeps/generic/pt-mutex-unlock.c108
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-getprotocol.c29
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-getpshared.c29
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-gettype.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-init.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c28
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-setprotocol.c42
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-setpshared.c39
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr-settype.c37
-rw-r--r--libpthread/sysdeps/generic/pt-mutexattr.c45
-rw-r--r--libpthread/sysdeps/generic/pt-once.c43
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-attr.c26
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-destroy.c29
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-init.c45
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-rdlock.c32
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c113
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c95
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-tryrdlock.c56
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-trywrlock.c46
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-unlock.c90
-rw-r--r--libpthread/sysdeps/generic/pt-rwlock-wrlock.c34
-rw-r--r--libpthread/sysdeps/generic/pt-rwlockattr-destroy.c27
-rw-r--r--libpthread/sysdeps/generic/pt-rwlockattr-getpshared.c29
-rw-r--r--libpthread/sysdeps/generic/pt-rwlockattr-init.c28
-rw-r--r--libpthread/sysdeps/generic/pt-rwlockattr-setpshared.c39
-rw-r--r--libpthread/sysdeps/generic/pt-setconcurrency.c34
-rw-r--r--libpthread/sysdeps/generic/pt-setschedparam.c28
-rw-r--r--libpthread/sysdeps/generic/pt-setschedprio.c27
-rw-r--r--libpthread/sysdeps/generic/pt-setspecific.c27
-rw-r--r--libpthread/sysdeps/generic/pt-startup.c25
-rw-r--r--libpthread/sysdeps/generic/raise.c41
-rw-r--r--libpthread/sysdeps/generic/sem-close.c32
-rw-r--r--libpthread/sysdeps/generic/sem-destroy.c38
-rw-r--r--libpthread/sysdeps/generic/sem-getvalue.c33
-rw-r--r--libpthread/sysdeps/generic/sem-init.c46
-rw-r--r--libpthread/sysdeps/generic/sem-open.c32
-rw-r--r--libpthread/sysdeps/generic/sem-post.c62
-rw-r--r--libpthread/sysdeps/generic/sem-timedwait.c91
-rw-r--r--libpthread/sysdeps/generic/sem-trywait.c42
-rw-r--r--libpthread/sysdeps/generic/sem-unlink.c32
-rw-r--r--libpthread/sysdeps/generic/sem-wait.c32
-rw-r--r--libpthread/sysdeps/generic/sigaddset.c35
-rw-r--r--libpthread/sysdeps/generic/sigdelset.c35
-rw-r--r--libpthread/sysdeps/generic/sigemptyset.c29
-rw-r--r--libpthread/sysdeps/generic/sigfillset.c29
-rw-r--r--libpthread/sysdeps/generic/siginterrupt.c36
-rw-r--r--libpthread/sysdeps/generic/sigismember.c36
-rw-r--r--libpthread/sysdeps/generic/signal.c44
-rw-r--r--libpthread/sysdeps/generic/sigwait.c34
-rw-r--r--libpthread/sysdeps/hurd/pt-destroy-specific.c79
-rw-r--r--libpthread/sysdeps/hurd/pt-getspecific.c39
-rw-r--r--libpthread/sysdeps/hurd/pt-init-specific.c30
-rw-r--r--libpthread/sysdeps/hurd/pt-key-create.c109
-rw-r--r--libpthread/sysdeps/hurd/pt-key-delete.c64
-rw-r--r--libpthread/sysdeps/hurd/pt-key.h76
-rw-r--r--libpthread/sysdeps/hurd/pt-kill.c52
-rw-r--r--libpthread/sysdeps/hurd/pt-setspecific.c47
-rw-r--r--libpthread/sysdeps/ia32/bits/atomic.h66
-rw-r--r--libpthread/sysdeps/ia32/bits/memory.h40
-rw-r--r--libpthread/sysdeps/ia32/bits/spin-lock-inline.h98
-rw-r--r--libpthread/sysdeps/ia32/bits/spin-lock.h39
-rw-r--r--libpthread/sysdeps/ia32/machine-sp.h30
-rw-r--r--libpthread/sysdeps/ia32/pt-machdep.h29
-rw-r--r--libpthread/sysdeps/l4/bits/pthread-np.h35
-rw-r--r--libpthread/sysdeps/l4/hurd/bits/pthread-np.h31
-rw-r--r--libpthread/sysdeps/l4/hurd/ia32/pt-machdep.c20
-rw-r--r--libpthread/sysdeps/l4/hurd/ia32/pt-setup.c117
-rw-r--r--libpthread/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c213
-rw-r--r--libpthread/sysdeps/l4/hurd/powerpc/pt-machdep.c20
-rw-r--r--libpthread/sysdeps/l4/hurd/powerpc/pt-setup.c93
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-block.c30
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-kill.c3
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-setactivity-np.c39
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-sigstate-destroy.c28
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-sigstate-init.c44
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-sigstate.c81
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-startup.c30
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-sysdep.c61
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-sysdep.h61
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-thread-alloc.c95
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-thread-halt.c104
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-thread-start.c70
-rw-r--r--libpthread/sysdeps/l4/hurd/pt-wakeup.c46
-rw-r--r--libpthread/sysdeps/l4/hurd/sig-sysdep.h69
-rw-r--r--libpthread/sysdeps/l4/hurd/sigprocmask.c41
-rw-r--r--libpthread/sysdeps/l4/pt-block.c47
-rw-r--r--libpthread/sysdeps/l4/pt-docancel.c42
-rw-r--r--libpthread/sysdeps/l4/pt-pool-np.c54
-rw-r--r--libpthread/sysdeps/l4/pt-spin.c63
-rw-r--r--libpthread/sysdeps/l4/pt-stack-alloc.c43
-rw-r--r--libpthread/sysdeps/l4/pt-thread-alloc.c43
-rw-r--r--libpthread/sysdeps/l4/pt-thread-dealloc.c32
-rw-r--r--libpthread/sysdeps/l4/pt-thread-halt.c45
-rw-r--r--libpthread/sysdeps/l4/pt-thread-start.c40
-rw-r--r--libpthread/sysdeps/l4/pt-timedblock.c35
-rw-r--r--libpthread/sysdeps/l4/pt-wakeup.c54
-rw-r--r--libpthread/sysdeps/mach/bits/spin-lock-inline.h90
-rw-r--r--libpthread/sysdeps/mach/bits/spin-lock.h38
-rw-r--r--libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c83
-rw-r--r--libpthread/sysdeps/mach/hurd/ia32/pt-setup.c108
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-attr-setstackaddr.c35
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-attr-setstacksize.c35
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-docancel.c64
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-sigstate-destroy.c28
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-sigstate-init.c37
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-sigstate.c69
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-sysdep.c72
-rw-r--r--libpthread/sysdeps/mach/hurd/pt-sysdep.h72
-rw-r--r--libpthread/sysdeps/mach/pt-block.c39
-rw-r--r--libpthread/sysdeps/mach/pt-spin.c36
-rw-r--r--libpthread/sysdeps/mach/pt-stack-alloc.c74
-rw-r--r--libpthread/sysdeps/mach/pt-thread-alloc.c106
-rw-r--r--libpthread/sysdeps/mach/pt-thread-dealloc.c41
-rw-r--r--libpthread/sysdeps/mach/pt-thread-halt.c37
-rw-r--r--libpthread/sysdeps/mach/pt-thread-start.c49
-rw-r--r--libpthread/sysdeps/mach/pt-timedblock.c68
-rw-r--r--libpthread/sysdeps/mach/pt-wakeup.c38
-rw-r--r--libpthread/sysdeps/posix/pt-spin.c54
-rw-r--r--libpthread/sysdeps/powerpc/bits/machine-lock.h78
-rw-r--r--libpthread/sysdeps/powerpc/bits/memory.h36
-rw-r--r--libpthread/sysdeps/powerpc/bits/spin-lock.h108
-rw-r--r--libpthread/sysdeps/powerpc/machine-sp.h31
-rw-r--r--libpthread/sysdeps/powerpc/pt-machdep.h29
-rw-r--r--libpthread/tests/.cvsignore1
-rw-r--r--libpthread/tests/Makefile29
-rw-r--r--libpthread/tests/test-1.c50
-rw-r--r--libpthread/tests/test-10.c46
-rw-r--r--libpthread/tests/test-11.c143
-rw-r--r--libpthread/tests/test-12.c29
-rw-r--r--libpthread/tests/test-13.c66
-rw-r--r--libpthread/tests/test-14.c44
-rw-r--r--libpthread/tests/test-15.c87
-rw-r--r--libpthread/tests/test-16.c71
-rw-r--r--libpthread/tests/test-2.c39
-rw-r--r--libpthread/tests/test-3.c55
-rw-r--r--libpthread/tests/test-4.c86
-rw-r--r--libpthread/tests/test-5.c75
-rw-r--r--libpthread/tests/test-6.c96
-rw-r--r--libpthread/tests/test-7.c70
-rw-r--r--libpthread/tests/test-8.c60
-rw-r--r--libpthread/tests/test-9.c88
-rw-r--r--procfs/Makefile26
-rw-r--r--procfs/TODO24
-rw-r--r--procfs/dircat.c128
-rw-r--r--procfs/dircat.h29
-rw-r--r--procfs/main.c190
-rw-r--r--procfs/main.h25
-rw-r--r--procfs/netfs.c445
-rw-r--r--procfs/process.c387
-rw-r--r--procfs/process.h27
-rw-r--r--procfs/procfs.c203
-rw-r--r--procfs/procfs.h93
-rw-r--r--procfs/procfs_dir.c134
-rw-r--r--procfs/procfs_dir.h63
-rw-r--r--procfs/proclist.c94
-rw-r--r--procfs/proclist.h23
-rw-r--r--procfs/rootdir.c506
-rw-r--r--procfs/rootdir.h23
-rw-r--r--random/Makefile29
-rw-r--r--random/TODO11
-rw-r--r--random/gnupg-bithelp.h41
-rw-r--r--random/gnupg-glue.h40
-rw-r--r--random/gnupg-random.c810
-rw-r--r--random/gnupg-random.h47
-rw-r--r--random/gnupg-rmd.h38
-rw-r--r--random/gnupg-rmd160.c656
-rw-r--r--random/random.c624
-rw-r--r--random/random.h32
-rw-r--r--tests/test-17.c57
-rw-r--r--tests/test-__pthread_destroy_specific-skip.c83
302 files changed, 20371 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 00000000..70845e08
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1 @@
+Makefile.in
diff --git a/libpthread/ChangeLog b/libpthread/ChangeLog
new file mode 100644
index 00000000..e991eac7
--- /dev/null
+++ b/libpthread/ChangeLog
@@ -0,0 +1,6 @@
+51839d398b0f9885a17ab5c0768b8dec4dd9eb79 is the last commit imported from CVS.
+All commits after that one have valid author and committer information.
+
+Use this to examine the change log for earlier changes:
+
+ $ git show 51839d398b0f9885a17ab5c0768b8dec4dd9eb79:ChangeLog
diff --git a/libpthread/Makefile b/libpthread/Makefile
new file mode 100644
index 00000000..a1801f5c
--- /dev/null
+++ b/libpthread/Makefile
@@ -0,0 +1,249 @@
+#
+# Copyright (C) 1994, 1995, 1996, 1997, 2000, 2002, 2004, 2005, 2006, 2007,
+# 2008, 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libpthread
+makemode := library
+
+MICROKERNEL := mach
+SYSDEPS := lockfile.c
+
+LCLHDRS :=
+
+SRCS := pt-attr.c pt-attr-destroy.c pt-attr-getdetachstate.c \
+ pt-attr-getguardsize.c pt-attr-getinheritsched.c \
+ pt-attr-getschedparam.c pt-attr-getschedpolicy.c pt-attr-getscope.c \
+ pt-attr-getstack.c pt-attr-getstackaddr.c pt-attr-getstacksize.c \
+ pt-attr-init.c pt-attr-setdetachstate.c pt-attr-setguardsize.c \
+ pt-attr-setinheritsched.c pt-attr-setschedparam.c \
+ pt-attr-setschedpolicy.c pt-attr-setscope.c pt-attr-setstack.c \
+ pt-attr-setstackaddr.c pt-attr-setstacksize.c \
+ \
+ pt-barrier-destroy.c pt-barrier-init.c pt-barrier-wait.c \
+ pt-barrier.c pt-barrierattr-destroy.c pt-barrierattr-init.c \
+ pt-barrierattr-getpshared.c pt-barrierattr-setpshared.c \
+ \
+ pt-destroy-specific.c pt-init-specific.c \
+ pt-key-create.c pt-key-delete.c \
+ pt-getspecific.c pt-setspecific.c \
+ \
+ pt-once.c \
+ \
+ pt-alloc.c \
+ pt-create.c \
+ pt-getattr.c \
+ pt-equal.c \
+ pt-dealloc.c \
+ pt-detach.c \
+ pt-exit.c \
+ pt-initialize.c \
+ pt-join.c \
+ pt-self.c \
+ pt-sigmask.c \
+ pt-spin-inlines.c \
+ pt-cleanup.c \
+ pt-setcancelstate.c \
+ pt-setcanceltype.c \
+ pt-testcancel.c \
+ pt-cancel.c \
+ \
+ pt-mutexattr.c \
+ pt-mutexattr-destroy.c pt-mutexattr-init.c \
+ pt-mutexattr-getprioceiling.c pt-mutexattr-getprotocol.c \
+ pt-mutexattr-getpshared.c pt-mutexattr-gettype.c \
+ pt-mutexattr-setprioceiling.c pt-mutexattr-setprotocol.c \
+ pt-mutexattr-setpshared.c pt-mutexattr-settype.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 \
+ pt-rwlockattr-getpshared.c pt-rwlockattr-setpshared.c \
+ \
+ pt-rwlock-init.c pt-rwlock-destroy.c \
+ pt-rwlock-rdlock.c pt-rwlock-tryrdlock.c \
+ pt-rwlock-trywrlock.c pt-rwlock-wrlock.c \
+ pt-rwlock-timedrdlock.c pt-rwlock-timedwrlock.c \
+ pt-rwlock-unlock.c \
+ \
+ pt-cond.c \
+ pt-condattr-init.c pt-condattr-destroy.c \
+ pt-condattr-getclock.c pt-condattr-getpshared.c \
+ pt-condattr-setclock.c pt-condattr-setpshared.c \
+ \
+ pt-cond-destroy.c pt-cond-init.c \
+ pt-cond-brdcast.c \
+ pt-cond-signal.c \
+ pt-cond-wait.c \
+ pt-cond-timedwait.c \
+ \
+ pt-stack-alloc.c \
+ pt-thread-alloc.c \
+ pt-thread-dealloc.c \
+ pt-thread-start.c \
+ pt-thread-halt.c \
+ pt-startup.c \
+ \
+ pt-getconcurrency.c pt-setconcurrency.c \
+ \
+ pt-block.c \
+ pt-timedblock.c \
+ pt-wakeup.c \
+ pt-docancel.c \
+ pt-sysdep.c \
+ pt-setup.c \
+ pt-machdep.c \
+ pt-spin.c \
+ \
+ pt-sigstate-init.c \
+ pt-sigstate-destroy.c \
+ pt-sigstate.c \
+ \
+ pt-atfork.c \
+ pt-kill.c \
+ pt-getcpuclockid.c \
+ \
+ pt-getschedparam.c pt-setschedparam.c pt-setschedprio.c \
+ pt-yield.c \
+ \
+ sem-close.c sem-destroy.c sem-getvalue.c sem-init.c sem-open.c \
+ sem-post.c sem-timedwait.c sem-trywait.c sem-unlink.c \
+ sem-wait.c \
+ \
+ cthreads-compat.c \
+ $(SYSDEPS)
+
+OBJS = $(addsuffix .o,$(basename $(notdir $(SRCS))))
+
+OTHERTAGS =
+
+libname = libpthread
+
+sysdeps_headers = \
+ pthread.h \
+ pthread/pthread.h \
+ pthread/pthreadtypes.h \
+ semaphore.h \
+ \
+ bits/pthread.h \
+ bits/pthread-np.h \
+ bits/mutex.h \
+ bits/condition.h \
+ bits/condition-attr.h \
+ bits/spin-lock.h \
+ bits/spin-lock-inline.h \
+ bits/cancelation.h \
+ bits/thread-attr.h \
+ bits/barrier-attr.h \
+ bits/barrier.h \
+ bits/thread-specific.h \
+ bits/once.h \
+ bits/mutex-attr.h \
+ bits/rwlock.h \
+ bits/rwlock-attr.h \
+ bits/semaphore.h
+
+SYSDEP_PATH = $(srcdir)/sysdeps/$(MICROKERNEL)/hurd/ia32 \
+ $(srcdir)/sysdeps/$(MICROKERNEL)/ia32 \
+ $(srcdir)/sysdeps/ia32 \
+ $(srcdir)/sysdeps/$(MICROKERNEL)/hurd \
+ $(srcdir)/sysdeps/$(MICROKERNEL) \
+ $(srcdir)/sysdeps/hurd \
+ $(srcdir)/sysdeps/generic \
+ $(srcdir)/sysdeps/posix \
+ $(srcdir)/pthread \
+ $(srcdir)/include
+
+VPATH += $(SYSDEP_PATH)
+
+HURDLIBS = ihash
+
+installhdrs :=
+installhdrsubdir := .
+
+include ../Makeconf
+
+CPPFLAGS += \
+ -DENABLE_TLS \
+ $(addprefix -I, $(SYSDEP_PATH)) \
+ -imacros $(srcdir)/include/libc-symbols.h \
+ -imacros $(srcdir)/not-in-libc.h
+
+
+install: install-headers $(libdir)/libpthread2.a $(libdir)/libpthread2_pic.a
+install-headers: $(addprefix $(includedir)/, $(sysdeps_headers))
+
+# XXX: If $(libdir)/libpthread2.a is installed and
+# $(libdir)/libpthread is not, we can have some issues.
+.PHONY: $(libdir)/libpthread.a $(libdir)/libpthread_pic.a
+
+# XXX: These rules are a hack. But it is better than messing with
+# ../Makeconf at the moment. Note that the linker scripts
+# $(srcdir)/libpthread.a and $(srcdir)/libpthread_pic.a get overwritten
+# when building in $(srcdir) and not a seperate build directory.
+$(libdir)/libpthread2.a: $(libdir)/libpthread.a
+ mv $< $@
+ $(INSTALL_DATA) $(srcdir)/libpthread.a $<
+
+$(libdir)/libpthread2_pic.a: $(libdir)/libpthread_pic.a
+ mv $< $@
+ $(INSTALL_DATA) $(srcdir)/libpthread_pic.a $<
+
+.PHONY: $(addprefix $(includedir)/, $(sysdeps_headers))
+
+$(addprefix $(includedir)/, $(sysdeps_headers)):
+ @set -e; \
+ t="$@"; \
+ t=$${t#$(includedir)/}; \
+ header_ok=0; \
+ for dir in $(SYSDEP_PATH); \
+ do \
+ if test -e "$$dir/$$t"; \
+ then \
+ tdir=`dirname "$@"`; \
+ if test ! -e $$tdir; \
+ then \
+ mkdir $$tdir; \
+ fi; \
+ echo $(INSTALL_DATA) "$$dir/$$t" "$@"; \
+ $(INSTALL_DATA) "$$dir/$$t" "$@"; \
+ header_ok=1; \
+ break; \
+ fi; \
+ done; \
+ if test "$${header_ok}" -ne 1; \
+ then \
+ echo; \
+ echo '*** 'The header file \`$@\' is required, but not \
+provided, by; \
+ echo '*** 'this configuration. Please report this to the \
+maintainer.; \
+ echo; \
+ false; \
+ fi
+
+# ifeq ($(VERSIONING),yes)
+#
+# # Adding this dependency gets it included in the command line,
+# # where ld will read it as a linker script.
+# $(libname).so.$(hurd-version): $(srcdir)/$(libname).map
+#
+# endif
diff --git a/libpthread/Makefile.am b/libpthread/Makefile.am
new file mode 100644
index 00000000..e1c062c1
--- /dev/null
+++ b/libpthread/Makefile.am
@@ -0,0 +1,168 @@
+# Makefile.am - Makefile template for libpthread.
+# Copyright (C) 2003, 2008 Free Software Foundation, Inc.
+#
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# The GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+if ARCH_IA32
+ arch=ia32
+endif
+if ARCH_POWERPC
+ arch=powerpc
+endif
+
+# 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} \
+ $(srcdir)/sysdeps/${arch} \
+ $(srcdir)/sysdeps/l4/hurd \
+ $(srcdir)/sysdeps/l4 \
+ $(srcdir)/sysdeps/hurd \
+ $(srcdir)/sysdeps/generic \
+ $(srcdir)/sysdeps/posix \
+ $(srcdir)/pthread \
+ $(srcdir)/signal \
+ $(srcdir)/include
+vpath %.c $(SYSDEP_PATH)
+
+AM_CPPFLAGS = $(USER_CPPFLAGS) -I$(srcdir)/pthread \
+ $(addprefix -I, $(SYSDEP_PATH)) -imacros $(srcdir)/include/libc-symbols.h
+AM_CFLAGS = $(USER_CFLAGS)
+
+# Sources.
+SYSDEPS := lockfile.c
+
+if ! ENABLE_TESTS
+noinst_LIBRARIES = libpthread.a
+endif
+
+libpthread_a_SOURCES = pt-attr.c pt-attr-destroy.c pt-attr-getdetachstate.c \
+ pt-attr-getguardsize.c pt-attr-getinheritsched.c \
+ pt-attr-getschedparam.c pt-attr-getschedpolicy.c pt-attr-getscope.c \
+ pt-attr-getstack.c pt-attr-getstackaddr.c pt-attr-getstacksize.c \
+ pt-attr-init.c pt-attr-setdetachstate.c pt-attr-setguardsize.c \
+ pt-attr-setinheritsched.c pt-attr-setschedparam.c \
+ pt-attr-setschedpolicy.c pt-attr-setscope.c pt-attr-setstack.c \
+ pt-attr-setstackaddr.c pt-attr-setstacksize.c pt-attr.c \
+ pt-barrier-destroy.c pt-barrier-init.c pt-barrier-wait.c \
+ pt-barrier.c pt-barrierattr-destroy.c pt-barrierattr-init.c \
+ pt-barrierattr-getpshared.c pt-barrierattr-setpshared.c \
+ pt-destroy-specific.c pt-init-specific.c \
+ pt-key-create.c pt-key-delete.c \
+ pt-getspecific.c pt-setspecific.c \
+ pt-once.c \
+ pt-alloc.c \
+ pt-create.c \
+ pt-getattr.c \
+ pt-pool-np.c \
+ pt-equal.c \
+ pt-dealloc.c \
+ pt-detach.c \
+ pt-exit.c \
+ pt-initialize.c \
+ pt-join.c \
+ pt-self.c \
+ pt-sigmask.c \
+ pt-spin-inlines.c \
+ pt-cleanup.c \
+ pt-setcancelstate.c \
+ pt-setcanceltype.c \
+ pt-testcancel.c \
+ pt-cancel.c \
+ pt-mutexattr.c \
+ pt-mutexattr-destroy.c pt-mutexattr-init.c \
+ pt-mutexattr-getprioceiling.c pt-mutexattr-getprotocol.c \
+ pt-mutexattr-getpshared.c pt-mutexattr-gettype.c \
+ pt-mutexattr-setprioceiling.c pt-mutexattr-setprotocol.c \
+ pt-mutexattr-setpshared.c pt-mutexattr-settype.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 \
+ pt-rwlockattr-getpshared.c pt-rwlockattr-setpshared.c \
+ pt-rwlock-init.c pt-rwlock-destroy.c \
+ pt-rwlock-rdlock.c pt-rwlock-tryrdlock.c \
+ pt-rwlock-trywrlock.c pt-rwlock-wrlock.c \
+ pt-rwlock-timedrdlock.c pt-rwlock-timedwrlock.c \
+ pt-rwlock-unlock.c \
+ pt-cond.c \
+ pt-condattr-init.c pt-condattr-destroy.c \
+ pt-condattr-getclock.c pt-condattr-getpshared.c \
+ pt-condattr-setclock.c pt-condattr-setpshared.c \
+ pt-cond-destroy.c pt-cond-init.c \
+ pt-cond-brdcast.c \
+ pt-cond-signal.c \
+ pt-cond-wait.c \
+ pt-cond-timedwait.c \
+ pt-stack-alloc.c \
+ pt-thread-alloc.c \
+ pt-thread-dealloc.c \
+ pt-thread-start.c \
+ pt-thread-halt.c \
+ pt-startup.c \
+ pt-getconcurrency.c pt-setconcurrency.c \
+ pt-block.c \
+ pt-timedblock.c \
+ pt-wakeup.c \
+ pt-docancel.c \
+ pt-sysdep.c \
+ pt-setup.c \
+ pt-machdep.c \
+ pt-spin.c \
+ pt-sigstate-init.c \
+ pt-sigstate-destroy.c \
+ pt-sigstate.c \
+ pt-atfork.c \
+ pt-kill.c \
+ pt-getcpuclockid.c \
+ pt-getschedparam.c pt-setschedparam.c pt-setschedprio.c \
+ pt-yield.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 \
+ \
+ pt-setactivity-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 \
+ sigprocmask.c
diff --git a/libpthread/TODO b/libpthread/TODO
new file mode 100644
index 00000000..d7e54da6
--- /dev/null
+++ b/libpthread/TODO
@@ -0,0 +1,177 @@
+-*- Mode: outline -*-
+
+* Interfaces
+** All interfaces specified by IEEE Std 1003.1-2001 are present, however,
+ pthread_kill and pthread_sigmask are defined in <pthread.h> and not
+ <signal.h> as they should be. Once we are compiled with glibc,
+ this should be eaiser.
+
+* Test cases. Can never have enough.
+
+* Ports
+ Port to other kernels (e.g. Linux and FreeBSD) and test on other
+ platforms.
+
+* Implementation details
+** pthread_atfork
+ This cannot be implemented without either changing glibc to export
+ some hooks (c.f. libc/sysdeps/mach/hurd/fork.c) or by providing a
+ custom fork implementation that wraps the origial using dlopen et
+ al.
+
+** Scheduling and priorities
+
+ We do not support scheduling right now in any way what so ever.
+
+ This affects:
+ pthread_attr_getinheritsched
+ pthread_attr_setinheritsched
+ pthread_attr_getschedparam
+ pthread_attr_setschedparam
+ pthread_attr_getschedpolicy
+ pthread_attr_setschedpolicy
+ pthread_attr_getscope
+ pthread_attr_setscope
+
+ pthread_mutexattr_getprioceiling
+ pthread_mutexattr_setprioceiling
+ pthread_mutexattr_getprotocol
+ pthread_mutexattr_setprotocol
+ pthread_mutex_getprioceiling
+ pthread_mutex_setprioceiling
+
+ pthread_setschedprio
+ pthread_getschedparam
+ pthread_setschedparam
+
+** Alternate stacks
+
+ Supporting alternate stacks (via pthread_attr_getstackaddr,
+ pthread_attr_setstackaddr, pthread_attr_getstack,
+ pthread_attr_setstack, pthread_attr_getstacksize and
+ pthread_attr_setstacksize) is no problem as long as they are of the
+ correct size and have the correct alignment. This is due to
+ limitations in the Hurd TSD implementation
+ (c.f. <hurd/threadvar.h>).
+
+** Cancelation
+*** Cancelation points
+ The only cancelation points are pthread_join, pthread_cond_wait,
+ pthead_cond_timedwait and pthread_testcancel. Need to explore if
+ the hurd_sigstate->cancel_hook (c.f. <hurd/signal.h>) provides the
+ desired semantics. If not, must either wrap the some functions
+ using dlsym or wait until integration with glibc.
+*** Async cancelation
+ We inject a new IP into the cancelled (running) thread and then
+ run the cancelation handlers
+ (c.f. sysdeps/mach/hurd/pt-docancel.c). The handlers need to have
+ access to the stack as they may use local variables. I think that
+ this method may leave the frame pointer in a corrupted state if
+ the thread was in, for instance, the middle of a function call.
+ The robustness needs to be confirmed.
+
+** Process Shared Attribute
+
+ Currently, there is no real support for the process shared
+ attribute. spinlocks work because we just use a test and set loop,
+ however, barriers, conditions mutexes and rwlocks, however, signal
+ wakeups via ports of which the names are process local.
+
+ We could have some process local data that is hashed to via the
+ address of the data structure. Then the first thread that blocks
+ per process would spin on the shared memory area and all others
+ would then block as normal. When the resource became available,
+ the first thread would signal the other local threads as necessary.
+ Alternatively, there could be some server, however, this opens a
+ new question: what can we use as an authentication agent.
+
+** Locking algorithm
+
+ When a thread blocks, it puts itself on a queue and then waits for
+ a message on a thread local port. The thread which eventually does
+ the wakeup sends a message to the waiter thereby waking it up. If
+ the wakeup is a broadcast wakeup (e.g. pthread_cond_broadcast,
+ pthread_barrier_wait and pthread_rdlock_unlock), the thread must
+ send O(N) messages where N is the number of waiting threads. If
+ all the threads instead received on a lock local (rather than
+ thread local) port then the thread which eventually does the wake
+ need just do one operation, mach_port_destroy and all of the
+ waiting threads would wakeup and get MACH_RCV_PORT_DIED back from
+ mach_msg. Note that the trade off is that the port must be
+ recreated. This needs to be benchmarked.
+
+ A possible problem with this is scheduling priorities. There may
+ be a preference for certain threads to wakeup before others
+ (especially if we are not doing a broadcast, for instance,
+ pthread_mutex_unlock and pthread_cond_signal). If we take this
+ approach, the kernel chooses which threads are awakened. If we
+ find that the kernel makes the wrong choices, we can still overcome
+ this by merging the two algorithms: have a list of ports sorted in
+ priority order and the waker does a mach_port_destroy on each as
+ appropriate.
+
+** Barriers
+
+ Barriers can be very slow and the contention can be very high. The
+ above algorithm is very appealing, however, this may be augmented
+ with an initial number of spins and yields. It is expected that
+ all of the threads reach the barrier within close succession, thus
+ queuing a message may be more expensive. This needs to be
+ benchmarked.
+
+** Clocks
+*** pthread_condattr_setclock allows a process to specify a clock for
+ use with pthread_cond_timedwaits. What is the correct default for
+ this, right now, we use CLOCK_REALTIME, however, we are really
+ using the system clock which, if I understand correctly, is
+ completely different.
+*** Could we even use other clocks? mach_msg uses a relative time against
+ the system clock.
+*** pthread_getcpuclockid just returns CLOCK_THREAD_CPUTIME_ID if defined.
+ Is this the correct behavior?
+
+** Timed Blocking
+*** pthread_cond_timedwait, pthead_mutex_timedlock, pthread_rwlock_timedrdlock
+ and pthread_rwlock_timedwrlock all take absolute times. We need
+ to convert them to relative times for mach_msg. Is there a way
+ around this? How will clock skew affect us?
+
+** weak aliases
+ Use them consistently and correctly and start by reading
+ http://sources.redhat.com/ml/libc-alpha/2002-08/msg00278.html.
+
+** TLS
+ Support for TLS is only implemented for Mach/Hurd (x86).
+
+* L4 Specific Issues
+** Stack
+*** Size
+ The stack size is defined to be a single page in
+ sysdeps/l4/hurd/pt-sysdep.h. Once we are able to setup regions,
+ this can be expanded to two megs as suggested by the Mach version.
+ Until then, however, we need to allocate too much physical memory.
+*** Deallocation
+ __thread_stack_dealloc currently does not deallocate the stack.
+ For a proper implementation, we need a working memory manager.
+
+** Scheduling
+*** yield
+ [L4] We cannot use yield for spin locks as L4 only yields to threads of
+ priority which are greater than or equal to the yielding thread.
+ If there are threads of lower priority, they are not considered;
+ the yielding thread is just placed back on the processor. This
+ introduces priority inversion quite quickly. L4 will not add a
+ priority suppression function call. As such, we need to do
+ an ipc with a small time out and then use exponential back off to
+ do the actual waiting. This sucks.
+
+** Stub code
+ [L4] We include <task_client.h> in pt-start.c, however, we need a library
+ so we do not have to play with the corba stuff.
+
+** Root server and Task server
+*** Getting the tids.
+ pt-start.c has a wonderfully evil hack that will never work well.
+
+** Paging
+ We set the pager to the root server. Evil. Fix this in pt-start.c.
diff --git a/libpthread/headers.m4 b/libpthread/headers.m4
new file mode 100644
index 00000000..5a58b9bf
--- /dev/null
+++ b/libpthread/headers.m4
@@ -0,0 +1,45 @@
+# headers.m4 - Autoconf snippets to install links for header files.
+# Copyright 2003, 2008 Free Software Foundation, Inc.
+# Written by Marcus Brinkmann <marcus@gnu.org>.
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+AC_CONFIG_LINKS([
+ sysroot/include/pthread.h:libpthread/include/pthread.h
+ sysroot/include/pthread/pthread.h:libpthread/include/pthread/pthread.h
+ sysroot/include/pthread/pthreadtypes.h:libpthread/include/pthread/pthreadtypes.h
+ sysroot/include/bits/memory.h:libpthread/sysdeps/${arch}/bits/memory.h
+ sysroot/include/bits/spin-lock.h:libpthread/sysdeps/${arch}/bits/spin-lock.h
+ sysroot/include/bits/spin-lock-inline.h:libpthread/sysdeps/${arch}/bits/spin-lock-inline.h
+ sysroot/include/bits/pthreadtypes.h:libpthread/sysdeps/generic/bits/pthreadtypes.h
+ sysroot/include/bits/barrier-attr.h:libpthread/sysdeps/generic/bits/barrier-attr.h
+ sysroot/include/bits/barrier.h:libpthread/sysdeps/generic/bits/barrier.h
+ sysroot/include/bits/cancelation.h:libpthread/sysdeps/generic/bits/cancelation.h
+ sysroot/include/bits/condition-attr.h:libpthread/sysdeps/generic/bits/condition-attr.h
+ sysroot/include/bits/condition.h:libpthread/sysdeps/generic/bits/condition.h
+ sysroot/include/bits/mutex-attr.h:libpthread/sysdeps/generic/bits/mutex-attr.h
+ sysroot/include/bits/mutex.h:libpthread/sysdeps/generic/bits/mutex.h
+ sysroot/include/bits/once.h:libpthread/sysdeps/generic/bits/once.h
+ sysroot/include/bits/pthread.h:libpthread/sysdeps/generic/bits/pthread.h
+ sysroot/include/bits/rwlock-attr.h:libpthread/sysdeps/generic/bits/rwlock-attr.h
+ sysroot/include/bits/rwlock.h:libpthread/sysdeps/generic/bits/rwlock.h
+ sysroot/include/bits/thread-attr.h:libpthread/sysdeps/generic/bits/thread-attr.h
+ sysroot/include/bits/thread-barrier.h:libpthread/sysdeps/generic/bits/thread-barrier.h
+ sysroot/include/bits/thread-specific.h:libpthread/sysdeps/generic/bits/thread-specific.h
+ sysroot/include/bits/pthread-np.h:libpthread/sysdeps/l4/hurd/bits/pthread-np.h
+ sysroot/include/semaphore.h:libpthread/include/semaphore.h
+ sysroot/include/bits/semaphore.h:libpthread/sysdeps/generic/bits/semaphore.h
+ sysroot/include/signal.h:libpthread/signal/signal.h
+])
+
+AC_CONFIG_COMMANDS_POST([
+ mkdir -p sysroot/lib libpthread &&
+ ln -sf ../../libpthread/libpthread.a sysroot/lib/ &&
+ touch libpthread/libpthread.a
+])
diff --git a/libpthread/include/libc-symbols.h b/libpthread/include/libc-symbols.h
new file mode 100644
index 00000000..54dd6e26
--- /dev/null
+++ b/libpthread/include/libc-symbols.h
@@ -0,0 +1,395 @@
+/* Support macros for making weak and strong aliases for symbols,
+ and for using symbol sets and linker warnings with GNU ld.
+ Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _LIBC_SYMBOLS_H
+#define _LIBC_SYMBOLS_H 1
+
+/* This file's macros are included implicitly in the compilation of every
+ file in the C library by -imacros.
+
+ We include config.h which is generated by configure.
+ It should define for us the following symbols:
+
+ * HAVE_ASM_SET_DIRECTIVE if we have `.set B, A' instead of `A = B'.
+ * ASM_GLOBAL_DIRECTIVE with `.globl' or `.global'.
+ * HAVE_GNU_LD if using GNU ld, with support for weak symbols in a.out,
+ and for symbol set and warning messages extensions in a.out and ELF.
+ * HAVE_ELF if using ELF, which supports weak symbols using `.weak'.
+ * HAVE_ASM_WEAK_DIRECTIVE if we have weak symbols using `.weak'.
+ * HAVE_ASM_WEAKEXT_DIRECTIVE if we have weak symbols using `.weakext'.
+
+ */
+
+/* This is defined for the compilation of all C library code. features.h
+ tests this to avoid inclusion of stubs.h while compiling the library,
+ before stubs.h has been generated. Some library code that is shared
+ with other packages also tests this symbol to see if it is being
+ compiled as part of the C library. We must define this before including
+ config.h, because it makes some definitions conditional on whether libc
+ itself is being compiled, or just some generator program. */
+// #define _LIBC 1
+
+/* Enable declarations of GNU extensions, since we are compiling them. */
+#define _GNU_SOURCE 1
+/* And we also need the data for the reentrant functions. */
+#define _REENTRANT 1
+
+// #include <config.h>
+#define HAVE_ASM_WEAK_DIRECTIVE
+#define HAVE_WEAK_SYMBOLS
+#define HAVE_ASM_SET_DIRECTIVE
+#define HAVE_BUILTIN_EXPECT
+#define HAVE_GNU_LD
+#define HAVE_ELF
+#define HAVE_SECTION_QUOTES
+#define HAVE_VISIBILITY_ATTRIBUTE
+#define HAVE_ASM_PREVIOUS_DIRECTIVE
+// #define SHARED
+
+/* The symbols in all the user (non-_) macros are C symbols.
+ HAVE_GNU_LD without HAVE_ELF implies a.out. */
+
+#if defined HAVE_ASM_WEAK_DIRECTIVE || defined HAVE_ASM_WEAKEXT_DIRECTIVE
+# define HAVE_WEAK_SYMBOLS
+#endif
+
+#ifndef __SYMBOL_PREFIX
+# ifdef NO_UNDERSCORES
+# define __SYMBOL_PREFIX
+# else
+# define __SYMBOL_PREFIX "_"
+# endif
+#endif
+
+#ifndef C_SYMBOL_NAME
+# ifdef NO_UNDERSCORES
+# define C_SYMBOL_NAME(name) name
+# else
+# define C_SYMBOL_NAME(name) _##name
+# endif
+#endif
+
+#ifndef ASM_LINE_SEP
+# define ASM_LINE_SEP ;
+#endif
+
+#ifndef C_SYMBOL_DOT_NAME
+# define C_SYMBOL_DOT_NAME(name) .##name
+#endif
+
+#ifndef __ASSEMBLER__
+/* GCC understands weak symbols and aliases; use its interface where
+ possible, instead of embedded assembly language. */
+
+/* Define ALIASNAME as a strong alias for NAME. */
+# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+# define _strong_alias(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+
+/* This comes between the return type and function name in
+ a function definition to make that definition weak. */
+# define weak_function __attribute__ ((weak))
+# define weak_const_function __attribute__ ((weak, __const__))
+
+# ifdef HAVE_WEAK_SYMBOLS
+
+/* Define ALIASNAME as a weak alias for NAME.
+ If weak aliases are not available, this defines a strong alias. */
+# define weak_alias(name, aliasname) _weak_alias (name, aliasname)
+# define _weak_alias(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
+
+/* Declare SYMBOL as weak undefined symbol (resolved to 0 if not defined). */
+# define weak_extern(symbol) _weak_extern (symbol)
+# ifdef HAVE_ASM_WEAKEXT_DIRECTIVE
+# define _weak_extern(symbol) asm (".weakext " __SYMBOL_PREFIX #symbol);
+# else
+# define _weak_extern(symbol) asm (".weak " __SYMBOL_PREFIX #symbol);
+# endif
+
+# else
+
+# define weak_alias(name, aliasname) strong_alias(name, aliasname)
+# define weak_extern(symbol) /* Nothing. */
+
+# endif
+
+#else /* __ASSEMBLER__ */
+
+# ifdef HAVE_ASM_SET_DIRECTIVE
+# define strong_alias(original, alias) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME (alias) ASM_LINE_SEP \
+ .set C_SYMBOL_NAME (alias),C_SYMBOL_NAME (original)
+# else
+# ifdef HAVE_ASM_GLOBAL_DOT_NAME
+# define strong_alias(original, alias) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) ASM_LINE_SEP \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_DOT_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_DOT_NAME (alias) = C_SYMBOL_DOT_NAME (original)
+# else
+# define strong_alias(original, alias) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original)
+# endif
+# endif
+
+# ifdef HAVE_WEAK_SYMBOLS
+# ifdef HAVE_ASM_WEAKEXT_DIRECTIVE
+# define weak_alias(original, alias) \
+ .weakext C_SYMBOL_NAME (alias), C_SYMBOL_NAME (original)
+# define weak_extern(symbol) \
+ .weakext C_SYMBOL_NAME (symbol)
+
+# else /* ! HAVE_ASM_WEAKEXT_DIRECTIVE */
+
+# ifdef HAVE_ASM_GLOBAL_DOT_NAME
+# define weak_alias(original, alias) \
+ .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) ASM_LINE_SEP \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_DOT_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_DOT_NAME (alias) = C_SYMBOL_DOT_NAME (original)
+# else
+# define weak_alias(original, alias) \
+ .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \
+ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original)
+# endif
+
+# define weak_extern(symbol) \
+ .weak C_SYMBOL_NAME (symbol)
+
+# endif /* ! HAVE_ASM_WEAKEXT_DIRECTIVE */
+
+# else /* ! HAVE_WEAK_SYMBOLS */
+
+# define weak_alias(original, alias) strong_alias(original, alias)
+# define weak_extern(symbol) /* Nothing */
+# endif /* ! HAVE_WEAK_SYMBOLS */
+
+#endif /* __ASSEMBLER__ */
+
+/* On some platforms we can make internal function calls (i.e., calls of
+ functions not exported) a bit faster by using a different calling
+ convention. */
+#ifndef internal_function
+# define internal_function /* empty */
+#endif
+
+/* Prepare for the case that `__builtin_expect' is not available. */
+#ifndef HAVE_BUILTIN_EXPECT
+# define __builtin_expect(expr, val) (expr)
+#endif
+
+/* Determine the return address. */
+#define RETURN_ADDRESS(nr) \
+ __builtin_extract_return_addr (__builtin_return_address (nr))
+
+/* When a reference to SYMBOL is encountered, the linker will emit a
+ warning message MSG. */
+#ifdef HAVE_GNU_LD
+# ifdef HAVE_ELF
+
+/* We want the .gnu.warning.SYMBOL section to be unallocated. */
+# ifdef HAVE_ASM_PREVIOUS_DIRECTIVE
+# define __make_section_unallocated(section_string) \
+ asm (".section " section_string "\n\t.previous");
+# elif defined HAVE_ASM_POPSECTION_DIRECTIVE
+# define __make_section_unallocated(section_string) \
+ asm (".pushsection " section_string "\n\t.popsection");
+# else
+# define __make_section_unallocated(section_string)
+# endif
+
+/* Tacking on "\n\t#" to the section name makes gcc put it's bogus
+ section attributes on what looks like a comment to the assembler. */
+# ifdef HAVE_SECTION_QUOTES
+# define link_warning(symbol, msg) \
+ __make_section_unallocated (".gnu.warning." #symbol) \
+ static const char __evoke_link_warning_##symbol[] \
+ __attribute__ ((unused, section (".gnu.warning." #symbol "\"\n\t#\""))) \
+ = msg;
+# else
+# define link_warning(symbol, msg) \
+ __make_section_unallocated (".gnu.warning." #symbol) \
+ static const char __evoke_link_warning_##symbol[] \
+ __attribute__ ((unused, section (".gnu.warning." #symbol "\n\t#"))) = msg;
+# endif
+# else /* Not ELF: a.out */
+# ifdef HAVE_XCOFF
+/* XCOFF does not support .stabs.
+ The native aix linker will remove the .stab and .stabstr sections
+ The gnu linker will have a fatal error if there is a relocation for
+ symbol in the .stab section. Silently disable this macro. */
+# define link_warning(symbol, msg)
+# else
+# define link_warning(symbol, msg) \
+ asm (".stabs \"" msg "\",30,0,0,0\n\t" \
+ ".stabs \"" __SYMBOL_PREFIX #symbol "\",1,0,0,0\n");
+# endif /* XCOFF */
+# endif
+#else
+/* We will never be heard; they will all die horribly. */
+# define link_warning(symbol, msg)
+#endif
+
+/* A canned warning for sysdeps/stub functions. */
+#define stub_warning(name) \
+ link_warning (name, \
+ "warning: " #name " is not implemented and will always fail")
+
+/*
+
+*/
+
+#ifdef HAVE_GNU_LD
+
+/* Symbol set support macros. */
+
+# ifdef HAVE_ELF
+
+/* Make SYMBOL, which is in the text segment, an element of SET. */
+# define text_set_element(set, symbol) _elf_set_element(set, symbol)
+/* Make SYMBOL, which is in the data segment, an element of SET. */
+# define data_set_element(set, symbol) _elf_set_element(set, symbol)
+/* Make SYMBOL, which is in the bss segment, an element of SET. */
+# define bss_set_element(set, symbol) _elf_set_element(set, symbol)
+
+/* These are all done the same way in ELF.
+ There is a new section created for each set. */
+# ifdef SHARED
+/* When building a shared library, make the set section writable,
+ because it will need to be relocated at run time anyway. */
+# define _elf_set_element(set, symbol) \
+ static const void *__elf_set_##set##_element_##symbol##__ \
+ __attribute__ ((unused, section (#set))) = &(symbol)
+# else
+# define _elf_set_element(set, symbol) \
+ static const void *const __elf_set_##set##_element_##symbol##__ \
+ __attribute__ ((unused, section (#set))) = &(symbol)
+# endif
+
+/* Define SET as a symbol set. This may be required (it is in a.out) to
+ be able to use the set's contents. */
+# define symbol_set_define(set) symbol_set_declare(set)
+
+/* Declare SET for use in this module, if defined in another module. */
+# define symbol_set_declare(set) \
+ extern void *const __start_##set __attribute__ ((__weak__)); \
+ extern void *const __stop_##set __attribute__ ((__weak__)); \
+ weak_extern (__start_##set) weak_extern (__stop_##set)
+
+/* Return a pointer (void *const *) to the first element of SET. */
+# define symbol_set_first_element(set) (&__start_##set)
+
+/* Return true iff PTR (a void *const *) has been incremented
+ past the last element in SET. */
+# define symbol_set_end_p(set, ptr) ((ptr) >= &__stop_##set)
+
+# else /* Not ELF: a.out. */
+
+# ifdef HAVE_XCOFF
+/* XCOFF does not support .stabs.
+ The native aix linker will remove the .stab and .stabstr sections
+ The gnu linker will have a fatal error if there is a relocation for
+ symbol in the .stab section. Silently disable these macros. */
+# define text_set_element(set, symbol)
+# define data_set_element(set, symbol)
+# define bss_set_element(set, symbol)
+# else
+# define text_set_element(set, symbol) \
+ asm (".stabs \"" __SYMBOL_PREFIX #set "\",23,0,0," __SYMBOL_PREFIX #symbol)
+# define data_set_element(set, symbol) \
+ asm (".stabs \"" __SYMBOL_PREFIX #set "\",25,0,0," __SYMBOL_PREFIX #symbol)
+# define bss_set_element(set, symbol) ?error Must use initialized data.
+# endif /* XCOFF */
+# define symbol_set_define(set) void *const (set)[1];
+# define symbol_set_declare(set) extern void *const (set)[1];
+
+# define symbol_set_first_element(set) &(set)[1]
+# define symbol_set_end_p(set, ptr) (*(ptr) == 0)
+
+# endif /* ELF. */
+#else
+/* We cannot do anything in generial. */
+# define text_set_element(set, symbol) asm ("")
+# define data_set_element(set, symbol) asm ("")
+# define bss_set_element(set, symbol) asm ("")
+# define symbol_set_define(set) void *const (set)[1];
+# define symbol_set_declare(set) extern void *const (set)[1];
+
+# define symbol_set_first_element(set) &(set)[1]
+# define symbol_set_end_p(set, ptr) (*(ptr) == 0)
+#endif /* Have GNU ld. */
+
+#if DO_VERSIONING
+# define symbol_version(real, name, version) \
+ _symbol_version(real, name, version)
+# define default_symbol_version(real, name, version) \
+ _default_symbol_version(real, name, version)
+# ifdef __ASSEMBLER__
+# define _symbol_version(real, name, version) \
+ .symver real, name##@##version
+# define _default_symbol_version(real, name, version) \
+ .symver real, name##@##@##version
+# else
+# define _symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@" #version)
+# define _default_symbol_version(real, name, version) \
+ __asm__ (".symver " #real "," #name "@@" #version)
+# endif
+#else
+# define symbol_version(real, name, version)
+# define default_symbol_version(real, name, version) \
+ strong_alias(real, name)
+#endif
+
+#if defined HAVE_VISIBILITY_ATTRIBUTE && defined SHARED
+# define attribute_hidden __attribute__ ((visibility ("hidden")))
+#else
+# define attribute_hidden
+#endif
+
+/* Handling on non-exported internal names. We have to do this only
+ for shared code. */
+#ifdef SHARED
+# define INTUSE(name) name##_internal
+# define INTDEF(name) strong_alias (name, name##_internal)
+# define INTVARDEF(name) \
+ _INTVARDEF (name, name##_internal)
+# if defined HAVE_VISIBILITY_ATTRIBUTE
+# define _INTVARDEF(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((alias (#name), \
+ visibility ("hidden")));
+# else
+# define _INTVARDEF(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+# endif
+# define INTDEF2(name, newname) strong_alias (name, newname##_internal)
+# define INTVARDEF2(name, newname) _INTVARDEF (name, newname##_internal)
+#else
+# define INTUSE(name) name
+# define INTDEF(name)
+# define INTVARDEF(name)
+# define INTDEF2(name, newname)
+# define INTVARDEF2(name, newname)
+#endif
+
+#endif /* libc-symbols.h */
diff --git a/libpthread/include/pthread.h b/libpthread/include/pthread.h
new file mode 100644
index 00000000..1d4d3c7b
--- /dev/null
+++ b/libpthread/include/pthread.h
@@ -0,0 +1,7 @@
+#ifndef _PTHREAD_H
+#include <pthread/pthread.h>
+
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+#endif
diff --git a/libpthread/include/pthread/pthread.h b/libpthread/include/pthread/pthread.h
new file mode 100644
index 00000000..4dbcb0cb
--- /dev/null
+++ b/libpthread/include/pthread/pthread.h
@@ -0,0 +1,755 @@
+/* Copyright (C) 2000, 2002, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * POSIX Threads Extension: ??? <pthread.h>
+ */
+
+#ifndef _PTHREAD_H
+#define _PTHREAD_H 1
+
+#include <features.h>
+
+#include <sys/cdefs.h>
+#ifndef __extern_inline
+/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+ inline semantics, unless -fgnu89-inline is used. */
+# if !defined __cplusplus || __GNUC_PREREQ (4,3)
+# if defined __GNUC_STDC_INLINE__ || defined __cplusplus
+# define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
+# if __GNUC_PREREQ (4,3)
+# define __extern_always_inline \
+ extern __always_inline __attribute__ ((__gnu_inline__, __artificial__))
+# else
+# define __extern_always_inline \
+ extern __always_inline __attribute__ ((__gnu_inline__))
+# endif
+# else
+# define __extern_inline extern __inline
+# define __extern_always_inline extern __always_inline
+# endif
+# endif
+#endif
+
+#include <sched.h>
+#include <time.h>
+
+__BEGIN_DECLS
+
+#include <pthread/pthreadtypes.h>
+
+#include <bits/pthread.h>
+
+/* Possible values for the process shared attribute. */
+#define PTHREAD_PROCESS_PRIVATE __PTHREAD_PROCESS_PRIVATE
+#define PTHREAD_PROCESS_SHARED __PTHREAD_PROCESS_SHARED
+
+
+/* Thread attributes. */
+
+/* Possible values for the inheritsched attribute. */
+#define PTHREAD_EXPLICIT_SCHED __PTHREAD_EXPLICIT_SCHED
+#define PTHREAD_INHERIT_SCHED __PTHREAD_INHERIT_SCHED
+
+/* Possible values for the `contentionscope' attribute. */
+#define PTHREAD_SCOPE_SYSTEM __PTHREAD_SCOPE_SYSTEM
+#define PTHREAD_SCOPE_PROCESS __PTHREAD_SCOPE_PROCESS
+
+/* Possible values for the `detachstate' attribute. */
+#define PTHREAD_CREATE_JOINABLE __PTHREAD_CREATE_JOINABLE
+#define PTHREAD_CREATE_DETACHED __PTHREAD_CREATE_DETACHED
+
+#include <bits/thread-attr.h>
+
+/* Initialize the thread attribute object in *ATTR to the default
+ values. */
+extern int pthread_attr_init (pthread_attr_t *attr);
+
+/* Destroy the thread attribute object in *ATTR. */
+extern int pthread_attr_destroy (pthread_attr_t *attr);
+
+
+/* Return the value of the inheritsched attribute in *ATTR in
+ *INHERITSCHED. */
+extern int pthread_attr_getinheritsched (const pthread_attr_t *__restrict attr,
+ int *__restrict inheritsched);
+
+/* Set the value of the inheritsched attribute in *ATTR to
+ INHERITSCHED. */
+extern int pthread_attr_setinheritsched (pthread_attr_t *attr,
+ int inheritsched);
+
+
+/* Return the value of the schedparam attribute in *ATTR in *PARAM. */
+extern int pthread_attr_getschedparam (const pthread_attr_t *__restrict attr,
+ struct sched_param *__restrict param);
+
+/* Set the value of the schedparam attribute in *ATTR to PARAM. */
+extern int pthread_attr_setschedparam (pthread_attr_t *__restrict attr,
+ const struct sched_param *__restrict param);
+
+
+/* Return the value of the schedpolicy attribute in *ATTR to *POLICY. */
+extern int pthread_attr_getschedpolicy (const pthread_attr_t *__restrict attr,
+ int *__restrict policy);
+
+/* Set the value of the schedpolicy attribute in *ATTR to POLICY. */
+extern int pthread_attr_setschedpolicy (pthread_attr_t *attr,
+ int policy);
+
+
+/* Return the value of the contentionscope attribute in *ATTR in
+ *CONTENTIONSCOPE. */
+extern int pthread_attr_getscope (const pthread_attr_t *__restrict attr,
+ int *__restrict contentionscope);
+
+/* Set the value of the contentionscope attribute in *ATTR to
+ CONTENTIONSCOPE. */
+extern int pthread_attr_setscope (pthread_attr_t *attr,
+ int contentionscope);
+
+
+/* Return the value of the stackaddr attribute in *ATTR in
+ *STACKADDR. */
+extern int pthread_attr_getstackaddr (const pthread_attr_t *__restrict attr,
+ void **__restrict stackaddr);
+
+/* Set the value of the stackaddr attribute in *ATTR to STACKADDR. */
+extern int pthread_attr_setstackaddr (pthread_attr_t *attr,
+ void *stackaddr);
+
+
+#ifdef __USE_XOPEN2K
+/* Return the value of the stackaddr and stacksize attributes in *ATTR
+ in *STACKADDR and *STACKSIZE respectively. */
+extern int pthread_attr_getstack (const pthread_attr_t *__restrict attr,
+ void **__restrict stackaddr,
+ size_t *__restrict stacksize);
+
+/* Set the value of the stackaddr and stacksize attributes in *ATTR to
+ STACKADDR and STACKSIZE respectively. */
+extern int pthread_attr_setstack (pthread_attr_t *attr,
+ void *stackaddr,
+ size_t stacksize);
+#endif
+
+
+/* Return the value of the detachstate attribute in *ATTR in
+ *DETACHSTATE. */
+extern int pthread_attr_getdetachstate (const pthread_attr_t *attr,
+ int *detachstate);
+
+/* Set the value of the detachstate attribute in *ATTR to
+ DETACHSTATE. */
+extern int pthread_attr_setdetachstate (pthread_attr_t *attr,
+ int detachstate);
+
+
+/* Return the value of the guardsize attribute in *ATTR in
+ *GUARDSIZE. */
+extern int pthread_attr_getguardsize (const pthread_attr_t *__restrict attr,
+ size_t *__restrict guardsize);
+
+/* Set the value of the guardsize attribute in *ATTR to GUARDSIZE. */
+extern int pthread_attr_setguardsize (pthread_attr_t *attr,
+ size_t guardsize);
+
+
+/* Return the value of the stacksize attribute in *ATTR in
+ *STACKSIZE. */
+extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict attr,
+ size_t *__restrict stacksize);
+
+/* Set the value of the stacksize attribute in *ATTR to STACKSIZE. */
+extern int pthread_attr_setstacksize (pthread_attr_t *attr,
+ size_t stacksize);
+
+#ifdef __USE_GNU
+/* Initialize thread attribute *ATTR with attributes corresponding to the
+ already running thread THREAD. It shall be called on an uninitialized ATTR
+ and destroyed with pthread_attr_destroy when no longer needed. */
+extern int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr);
+#endif
+
+
+/* Create a thread with attributes given by ATTR, executing
+ START_ROUTINE with argument ARG. */
+extern int pthread_create (pthread_t *__restrict __threadp,
+ __const pthread_attr_t *__restrict __attr,
+ void *(*__start_routine)(void *),
+ void *__restrict __arg);
+
+/* Terminate the current thread and make STATUS available to any
+ thread that might join us. */
+extern void pthread_exit (void *__status) __attribute__ ((noreturn));
+
+/* Make calling thread wait for termination of thread THREAD. Return
+ the exit status of the thread in *STATUS. */
+extern int pthread_join (pthread_t __threadp, void **__status);
+
+/* Indicate that the storage for THREAD can be reclaimed when it
+ terminates. */
+extern int pthread_detach (pthread_t __threadp);
+
+/* Compare thread IDs T1 and T2. Return nonzero if they are equal, 0
+ if they are not. */
+extern int pthread_equal (pthread_t __t1, pthread_t __t2);
+
+# ifdef __USE_EXTERN_INLINES
+
+__extern_inline int
+pthread_equal (pthread_t __t1, pthread_t __t2)
+{
+ return __pthread_equal (__t1, __t2);
+}
+
+# endif /* Use extern inlines. */
+
+
+/* Return the thread ID of the calling thread. */
+extern pthread_t pthread_self (void);
+
+
+/* Mutex attributes. */
+
+#define PTHREAD_PRIO_NONE_NP __PTHREAD_PRIO_NONE
+#define PTHREAD_PRIO_INHERIT_NP __PTHREAD_PRIO_INHERIT
+#define PTHREAD_PRIO_PROTECT_NP __PTHREAD_PRIO_PROTECT
+#ifdef __USE_UNIX98
+#define PTHREAD_PRIO_NONE PTHREAD_PRIO_NONE_NP
+#define PTHREAD_PRIO_INHERIT PTHREAD_PRIO_INHERIT_NP
+#define PTHREAD_PRIO_PROTECT PTHREAD_PRIO_PROTECT_NP
+#endif
+
+#define PTHREAD_MUTEX_TIMED_NP __PTHREAD_MUTEX_TIMED
+#define PTHREAD_MUTEX_ERRORCHECK_NP __PTHREAD_MUTEX_ERRORCHECK
+#define PTHREAD_MUTEX_RECURSIVE_NP __PTHREAD_MUTEX_RECURSIVE
+#ifdef __USE_UNIX98
+#define PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_TIMED_NP
+#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
+#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+#endif
+#ifdef __USE_GNU
+/* For compatibility. */
+#define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_TIMED_NP
+#endif
+
+#include <bits/mutex-attr.h>
+
+/* Initialize the mutex attribute object in *ATTR to the default
+ values. */
+extern int pthread_mutexattr_init(pthread_mutexattr_t *attr);
+
+/* Destroy the mutex attribute structure in *ATTR. */
+extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
+
+
+#ifdef __USE_UNIX98
+/* Return the value of the prioceiling attribute in *ATTR in
+ *PRIOCEILING. */
+extern int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict attr,
+ int *__restrict prioceiling);
+
+/* Set the value of the prioceiling attribute in *ATTR to
+ PRIOCEILING. */
+extern int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
+ int prioceiling);
+
+
+/* Return the value of the protocol attribute in *ATTR in
+ *PROTOCOL. */
+extern int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict attr,
+ int *__restrict protocol);
+
+/* Set the value of the protocol attribute in *ATTR to PROTOCOL. */
+extern int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
+ int protocol);
+#endif
+
+
+/* Return the value of the process shared attribute in *ATTR in
+ *PSHARED. */
+extern int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict attr,
+ int *__restrict pshared);
+
+/* Set the value of the process shared attribute in *ATTR to
+ PSHARED. */
+extern int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
+ int pshared);
+
+
+#ifdef __USE_UNIX98
+/* Return the value of the type attribute in *ATTR in *TYPE. */
+extern int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict attr,
+ int *__restrict type);
+
+/* Set the value of the type attribute in *ATTR to TYPE. */
+extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr,
+ int type);
+#endif
+
+
+/* Mutexes. */
+
+#include <bits/mutex.h>
+
+#define PTHREAD_MUTEX_INITIALIZER __PTHREAD_MUTEX_INITIALIZER
+/* Static initializer for recursive mutexes. */
+
+#ifdef __USE_GNU
+# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
+ __PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+ __PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+#endif
+
+/* Create a mutex with attributes given by ATTR and store it in
+ *__MUTEX. */
+extern int pthread_mutex_init (struct __pthread_mutex *__restrict __mutex,
+ const pthread_mutexattr_t *__restrict attr);
+
+/* Destroy the mutex __MUTEX. */
+extern int pthread_mutex_destroy (struct __pthread_mutex *__mutex);
+
+/* Wait until lock for MUTEX becomes available and lock it. */
+extern int pthread_mutex_lock (pthread_mutex_t *__mutex);
+
+/* Try to lock MUTEX. */
+extern int pthread_mutex_trylock (pthread_mutex_t *__mutex);
+
+#ifdef __USE_XOPEN2K
+/* Try to lock MUTEX, block until *ABSTIME if it is already held. */
+extern int pthread_mutex_timedlock (struct __pthread_mutex *__restrict mutex,
+ const struct timespec *__restrict abstime);
+#endif
+
+/* Unlock MUTEX. */
+extern int pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+/* Transfer ownership of the mutex MUTEX to the thread TID. The
+ caller must own the lock. */
+extern int __pthread_mutex_transfer_np (struct __pthread_mutex *mutex,
+ pthread_t tid);
+
+
+#ifdef __USE_UNIX98
+/* Return the priority ceiling of mutex *MUTEX in *PRIOCEILING. */
+extern int pthread_mutex_getprioceiling (const pthread_mutex_t *__restrict mutex,
+ int *__restrict prioceiling);
+
+/* After acquiring the mutex *MUTEX, set its priority ceiling to PRIO
+ and return the old priority ceiling in *OLDPRIO. Before returning,
+ release the mutex. */
+extern int pthread_mutex_setprioceiling (pthread_mutex_t *__restrict mutex,
+ int prio, int *__restrict oldprio);
+#endif
+
+
+
+/* Condition attributes. */
+
+#include <bits/condition-attr.h>
+
+/* Initialize the condition attribute in *ATTR to the default
+ values. */
+extern int pthread_condattr_init (pthread_condattr_t *attr);
+
+/* Destroy the condition attribute structure in *ATTR. */
+extern int pthread_condattr_destroy (pthread_condattr_t *attr);
+
+
+#ifdef __USE_XOPEN2K
+/* Return the value of the clock attribute in *ATTR in *CLOCK_ID. */
+extern int pthread_condattr_getclock (const pthread_condattr_t *__restrict attr,
+ __clockid_t *__restrict clock_id);
+
+/* Set the value of the clock attribute in *ATTR to CLOCK_ID. */
+extern int pthread_condattr_setclock (pthread_condattr_t *attr,
+ __clockid_t clock_id);
+#endif
+
+
+/* Return the value of the process shared attribute in *ATTR in
+ *PSHARED. */
+extern int pthread_condattr_getpshared (const pthread_condattr_t *__restrict attr,
+ int *__restrict pshared);
+
+/* Set the value of the process shared attribute in *ATTR to
+ PSHARED. */
+extern int pthread_condattr_setpshared (pthread_condattr_t *attr,
+ int pshared);
+
+
+/* Condition variables. */
+
+#include <bits/condition.h>
+
+#define PTHREAD_COND_INITIALIZER __PTHREAD_COND_INITIALIZER
+
+extern int pthread_cond_init (pthread_cond_t *__restrict cond,
+ const pthread_condattr_t *__restrict attr);
+
+extern int pthread_cond_destroy (pthread_cond_t *cond);
+
+/* Unblock at least one of the threads that are blocked on condition
+ variable COND. */
+extern int pthread_cond_signal (pthread_cond_t *__cond);
+
+/* Unblock all threads that are blocked on condition variable COND. */
+extern int pthread_cond_broadcast (pthread_cond_t *__cond);
+
+/* Block on condition variable COND. MUTEX should be held by the
+ calling thread. On success, MUTEX will be held by the calling
+ thread. */
+extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex);
+
+/* Block on condition variable COND. MUTEX should be held by the
+ calling thread. On success, MUTEX will be held by the calling
+ thread. If the time specified by ABSTIME passes, ETIMEDOUT is
+ returned, and MUTEX will nevertheless be held. */
+extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex,
+ __const struct timespec *__restrict __abstime);
+
+
+/* Spin locks. */
+
+#ifdef __USE_XOPEN2K
+
+# include <bits/spin-lock.h>
+
+#define PTHREAD_SPINLOCK_INITIALIZER __PTHREAD_SPIN_LOCK_INITIALIZER
+
+/* Destroy the spin lock object LOCK. */
+extern int pthread_spin_destroy (pthread_spinlock_t *__lock);
+
+/* Initialize the spin lock object LOCK. PSHARED determines whether
+ the spin lock can be operated upon by multiple processes. */
+extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared);
+
+/* Lock the spin lock object LOCK. If the lock is held by another
+ thread spin until it becomes available. */
+extern int pthread_spin_lock (pthread_spinlock_t *__lock);
+
+/* Lock the spin lock object LOCK. Fail if the lock is held by
+ another thread. */
+extern int pthread_spin_trylock (pthread_spinlock_t *__lock);
+
+/* Unlock the spin lock object LOCK. */
+extern int pthread_spin_unlock (pthread_spinlock_t *__lock);
+
+# ifdef __USE_EXTERN_INLINES
+
+# include <bits/spin-lock-inline.h>
+
+__extern_inline int
+pthread_spin_destroy (pthread_spinlock_t *__lock)
+{
+ return __pthread_spin_destroy (__lock);
+}
+
+__extern_inline int
+pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)
+{
+ return __pthread_spin_init (__lock, __pshared);
+}
+
+__extern_inline int
+pthread_spin_lock (pthread_spinlock_t *__lock)
+{
+ return __pthread_spin_lock (__lock);
+}
+
+__extern_inline int
+pthread_spin_trylock (pthread_spinlock_t *__lock)
+{
+ return __pthread_spin_trylock (__lock);
+}
+
+__extern_inline int
+pthread_spin_unlock (pthread_spinlock_t *__lock)
+{
+ return __pthread_spin_unlock (__lock);
+}
+
+# endif /* Use extern inlines. */
+
+#endif /* XPG6. */
+
+
+/* rwlock attributes. */
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+
+#include <bits/rwlock-attr.h>
+
+/* Initialize rwlock attribute object in *ATTR to the default
+ values. */
+extern int pthread_rwlockattr_init (pthread_rwlockattr_t *attr);
+
+/* Destroy the rwlock attribute object in *ATTR. */
+extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr);
+
+
+/* Return the value of the process shared attribute in *ATTR in
+ *PSHARED. */
+extern int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *__restrict attr,
+ int *__restrict pshared);
+
+/* Set the value of the process shared atrribute in *ATTR to
+ PSHARED. */
+extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr,
+ int pshared);
+
+
+/* rwlocks. */
+
+#include <bits/rwlock.h>
+
+#define PTHREAD_RWLOCK_INITIALIZER __PTHREAD_RWLOCK_INITIALIZER
+/* Create a rwlock object with attributes given by ATTR and strore the
+ result in *RWLOCK. */
+extern int pthread_rwlock_init (pthread_rwlock_t *__restrict rwlock,
+ const pthread_rwlockattr_t *__restrict attr);
+
+/* Destroy the rwlock *RWLOCK. */
+extern int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
+
+/* Acquire the rwlock *RWLOCK for reading. */
+extern int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
+
+/* Acquire the rwlock *RWLOCK for reading. */
+extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock);
+
+# ifdef __USE_XOPEN2K
+/* Acquire the rwlock *RWLOCK for reading blocking until *ABSTIME if
+ it is already held. */
+extern int pthread_rwlock_timedrdlock (struct __pthread_rwlock *__restrict rwlock,
+ const struct timespec *__restrict abstime);
+# endif
+
+/* Acquire the rwlock *RWLOCK for writing. */
+extern int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
+
+/* Try to acquire the rwlock *RWLOCK for writing. */
+extern int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock);
+
+# ifdef __USE_XOPEN2K
+/* Acquire the rwlock *RWLOCK for writing blocking until *ABSTIME if
+ it is already held. */
+extern int pthread_rwlock_timedwrlock (struct __pthread_rwlock *__restrict rwlock,
+ const struct timespec *__restrict abstime);
+# endif
+
+/* Release the lock held by the current thread on *RWLOCK. */
+extern int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+
+#endif /* __USE_UNIX98 || __USE_XOPEN2K */
+
+
+
+/* Cancelation. */
+
+/* Register a cleanup handler. */
+extern void pthread_cleanup_push (void (*routine) (void *), void *arg);
+
+/* Unregister a cleanup handler. */
+extern void pthread_cleanup_pop (int execute);
+
+#include <bits/cancelation.h>
+
+#define pthread_cleanup_push(rt, rtarg) __pthread_cleanup_push(rt, rtarg)
+#define pthread_cleanup_pop(execute) __pthread_cleanup_pop(execute)
+
+#define PTHREAD_CANCEL_DISABLE 0
+#define PTHREAD_CANCEL_ENABLE 1
+
+/* Return the calling thread's cancelation state in *OLDSTATE and set
+ its state to STATE. */
+extern int pthread_setcancelstate (int state, int *oldstate);
+
+#define PTHREAD_CANCEL_DEFERRED 0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 1
+
+/* Return the calling thread's cancelation type in *OLDTYPE and set
+ its type to TYPE. */
+extern int pthread_setcanceltype (int type, int *oldtype);
+
+/* Value returned by pthread_join if the target thread was
+ canceled. */
+#define PTHREAD_CANCELED ((void *) -1)
+
+/* Cancel THEAD. */
+extern int pthread_cancel (pthread_t thread);
+
+/* Add an explicit cancelation point. */
+extern void pthread_testcancel (void);
+
+
+/* Barriers attributes. */
+
+#ifdef __USE_XOPEN2K
+
+#include <bits/barrier-attr.h>
+
+/* Initialize barrier attribute object in *ATTR to the default
+ values. */
+extern int pthread_barrierattr_init (pthread_barrierattr_t *attr);
+
+/* Destroy the barrier attribute object in *ATTR. */
+extern int pthread_barrierattr_destroy (pthread_barrierattr_t *attr);
+
+
+/* Return the value of the process shared attribute in *ATTR in
+ *PSHARED. */
+extern int pthread_barrierattr_getpshared (const pthread_barrierattr_t *__restrict attr,
+ int *__restrict pshared);
+
+/* Set the value of the process shared atrribute in *ATTR to
+ PSHARED. */
+extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *attr,
+ int pshared);
+
+
+/* Barriers. */
+
+#include <bits/barrier.h>
+
+/* Returned by pthread_barrier_wait to exactly one thread each time a
+ barrier is passed. */
+#define PTHREAD_BARRIER_SERIAL_THREAD -1
+
+/* Initialize barrier BARRIER. */
+extern int pthread_barrier_init (pthread_barrier_t *__restrict barrier,
+ const pthread_barrierattr_t *__restrict attr,
+ unsigned count);
+
+/* Destroy barrier BARRIER. */
+extern int pthread_barrier_destroy (pthread_barrier_t *barrier);
+
+/* Wait on barrier BARRIER. */
+extern int pthread_barrier_wait (pthread_barrier_t *barrier);
+
+#endif /* __USE_XOPEN2K */
+
+
+
+/* Thread specific data. */
+
+#include <bits/thread-specific.h>
+
+/* Create a thread specific data key in KEY visible to all threads.
+ On thread destruction, DESTRUCTOR shall be called with the thread
+ specific data associate with KEY if it is not NULL. */
+extern int pthread_key_create (pthread_key_t *key,
+ void (*destructor) (void *));
+
+/* Delete the thread specific data key KEY. The associated destructor
+ function is not called. */
+extern int pthread_key_delete (pthread_key_t key);
+
+/* Return the caller thread's thread specific value of KEY. */
+extern void *pthread_getspecific (pthread_key_t key);
+
+/* Set the caller thread's thread specific value of KEY to VALUE. */
+extern int pthread_setspecific (pthread_key_t key, const void *value);
+
+
+/* Dynamic package initialization. */
+
+#include <bits/once.h>
+
+#define PTHREAD_ONCE_INIT __PTHREAD_ONCE_INIT
+
+/* Call INIT_ROUTINE if this function has never been called with
+ *ONCE_CONTROL, otherwise do nothing. */
+extern int pthread_once (pthread_once_t *once_control,
+ void (*init_routine) (void));
+
+
+/* Concurrency. */
+
+#ifdef __USE_UNIX98
+/* Set the desired concurrency level to NEW_LEVEL. */
+extern int pthread_setconcurrency (int new_level);
+
+/* Get the current concurrency level. */
+extern int pthread_getconcurrency (void);
+#endif
+
+
+/* Forking. */
+
+/* Register the function PREPARE to be run before the process forks,
+ the function PARENT to be run after a fork in the parent and the
+ function CHILD to be run in the child after the fork. If no
+ handling is desired then any of PREPARE, PARENT and CHILD may be
+ NULL. The prepare handles will be called in the reverse order
+ which they were registered and the parent and child handlers in the
+ order in which they were registered. */
+extern int pthread_atfork (void (*prepare) (void), void (*parent) (void),
+ void (*child) (void));
+
+
+/* Signals (should be in <signal.h>). */
+
+/* Send signal SIGNO to thread THREAD. */
+extern int pthread_kill (pthread_t thread, int signo);
+
+
+/* Time. */
+
+#ifdef __USE_XOPEN2K
+/* Return the thread cpu clock. */
+extern int pthread_getcpuclockid (pthread_t thread, __clockid_t *clock);
+#endif
+
+
+/* Scheduling. */
+
+/* Return thread THREAD's scheduling paramters. */
+extern int pthread_getschedparam (pthread_t thread, int *__restrict policy,
+ struct sched_param *__restrict param);
+
+/* Set thread THREAD's scheduling paramters. */
+extern int pthread_setschedparam (pthread_t thread, int policy,
+ const struct sched_param *param);
+
+/* Set thread THREAD's scheduling priority. */
+extern int pthread_setschedprio (pthread_t thread, int prio);
+
+#ifdef __USE_GNU
+/* Yield the processor to another thread or process.
+ This function is similar to the POSIX `sched_yield' function but
+ might be differently implemented in the case of a m-on-n thread
+ implementation. */
+extern int pthread_yield (void);
+#endif
+
+
+/* Kernel-specific interfaces. */
+
+#include <bits/pthread-np.h>
+
+
+__END_DECLS
+
+#endif /* pthread.h */
diff --git a/libpthread/include/pthread/pthreadtypes.h b/libpthread/include/pthread/pthreadtypes.h
new file mode 100644
index 00000000..33bd0099
--- /dev/null
+++ b/libpthread/include/pthread/pthreadtypes.h
@@ -0,0 +1,125 @@
+/* Copyright (C) 2000, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * POSIX Threads Extension: ??? <pthreadtypes.h>
+ */
+
+#ifndef _PTHREADTYPES_H
+#define _PTHREADTYPES_H 1
+
+#include <features.h>
+
+#include <bits/types.h>
+
+__BEGIN_DECLS
+
+#include <bits/pthread.h>
+typedef __pthread_t pthread_t;
+
+/* Possible values for the process shared attribute. */
+enum __pthread_process_shared
+ {
+ __PTHREAD_PROCESS_PRIVATE = 0,
+ __PTHREAD_PROCESS_SHARED
+ };
+
+/* Possible values for the inheritsched attribute. */
+enum __pthread_inheritsched
+ {
+ __PTHREAD_EXPLICIT_SCHED = 0,
+ __PTHREAD_INHERIT_SCHED
+ };
+
+/* Possible values for the `contentionscope' attribute. */
+enum __pthread_contentionscope
+ {
+ __PTHREAD_SCOPE_SYSTEM = 0,
+ __PTHREAD_SCOPE_PROCESS
+ };
+
+/* Possible values for the `detachstate' attribute. */
+enum __pthread_detachstate
+ {
+ __PTHREAD_CREATE_JOINABLE = 0,
+ __PTHREAD_CREATE_DETACHED
+ };
+
+#include <bits/thread-attr.h>
+typedef struct __pthread_attr pthread_attr_t;
+
+enum __pthread_mutex_protocol
+ {
+ __PTHREAD_PRIO_NONE= 0,
+ __PTHREAD_PRIO_INHERIT,
+ __PTHREAD_PRIO_PROTECT
+ };
+
+enum __pthread_mutex_type
+ {
+ __PTHREAD_MUTEX_TIMED,
+ __PTHREAD_MUTEX_ERRORCHECK,
+ __PTHREAD_MUTEX_RECURSIVE
+ };
+
+#include <bits/mutex-attr.h>
+typedef struct __pthread_mutexattr pthread_mutexattr_t;
+
+#include <bits/mutex.h>
+typedef struct __pthread_mutex pthread_mutex_t;
+
+#include <bits/condition-attr.h>
+typedef struct __pthread_condattr pthread_condattr_t;
+
+#include <bits/condition.h>
+typedef struct __pthread_cond pthread_cond_t;
+
+#ifdef __USE_XOPEN2K
+# include <bits/spin-lock.h>
+typedef __pthread_spinlock_t pthread_spinlock_t;
+#endif /* XPG6. */
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+
+#include <bits/rwlock-attr.h>
+typedef struct __pthread_rwlockattr pthread_rwlockattr_t;
+
+#include <bits/rwlock.h>
+typedef struct __pthread_rwlock pthread_rwlock_t;
+
+#endif /* __USE_UNIX98 || __USE_XOPEN2K */
+
+#ifdef __USE_XOPEN2K
+
+#include <bits/barrier-attr.h>
+typedef struct __pthread_barrierattr pthread_barrierattr_t;
+
+#include <bits/barrier.h>
+typedef struct __pthread_barrier pthread_barrier_t;
+
+#endif /* __USE_XOPEN2K */
+
+#include <bits/thread-specific.h>
+typedef __pthread_key pthread_key_t;
+
+#include <bits/once.h>
+typedef struct __pthread_once pthread_once_t;
+
+__END_DECLS
+
+#endif /* pthreadtypes.h */
diff --git a/libpthread/include/semaphore.h b/libpthread/include/semaphore.h
new file mode 100644
index 00000000..657e796e
--- /dev/null
+++ b/libpthread/include/semaphore.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _SEMAPHORE_H
+#define _SEMAPHORE_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#include <bits/semaphore.h>
+
+#define SEM_FAILED ((void *) 0)
+
+typedef struct __semaphore sem_t;
+
+/* Initialize semaphore *SEM with value VALUE. */
+extern int sem_init (sem_t *sem, int pshared, unsigned value);
+
+/* Destroy semaphore *SEM created with sem_init. */
+extern int sem_destroy (sem_t *sem);
+
+/* Store the value of semaphore *SEM in *VALUE. */
+extern int sem_getvalue (sem_t *__restrict sem, int *__restrict value);
+
+/* Perform a down operation on semaphore *SEM. */
+extern int sem_wait (sem_t *sem);
+
+/* Perform a down operation on semaphore *SEM if it can be done so
+ without blocking. */
+extern int sem_trywait (sem_t *sem);
+
+#ifdef __USE_XOPEN2K
+/* Perform a down operation on semaphore *SEM but don't wait longer
+ than TIMEOUT. */
+extern int sem_timedwait (sem_t *__restrict sem,
+ const struct timespec *__restrict timeout);
+#endif
+
+/* Perform an up operation on semaphore *SEM. */
+extern int sem_post (sem_t *sem);
+
+/* Open a named semaphore. */
+extern sem_t *sem_open (const char *name, int open_flags, ...);
+
+/* Close a semaphore returned by sem_open. */
+extern int sem_close (sem_t *sem);
+
+/* Unlink a named semaphore. */
+extern int sem_unlink (const char *name);
+
+__END_DECLS
+
+#endif /* semaphore.h */
diff --git a/libpthread/include/set-hooks.h b/libpthread/include/set-hooks.h
new file mode 100644
index 00000000..9ed71b32
--- /dev/null
+++ b/libpthread/include/set-hooks.h
@@ -0,0 +1,72 @@
+/* Macros for using symbol sets for running lists of functions.
+ Copyright (C) 1994, 1995, 1997, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SET_HOOKS_H
+#define _SET_HOOKS_H 1
+
+#define __need_size_t
+#include <stddef.h>
+// #include <sys/cdefs.h>
+#define __unbounded
+
+#ifdef symbol_set_define
+/* Define a hook variable called NAME. Functions put on this hook take
+ arguments described by PROTO. Use `text_set_element (NAME, FUNCTION)'
+ from gnu-stabs.h to add a function to the hook. */
+
+# define DEFINE_HOOK(NAME, PROTO) \
+ typedef void __##NAME##_hook_function_t PROTO; \
+ symbol_set_define (NAME)
+
+# define DECLARE_HOOK(NAME, PROTO) \
+ typedef void __##NAME##_hook_function_t PROTO;\
+ symbol_set_declare (NAME)
+
+/* Run all the functions hooked on the set called NAME.
+ Each function is called like this: `function ARGS'. */
+
+# define RUN_HOOK(NAME, ARGS) \
+do { \
+ void *const *__unbounded ptr; \
+ for (ptr = symbol_set_first_element (NAME); \
+ ! symbol_set_end_p (NAME, ptr); ++ptr) \
+ (*(__##NAME##_hook_function_t *) *ptr) ARGS; \
+} while (0)
+
+/* Define a hook variable with NAME and PROTO, and a function called RUNNER
+ which calls each function on the hook in turn, with ARGS. */
+
+# define DEFINE_HOOK_RUNNER(name, runner, proto, args) \
+DEFINE_HOOK (name, proto); \
+extern void runner proto; void runner proto { RUN_HOOK (name, args); }
+
+#else
+
+/* The system does not provide necessary support for this. */
+# define DEFINE_HOOK(NAME, PROTO)
+
+# define DECLARE_HOOK(NAME, PROTO)
+
+# define RUN_HOOK(NAME, ARGS)
+
+# define DEFINE_HOOK_RUNNER(name, runner, proto, args)
+
+#endif
+
+#endif /* set-hooks.h */
diff --git a/libpthread/libpthread.a b/libpthread/libpthread.a
new file mode 100644
index 00000000..d0e689e9
--- /dev/null
+++ b/libpthread/libpthread.a
@@ -0,0 +1,20 @@
+/* pthread initializer is weak in glibc. It must be included if glibc
+ is to start threading. */
+EXTERN(_cthread_init_routine)
+
+/* Weak references in glibc that must be filled if glibc is to be
+ thread safe. */
+EXTERN(cthread_detach)
+EXTERN(cthread_fork)
+EXTERN(cthread_keycreate)
+EXTERN(cthread_getspecific)
+EXTERN(__libc_getspecific)
+EXTERN(cthread_setspecific)
+EXTERN(__mutex_lock_solid)
+EXTERN(__mutex_unlock_solid)
+/* For libio stream locking. */
+EXTERN(_cthreads_flockfile)
+EXTERN(_cthreads_funlockfile)
+EXTERN(_cthreads_ftrylockfile)
+
+GROUP(-lpthread2 -lihash)
diff --git a/libpthread/libpthread_pic.a b/libpthread/libpthread_pic.a
new file mode 100644
index 00000000..5673b4e7
--- /dev/null
+++ b/libpthread/libpthread_pic.a
@@ -0,0 +1,20 @@
+/* pthread initializer is weak in glibc. It must be included if glibc
+ is to start threading. */
+EXTERN(_cthread_init_routine)
+
+/* Weak references in glibc that must be filled if glibc is to be
+ thread safe. */
+EXTERN(cthread_detach)
+EXTERN(cthread_fork)
+EXTERN(cthread_keycreate)
+EXTERN(cthread_getspecific)
+EXTERN(__libc_getspecific)
+EXTERN(cthread_setspecific)
+EXTERN(__mutex_lock_solid)
+EXTERN(__mutex_unlock_solid)
+/* For libio stream locking. */
+EXTERN(_cthreads_flockfile)
+EXTERN(_cthreads_funlockfile)
+EXTERN(_cthreads_ftrylockfile)
+
+GROUP(-lpthread2_pic -lihash_pic)
diff --git a/libpthread/lockfile.c b/libpthread/lockfile.c
new file mode 100644
index 00000000..040cbfb4
--- /dev/null
+++ b/libpthread/lockfile.c
@@ -0,0 +1,65 @@
+/* lockfile - Handle locking and unlocking of streams. Hurd cthreads version.
+ Copyright (C) 2000,01,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <cthreads.h>
+#include <pthread.h> /* Must come before <stdio.h>! */
+#include <stdio.h>
+
+#ifdef _STDIO_USES_IOSTREAM
+
+void
+_cthreads_flockfile (_IO_FILE *fp)
+{
+ _IO_lock_lock (*fp->_lock);
+}
+
+void
+_cthreads_funlockfile (_IO_FILE *fp)
+{
+ _IO_lock_unlock (*fp->_lock);
+}
+
+int
+_cthreads_ftrylockfile (_IO_FILE *fp)
+{
+ return __libc_lock_trylock_recursive (*fp->_lock);
+}
+
+# undef _IO_flockfile
+# undef _IO_funlockfile
+# undef _IO_ftrylockfile
+# undef flockfile
+# undef funlockfile
+# undef ftrylockfile
+
+void _IO_flockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_flockfile")));
+void _IO_funlockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_funlockfile")));
+int _IO_ftrylockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_ftrylockfile")));
+
+void flockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_flockfile")));
+void funlockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_funlockfile")));
+int ftrylockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_ftrylockfile")));
+
+#endif /* _STDIO_USES_IOSTREAM */
diff --git a/libpthread/not-in-libc.h b/libpthread/not-in-libc.h
new file mode 100644
index 00000000..516d4d13
--- /dev/null
+++ b/libpthread/not-in-libc.h
@@ -0,0 +1,11 @@
+#define __mach_port_insert_right mach_port_insert_right
+#define __mach_port_allocate mach_port_allocate
+#define __mig_init mig_init
+#define __thread_create thread_create
+#define __thread_get_state thread_get_state
+#define __thread_resume thread_resume
+#define __thread_set_state thread_set_state
+#define __thread_terminate thread_terminate
+#define __vm_allocate vm_allocate
+#define __vm_deallocate vm_deallocate
+#define __sched_yield sched_yield
diff --git a/libpthread/pt-yield.c b/libpthread/pt-yield.c
new file mode 100644
index 00000000..27848bb7
--- /dev/null
+++ b/libpthread/pt-yield.c
@@ -0,0 +1,26 @@
+/* Yield the processor to another thread or process.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <sched.h>
+
+int pthread_yield(void)
+{
+ return sched_yield ();
+}
diff --git a/libpthread/pthread/Versions b/libpthread/pthread/Versions
new file mode 100644
index 00000000..e4b4e8bf
--- /dev/null
+++ b/libpthread/pthread/Versions
@@ -0,0 +1,15 @@
+libc {
+ GLIBC_2.2 {
+ # XXX
+ __vm_deallocate; __mach_port_insert_right; __mach_reply_port;
+ __mig_init; __vm_allocate;
+
+ # functions used in inline functions or macros
+ __pthread_spin_destroy; __pthread_spin_init; __pthread_spin_lock;
+ _pthread_spin_lock; __pthread_spin_trylock; __pthread_spin_unlock;
+
+ # p*
+ pthread_spin_destroy; pthread_spin_init; pthread_spin_lock;
+ pthread_spin_trylock; pthread_spin_unlock;
+ }
+}
diff --git a/libpthread/pthread/cthreads-compat.c b/libpthread/pthread/cthreads-compat.c
new file mode 100644
index 00000000..e0536ef2
--- /dev/null
+++ b/libpthread/pthread/cthreads-compat.c
@@ -0,0 +1,104 @@
+/* Compatibility routines for cthreads.
+ Copyright (C) 2000, 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <pthread.h>
+
+typedef void *cthread_t;
+typedef void *(*cthread_fn_t) (void *arg);
+typedef int cthread_key_t;
+
+#define CTHREAD_KEY_INVALID (cthread_key_t) -1
+
+void
+cthread_detach (cthread_t thread)
+{
+ int err;
+
+ err = pthread_detach ((pthread_t) thread);
+ assert_perror (err);
+}
+
+cthread_t
+cthread_fork (cthread_fn_t func, void *arg)
+{
+ pthread_t thread;
+ int err;
+
+ err = pthread_create (&thread, NULL, func, arg);
+ assert_perror (err);
+
+ return (cthread_t) thread;
+}
+
+int
+cthread_keycreate (cthread_key_t *key)
+{
+ error_t err;
+
+ err = pthread_key_create (key, 0);
+ if (err)
+ {
+ errno = err;
+ *key = CTHREAD_KEY_INVALID;
+ err = -1;
+ }
+
+ return err;
+}
+
+int
+cthread_getspecific (cthread_key_t key, void **val)
+{
+ *val = pthread_getspecific (key);
+ return 0;
+}
+
+void *
+__libc_getspecific (cthread_key_t key)
+{
+ return pthread_getspecific (key);
+}
+
+int
+cthread_setspecific (cthread_key_t key, void *val)
+{
+ error_t err;
+
+ err = pthread_setspecific (key, (const void *) val);
+ if (err)
+ {
+ errno = err;
+ err = -1;
+ }
+
+ return err;
+}
+
+void
+__mutex_lock_solid (void *lock)
+{
+ __pthread_mutex_lock (lock);
+}
+
+void
+__mutex_unlock_solid (void *lock)
+{
+ __pthread_mutex_unlock (lock);
+}
diff --git a/libpthread/pthread/pt-alloc.c b/libpthread/pthread/pt-alloc.c
new file mode 100644
index 00000000..6af2da92
--- /dev/null
+++ b/libpthread/pthread/pt-alloc.c
@@ -0,0 +1,215 @@
+/* Allocate a new thread structure.
+ Copyright (C) 2000, 2002, 2005, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+/* This braindamage is necessary because the standard says that some
+ of the threads functions "shall fail" if "No thread could be found
+ corresponding to that specified by the given thread ID." */
+
+/* Thread ID lookup table. */
+struct __pthread **__pthread_threads;
+
+/* The size of the thread ID lookup table. */
+int __pthread_max_threads;
+
+/* The total number of thread IDs currently in use, or on the list of
+ available thread IDs. */
+int __pthread_num_threads;
+
+/* A lock for the table, and the other variables above. */
+pthread_rwlock_t __pthread_threads_lock;
+
+/* List of thread structures corresponding to free thread IDs. */
+struct __pthread *__pthread_free_threads;
+pthread_mutex_t __pthread_free_threads_lock;
+
+static inline error_t
+initialize_pthread (struct __pthread *new, int recycling)
+{
+ error_t err;
+
+ err = __pthread_init_specific (new);
+ if (err)
+ return err;
+
+ new->cancel_state = PTHREAD_CANCEL_ENABLE;
+ new->cancel_type = PTHREAD_CANCEL_DEFERRED;
+ new->cancel_pending = 0;
+
+ if (recycling)
+ /* Since we are recycling PTHREAD, we can assume certains things
+ about PTHREAD's current state and save some cycles by not
+ rewriting the memory. */
+ return 0;
+
+ new->stack = 0;
+
+ new->state_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
+ new->state_cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
+
+ new->cancelation_handlers = 0;
+
+ new->next = 0;
+ new->prevp = 0;
+
+ return 0;
+}
+
+
+/* Allocate a new thread structure and its pthread thread ID (but not
+ a kernel thread). */
+int
+__pthread_alloc (struct __pthread **pthread)
+{
+ error_t err;
+
+ struct __pthread *new;
+ struct __pthread **threads;
+ struct __pthread **old_threads;
+ int max_threads;
+ int new_max_threads;
+
+ pthread_mutex_lock (&__pthread_free_threads_lock);
+ for (new = __pthread_free_threads; new; new = new->next)
+ {
+ /* There is no need to take NEW->STATE_LOCK: if NEW is on this
+ list, then it is protected by __PTHREAD_FREE_THREADS_LOCK
+ except in __pthread_dealloc where after it is added to the
+ list (with the lock held), it drops the lock and then sets
+ NEW->STATE and immediately stops using NEW. */
+ if (new->state == PTHREAD_TERMINATED)
+ {
+ __pthread_dequeue (new);
+ break;
+ }
+ }
+ pthread_mutex_unlock (&__pthread_free_threads_lock);
+
+ if (new)
+ {
+ /* The thread may still be running. Make sure it is stopped.
+ If this is the case, then the thread is either at the end of
+ __pthread_dealloc or in __pthread_thread_halt. In both
+ cases, we are interrupt it. */
+ __pthread_thread_halt (new);
+
+ err = initialize_pthread (new, 1);
+ if (! err)
+ *pthread = new;
+ return err;
+ }
+
+ /* Allocate a new thread structure. */
+ new = malloc (sizeof (struct __pthread));
+ if (new == NULL)
+ return ENOMEM;
+
+ err = initialize_pthread (new, 0);
+ if (err)
+ {
+ free (new);
+ return err;
+ }
+
+ retry:
+ pthread_rwlock_wrlock (&__pthread_threads_lock);
+
+ if (__pthread_num_threads < __pthread_max_threads)
+ {
+ /* We have a free slot. Use the slot number plus one as the
+ thread ID for the new thread. */
+ new->thread = 1 + __pthread_num_threads++;
+ __pthread_threads[new->thread - 1] = NULL;
+
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ *pthread = new;
+ return 0;
+ }
+#ifdef PTHREAD_THREADS_MAX
+ else if (__pthread_num_threads >= PTHREAD_THREADS_MAX)
+ {
+ /* We have reached the limit on the number of threads per process. */
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ free (new);
+ return EAGAIN;
+ }
+#endif
+
+ /* We are going to enlarge the threads table. Save its current
+ size. We're going to release the lock before doing the necessary
+ memory allocation, since that's a potentially blocking operation. */
+ max_threads = __pthread_max_threads;
+
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ /* Allocate a new lookup table that's twice as large. */
+ new_max_threads
+ = max_threads > 0 ? max_threads * 2 : _POSIX_THREAD_THREADS_MAX;
+ threads = malloc (new_max_threads * sizeof (struct __pthread *));
+ if (threads == NULL)
+ {
+ free (new);
+ return ENOMEM;
+ }
+
+ pthread_rwlock_wrlock (&__pthread_threads_lock);
+
+ /* Check if nobody else has already enlarged the table. */
+ if (max_threads != __pthread_max_threads)
+ {
+ /* Yep, they did. */
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ /* Free the newly allocated table and try again to allocate a slot. */
+ free (threads);
+ goto retry;
+ }
+
+ /* Copy over the contents of the old table. */
+ memcpy (threads, __pthread_threads,
+ __pthread_max_threads * sizeof (struct __pthread *));
+
+ /* Save the location of the old table. We want to deallocate its
+ storage after we released the lock. */
+ old_threads = __pthread_threads;
+
+ /* Replace the table with the new one. */
+ __pthread_max_threads = new_max_threads;
+ __pthread_threads = threads;
+
+ /* And allocate ourselves one of the newly created slots. */
+ new->thread = 1 + __pthread_num_threads++;
+ __pthread_threads[new->thread - 1] = NULL;
+
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ free (old_threads);
+
+ *pthread = new;
+ return 0;
+}
diff --git a/libpthread/pthread/pt-cancel.c b/libpthread/pthread/pt-cancel.c
new file mode 100644
index 00000000..d19c557d
--- /dev/null
+++ b/libpthread/pthread/pt-cancel.c
@@ -0,0 +1,40 @@
+/* Cancel a thread.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+int
+pthread_cancel (pthread_t t)
+{
+ int err = 0;
+ struct __pthread *p;
+
+ p = __pthread_getid (t);
+ if (! p)
+ return ESRCH;
+
+ p->cancel_pending = 1;
+ if (p->cancel_state == PTHREAD_CANCEL_ENABLE
+ && p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
+ err = __pthread_do_cancel (p);
+
+ return err;
+}
diff --git a/libpthread/pthread/pt-cleanup.c b/libpthread/pthread/pt-cleanup.c
new file mode 100644
index 00000000..58865aa4
--- /dev/null
+++ b/libpthread/pthread/pt-cleanup.c
@@ -0,0 +1,28 @@
+/* Add a cancelation handler to the stack.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+struct __pthread_cancelation_handler **
+__pthread_get_cleanup_stack (void)
+{
+ return &_pthread_self ()->cancelation_handlers;
+}
diff --git a/libpthread/pthread/pt-create.c b/libpthread/pthread/pt-create.c
new file mode 100644
index 00000000..346c6979
--- /dev/null
+++ b/libpthread/pthread/pt-create.c
@@ -0,0 +1,217 @@
+/* Thread creation.
+ Copyright (C) 2000, 2002, 2005, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include <bits/atomic.h>
+
+#include <pt-internal.h>
+
+#ifdef HAVE_USELOCALE
+# include <locale.h>
+#endif
+
+/* The total number of pthreads currently active. This is defined
+ here since it would be really stupid to have a threads-using
+ program that doesn't call `pthread_create'. */
+__atomic_t __pthread_total;
+
+
+/* The entry-point for new threads. */
+static void
+entry_point (void *(*start_routine)(void *), void *arg)
+{
+#ifdef HAVE_USELOCALE
+ /* A fresh thread needs to be bound to the global locale. */
+ uselocale (LC_GLOBAL_LOCALE);
+#endif
+
+ __pthread_startup ();
+
+ pthread_exit (start_routine (arg));
+}
+
+/* Create a thread with attributes given by ATTR, executing
+ START_ROUTINE with argument ARG. */
+int
+pthread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ int err;
+ struct __pthread *pthread;
+
+ err = __pthread_create_internal (&pthread, attr, start_routine, arg);
+ if (! err)
+ *thread = pthread->thread;
+
+ return err;
+}
+
+/* Internal version of pthread_create. See comment in
+ pt-internal.h. */
+int
+__pthread_create_internal (struct __pthread **thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ int err;
+ struct __pthread *pthread;
+ const struct __pthread_attr *setup;
+ sigset_t sigset;
+
+ /* Allocate a new thread structure. */
+ err = __pthread_alloc (&pthread);
+ if (err)
+ goto failed;
+
+ /* Use the default attributes if ATTR is NULL. */
+ setup = attr ? attr : &__pthread_default_attr;
+
+ /* Initialize the thread state. */
+ pthread->state = (setup->detachstate == PTHREAD_CREATE_DETACHED
+ ? PTHREAD_DETACHED : PTHREAD_JOINABLE);
+
+ /* If the user supplied a stack, it is not our responsibility to
+ setup a stack guard. */
+ if (setup->stackaddr)
+ pthread->guardsize = 0;
+ else
+ pthread->guardsize = (setup->guardsize <= setup->stacksize
+ ? setup->guardsize : setup->stacksize);
+
+ /* Find a stack. There are several scenarios: if a detached thread
+ kills itself, it has no way to deallocate its stack, thus it
+ leaves PTHREAD->stack set to true. We try to reuse it here,
+ however, if the user supplied a stack, we cannot use the old one.
+ Right now, we simply deallocate it. */
+ if (pthread->stack)
+ {
+ if (setup->stackaddr != __pthread_default_attr.stackaddr)
+ {
+ __pthread_stack_dealloc (pthread->stackaddr,
+ pthread->stacksize);
+ pthread->stackaddr = setup->stackaddr;
+ pthread->stacksize = setup->stacksize;
+ }
+ }
+ else
+ {
+ err = __pthread_stack_alloc (&pthread->stackaddr,
+ setup->stacksize);
+ if (err)
+ goto failed_stack_alloc;
+
+ pthread->stacksize = setup->stacksize;
+ pthread->stack = 1;
+ }
+
+ /* Allocate the kernel thread and other required resources. */
+ err = __pthread_thread_alloc (pthread);
+ if (err)
+ goto failed_thread_alloc;
+
+#ifdef ENABLE_TLS
+ pthread->tcb = _dl_allocate_tls (NULL);
+ if (!pthread->tcb)
+ goto failed_thread_tls_alloc;
+ pthread->tcb->tcb = pthread->tcb;
+#endif /* ENABLE_TLS */
+
+ /* And initialize the rest of the machine context. This may include
+ additional machine- and system-specific initializations that
+ prove convenient. */
+ err = __pthread_setup (pthread, entry_point, start_routine, arg);
+ if (err)
+ goto failed_setup;
+
+ /* Initialize the system-specific signal state for the new
+ thread. */
+ err = __pthread_sigstate_init (pthread);
+ if (err)
+ goto failed_sigstate;
+
+ /* Set the new thread's signal mask and set the pending signals to
+ empty. POSIX says: "The signal mask shall be inherited from the
+ creating thread. The set of signals pending for the new thread
+ shall be empty." If the currnet thread is not a pthread then we
+ just inherit the process' sigmask. */
+ if (__pthread_num_threads == 1)
+ err = sigprocmask (0, 0, &sigset);
+ else
+ err = __pthread_sigstate (_pthread_self (), 0, 0, &sigset, 0);
+ assert_perror (err);
+
+ err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1);
+ assert_perror (err);
+
+ /* Increase the total number of threads. We do this before actually
+ starting the new thread, since the new thread might immediately
+ call `pthread_exit' which decreases the number of threads and
+ calls `exit' if the number of threads reaches zero. Increasing
+ the number of threads from within the new thread isn't an option
+ since this thread might return and call `pthread_exit' before the
+ new thread runs. */
+ __atomic_inc (&__pthread_total);
+
+ /* Store a pointer to this thread in the thread ID lookup table. We
+ could use __thread_setid, however, we only lock for reading as no
+ other thread should be using this entry (we also assume that the
+ store is atomic). */
+ pthread_rwlock_rdlock (&__pthread_threads_lock);
+ __pthread_threads[pthread->thread - 1] = pthread;
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+ /* At this point it is possible to guess our pthread ID. We have to
+ make sure that all functions taking a pthread_t argument can
+ handle the fact that this thread isn't really running yet. */
+
+ /* Schedule the new thread. */
+ err = __pthread_thread_start (pthread);
+ if (err)
+ goto failed_starting;
+
+ /* At this point the new thread is up and running. */
+
+ *thread = pthread;
+
+ return 0;
+
+ failed_starting:
+ __pthread_setid (pthread->thread, NULL);
+ __atomic_dec (&__pthread_total);
+ failed_sigstate:
+ __pthread_sigstate_destroy (pthread);
+ failed_setup:
+#ifdef ENABLE_TLS
+ _dl_deallocate_tls (pthread->tcb, 1);
+ failed_thread_tls_alloc:
+#endif /* ENABLE_TLS */
+ __pthread_thread_dealloc (pthread);
+ __pthread_thread_halt (pthread);
+ failed_thread_alloc:
+ __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
+ pthread->stack = 0;
+ failed_stack_alloc:
+ __pthread_dealloc (pthread);
+ failed:
+ return err;
+}
diff --git a/libpthread/pthread/pt-dealloc.c b/libpthread/pthread/pt-dealloc.c
new file mode 100644
index 00000000..92fe1fda
--- /dev/null
+++ b/libpthread/pthread/pt-dealloc.c
@@ -0,0 +1,64 @@
+/* Deallocate a thread structure.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <pt-internal.h>
+
+/* List of thread structures corresponding to free thread IDs. */
+extern struct __pthread *__pthread_free_threads;
+extern pthread_mutex_t __pthread_free_threads_lock;
+
+
+/* Deallocate the thread structure for PTHREAD. */
+void
+__pthread_dealloc (struct __pthread *pthread)
+{
+ assert (pthread->state != PTHREAD_TERMINATED);
+
+ /* Withdraw this thread from the thread ID lookup table. */
+ __pthread_setid (pthread->thread, NULL);
+
+ /* Mark the thread as terminated. We broadcast the condition
+ here to prevent pthread_join from waiting for this thread to
+ exit where it was never really started. Such a call to
+ pthread_join is completely bogus, but unfortunately allowed
+ by the standards. */
+ __pthread_mutex_lock (&pthread->state_lock);
+ if (pthread->state != PTHREAD_EXITED)
+ pthread_cond_broadcast (&pthread->state_cond);
+ __pthread_mutex_unlock (&pthread->state_lock);
+
+ /* We do not actually deallocate the thread structure, but add it to
+ a list of re-usable thread structures. */
+ pthread_mutex_lock (&__pthread_free_threads_lock);
+ __pthread_enqueue (&__pthread_free_threads, pthread);
+ pthread_mutex_unlock (&__pthread_free_threads_lock);
+
+ /* Setting PTHREAD->STATE to PTHREAD_TERMINATED makes this TCB
+ available for reuse. After that point, we can no longer assume
+ that PTHREAD is valid.
+
+ Note that it is safe to not lock this update to PTHREAD->STATE:
+ the only way that it can now be accessed is in __pthread_alloc,
+ which reads this variable. */
+ pthread->state = PTHREAD_TERMINATED;
+}
diff --git a/libpthread/pthread/pt-detach.c b/libpthread/pthread/pt-detach.c
new file mode 100644
index 00000000..1e42c452
--- /dev/null
+++ b/libpthread/pthread/pt-detach.c
@@ -0,0 +1,92 @@
+/* Detach a thread.
+ Copyright (C) 2000, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+
+#include <pt-internal.h>
+
+/* Indicate that the storage for THREAD can be reclaimed when it
+ terminates. */
+int
+pthread_detach (pthread_t thread)
+{
+ struct __pthread *pthread;
+ int err = 0;
+
+ /* Lookup the thread structure for THREAD. */
+ pthread = __pthread_getid (thread);
+ if (pthread == NULL)
+ return ESRCH;
+
+ __pthread_mutex_lock (&pthread->state_lock);
+
+ switch (pthread->state)
+ {
+ case PTHREAD_JOINABLE:
+ /* THREAD still running. Mark it as detached such that its
+ resources can be reclaimed as soon as the thread exits. */
+ pthread->state = PTHREAD_DETACHED;
+
+ /* Broadcast the condition. This will make threads that are
+ waiting to join THREAD continue with hopefully disastrous
+ consequences instead of blocking indefinitely. */
+ pthread_cond_broadcast (&pthread->state_cond);
+ __pthread_mutex_unlock (&pthread->state_lock);
+ break;
+
+ case PTHREAD_EXITED:
+ /* THREAD has already exited. Make sure that nobody can
+ reference it anymore, and mark it as terminated. */
+
+ __pthread_mutex_unlock (&pthread->state_lock);
+
+ /* Make sure the thread is not running before we remove its
+ stack. (The only possibility is that it is in a call to
+ __pthread_thread_halt itself, but that is enough to cause a
+ sigsegv.) */
+ __pthread_thread_halt (pthread);
+
+ /* Destroy the stack, the kernel resources and the control
+ block. */
+ assert (pthread->stack);
+ __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
+ pthread->stack = 0;
+
+ __pthread_thread_dealloc (pthread);
+
+ __pthread_dealloc (pthread);
+ break;
+
+ case PTHREAD_TERMINATED:
+ /* Pretend THREAD wasn't there in the first place. */
+ __pthread_mutex_unlock (&pthread->state_lock);
+ err = ESRCH;
+ break;
+
+ default:
+ /* Thou shalt not detach non-joinable threads! */
+ __pthread_mutex_unlock (&pthread->state_lock);
+ err = EINVAL;
+ break;
+ }
+
+ return err;
+}
diff --git a/libpthread/pthread/pt-exit.c b/libpthread/pthread/pt-exit.c
new file mode 100644
index 00000000..c01efda0
--- /dev/null
+++ b/libpthread/pthread/pt-exit.c
@@ -0,0 +1,122 @@
+/* Thread termination.
+ Copyright (C) 2000, 2002, 2005, 2007, 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <pt-internal.h>
+
+#include <bits/atomic.h>
+
+
+/* Terminate the current thread and make STATUS available to any
+ thread that might join it. */
+void
+pthread_exit (void *status)
+{
+ struct __pthread *self = _pthread_self ();
+ struct __pthread_cancelation_handler **handlers;
+ int oldstate;
+
+ /* Run any cancelation handlers. According to POSIX, the
+ cancellation cleanup handlers should be called with cancellation
+ disabled. */
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
+
+ for (handlers = __pthread_get_cleanup_stack ();
+ *handlers;
+ *handlers = (*handlers)->next)
+ (*handlers)->handler ((*handlers)->arg);
+
+ pthread_setcancelstate (oldstate, &oldstate);
+
+ /* Destory any thread specific data. */
+ __pthread_destroy_specific (self);
+
+ /* Destroy any signal state. */
+ __pthread_sigstate_destroy (self);
+
+ /* Decrease the number of threads. We use an atomic operation to
+ make sure that only the last thread calls `exit'. */
+ if (__atomic_dec_and_test (&__pthread_total))
+ /* We are the last thread. */
+ exit (0);
+
+ /* Note that after this point the process can be terminated at any
+ point if another thread calls `pthread_exit' and happens to be
+ the last thread. */
+
+ __pthread_mutex_lock (&self->state_lock);
+
+ if (self->cancel_state == PTHREAD_CANCEL_ENABLE && self->cancel_pending)
+ status = PTHREAD_CANCELED;
+
+#ifdef ENABLE_TLS
+ if (self->tcb)
+ _dl_deallocate_tls (self->tcb, 1);
+#endif /* ENABLE_TLS */
+
+ switch (self->state)
+ {
+ default:
+ assert (! "Consistency error: unexpected self->state");
+ abort ();
+ break;
+
+ case PTHREAD_DETACHED:
+ /* Make sure that nobody can reference this thread anymore, and
+ mark it as terminated. Our thread ID will immediately become
+ available for re-use. For obvious reasons, we cannot
+ deallocate our own stack. However, it will eventually be
+ reused when this thread structure is recycled. */
+ __pthread_mutex_unlock (&self->state_lock);
+
+ __pthread_dealloc (self);
+
+ break;
+
+ case PTHREAD_JOINABLE:
+ /* We need to stay around for a while since another thread
+ might want to join us. */
+ self->state = PTHREAD_EXITED;
+
+ /* We need to remember the exit status. A thread joining us
+ might ask for it. */
+ self->status = status;
+
+ /* Broadcast the condition. This will wake up threads that are
+ waiting to join us. */
+ pthread_cond_broadcast (&self->state_cond);
+ __pthread_mutex_unlock (&self->state_lock);
+
+ break;
+ }
+
+ /* Note that after this point the resources used by this thread can
+ be freed at any moment if another thread joins or detaches us.
+ This means that before freeing any resources, such a thread
+ should make sure that this thread is really halted. */
+
+ __pthread_thread_halt (self);
+
+ /* NOTREACHED */
+ abort ();
+}
diff --git a/libpthread/pthread/pt-getattr.c b/libpthread/pthread/pt-getattr.c
new file mode 100644
index 00000000..24599c6e
--- /dev/null
+++ b/libpthread/pthread/pt-getattr.c
@@ -0,0 +1,49 @@
+/* Thread attributes retrieval.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+/* Initialize thread attribute *ATTR with attributes corresponding to the
+ already running thread THREAD. It shall be called on an uninitialized ATTR
+ and destroyed with pthread_attr_destroy when no longer needed. */
+int
+pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
+{
+ struct __pthread *pthread;
+
+ pthread = __pthread_getid(thread);
+ if (pthread == NULL)
+ return ESRCH;
+
+ /* Some attributes (schedparam, inheritsched, contentionscope and schedpolicy)
+ are not supported yet, so fill them with our default values. */
+ *attr = __pthread_default_attr;
+
+ attr->stackaddr = pthread->stackaddr;
+ attr->stacksize = pthread->stacksize;
+ attr->guardsize = pthread->guardsize;
+ attr->detachstate = (pthread->state == PTHREAD_DETACHED
+ ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
+
+ return 0;
+}
diff --git a/libpthread/pthread/pt-initialize.c b/libpthread/pthread/pt-initialize.c
new file mode 100644
index 00000000..cf32b8b5
--- /dev/null
+++ b/libpthread/pthread/pt-initialize.c
@@ -0,0 +1,33 @@
+/* Initialize pthreads library.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <string.h>
+
+#include <pt-internal.h>
+#include <set-hooks.h>
+
+DEFINE_HOOK (__pthread_init, (void));
+
+/* Initialize the pthreads library. */
+void
+__pthread_initialize (void)
+{
+ RUN_HOOK (__pthread_init, ());
+}
diff --git a/libpthread/pthread/pt-internal.h b/libpthread/pthread/pt-internal.h
new file mode 100644
index 00000000..3f69d2dd
--- /dev/null
+++ b/libpthread/pthread/pt-internal.h
@@ -0,0 +1,317 @@
+/* Internal defenitions for pthreads library.
+ Copyright (C) 2000, 2005, 2006, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PT_INTERNAL_H
+#define _PT_INTERNAL_H 1
+
+#include <pthread.h>
+#include <stddef.h>
+#include <sched.h>
+#include <signal.h>
+#include <assert.h>
+
+#include <bits/atomic.h>
+
+#include <pt-key.h>
+
+#include <pt-sysdep.h>
+#include <pt-machdep.h>
+
+/* Thread state. */
+enum pthread_state
+{
+ /* The thread is running and joinable. */
+ PTHREAD_JOINABLE = 0,
+ /* The thread is running and detached. */
+ PTHREAD_DETACHED,
+ /* A joinable thread exited and its return code is available. */
+ PTHREAD_EXITED,
+ /* The thread structure is unallocated and available for reuse. */
+ PTHREAD_TERMINATED
+};
+
+#ifndef PTHREAD_KEY_MEMBERS
+# define PTHREAD_KEY_MEMBERS
+#endif
+
+#ifndef PTHREAD_SYSDEP_MEMBERS
+# define PTHREAD_SYSDEP_MEMBERS
+#endif
+
+#ifdef ENABLE_TLS
+/* Type of the TCB. */
+typedef struct
+{
+ void *tcb; /* Points to this structure. */
+ void *dtv; /* Vector of pointers to TLS data. */
+ thread_t self; /* This thread's control port. */
+} tcbhead_t;
+#endif /* ENABLE_TLS */
+
+/* This structure describes a POSIX thread. */
+struct __pthread
+{
+ /* Thread ID. */
+ pthread_t thread;
+
+ /* Cancellation. */
+ int cancel_state;
+ int cancel_type;
+ int cancel_pending;
+ struct __pthread_cancelation_handler *cancelation_handlers;
+
+ /* Thread stack. */
+ void *stackaddr;
+ size_t stacksize;
+ size_t guardsize; /* Included in STACKSIZE (i.e. total
+ stack memory is STACKSIZE, not
+ STACKSIZE + GUARDSIZE). */
+ int stack; /* Nonzero if the stack was allocated. */
+
+ /* Exit status. */
+ void *status;
+
+ /* Thread state. */
+ enum pthread_state state;
+ pthread_mutex_t state_lock; /* Locks the state. */
+ pthread_cond_t state_cond; /* Signalled when the state changes. */
+
+ /* Thread context. */
+ struct pthread_mcontext mcontext;
+
+ PTHREAD_KEY_MEMBERS
+
+ PTHREAD_SYSDEP_MEMBERS
+
+#ifdef ENABLE_TLS
+ tcbhead_t *tcb;
+#endif /* ENABLE_TLS */
+
+ struct __pthread *next, **prevp;
+};
+
+/* Enqueue an element THREAD on the queue *HEAD. */
+static inline void
+__pthread_enqueue (struct __pthread **head, struct __pthread *thread)
+{
+ assert (thread->prevp == 0);
+
+ thread->next = *head;
+ thread->prevp = head;
+ if (*head)
+ (*head)->prevp = &thread->next;
+ *head = thread;
+}
+
+/* Dequeue the element THREAD from the queue it is connected to. */
+static inline void
+__pthread_dequeue (struct __pthread *thread)
+{
+ assert (thread);
+
+ if (thread->next)
+ thread->next->prevp = thread->prevp;
+ *thread->prevp = thread->next;
+ thread->prevp = 0;
+}
+
+/* Iterate over QUEUE storing each element in ELEMENT. */
+#define __pthread_queue_iterate(queue, element) \
+ for (struct __pthread *__pdi_next = (queue); \
+ ((element) = __pdi_next) \
+ && ((__pdi_next = __pdi_next->next), \
+ 1); \
+ )
+
+/* Iterate over QUEUE dequeuing each element, storing it in
+ ELEMENT. */
+#define __pthread_dequeuing_iterate(queue, element) \
+ for (struct __pthread *__pdi_next = (queue); \
+ ((element) = __pdi_next) \
+ && ((__pdi_next = __pdi_next->next), \
+ ((element)->prevp = 0), \
+ 1); \
+ )
+
+/* The total number of threads currently active. */
+extern __atomic_t __pthread_total;
+
+/* The total number of thread IDs currently in use, or on the list of
+ available thread IDs. */
+extern int __pthread_num_threads;
+
+/* Concurrency hint. */
+extern int __pthread_concurrency;
+
+/* Array of __pthread structures and its lock. Indexed by the pthread
+ id minus one. (Why not just use the pthread id? Because some
+ brain-dead users of the pthread interface incorrectly assume that 0
+ is an invalid pthread id.) */
+extern struct __pthread **__pthread_threads;
+extern pthread_rwlock_t __pthread_threads_lock;
+
+#define __pthread_getid(thread) \
+ ({ struct __pthread *__t; \
+ pthread_rwlock_rdlock (&__pthread_threads_lock); \
+ __t = __pthread_threads[thread - 1]; \
+ pthread_rwlock_unlock (&__pthread_threads_lock); \
+ __t; })
+
+#define __pthread_setid(thread, pthread) \
+ pthread_rwlock_wrlock (&__pthread_threads_lock); \
+ __pthread_threads[thread - 1] = pthread; \
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+
+/* Similar to pthread_self, but returns the thread descriptor instead
+ of the thread ID. */
+#ifndef _pthread_self
+extern struct __pthread *_pthread_self (void);
+#endif
+
+
+/* Initialize the pthreads library. */
+extern void __pthread_initialize (void);
+
+/* Internal version of pthread_create. Rather than return the new
+ tid, we return the whole __pthread structure in *PTHREAD. */
+extern int __pthread_create_internal (struct __pthread **__restrict pthread,
+ const pthread_attr_t *__restrict attr,
+ void *(*start_routine)(void *),
+ void *__restrict arg);
+
+/* Allocate a new thread structure and a pthread thread ID (but not a
+ kernel thread or a stack). */
+extern int __pthread_alloc (struct __pthread **thread);
+
+/* Deallocate the thread structure. This is the dual of
+ __pthread_alloc (N.B. it does not call __pthread_stack_alloc nor
+ __pthread_thread_halt). */
+extern void __pthread_dealloc (struct __pthread *thread);
+
+
+/* Allocate a stack of size STACKSIZE. The stack base shall be
+ returned in *STACKADDR. */
+extern int __pthread_stack_alloc (void **stackaddr, size_t stacksize);
+
+/* Deallocate the stack STACKADDR of size STACKSIZE. */
+extern void __pthread_stack_dealloc (void *stackaddr, size_t stacksize);
+
+
+/* Setup thread THREAD's context. */
+extern int __pthread_setup (struct __pthread *__restrict thread,
+ void (*entry_point)(void *(*)(void *),
+ void *),
+ void *(*start_routine)(void *),
+ void *__restrict arg);
+
+
+/* Allocate a kernel thread (and any miscellaneous system dependent
+ resources) for THREAD; it must not be placed on the run queue. */
+extern int __pthread_thread_alloc (struct __pthread *thread);
+
+/* Deallocate any kernel resources associated with THREAD. The thread
+ must not be running (that is, if __pthread_thread_start was called,
+ __pthread_thread_halt must first be called). This function will
+ never be called by a thread on itself. In the case that a thread
+ exits, its thread structure will be cached and cleaned up
+ later. */
+extern void __pthread_thread_dealloc (struct __pthread *thread);
+
+/* Start THREAD making it eligible to run. */
+extern int __pthread_thread_start (struct __pthread *thread);
+
+/* Stop the kernel thread associated with THREAD. This function may
+ be called by two threads in parallel. In particular, by the thread
+ itself and another thread trying to join it. This function must be
+ implemented such that this is safe. */
+extern void __pthread_thread_halt (struct __pthread *thread);
+
+
+/* Called by a thread just before it calls the provided start
+ routine. */
+extern void __pthread_startup (void);
+
+/* Block THREAD. */
+extern void __pthread_block (struct __pthread *thread);
+
+/* Block THREAD until *ABSTIME is reached. */
+extern error_t __pthread_timedblock (struct __pthread *__restrict thread,
+ const struct timespec *__restrict abstime);
+
+/* Wakeup THREAD. */
+extern void __pthread_wakeup (struct __pthread *thread);
+
+
+/* Perform a cancelation. */
+extern int __pthread_do_cancel (struct __pthread *thread);
+
+
+/* Initialize the thread specific data structures. THREAD must be the
+ calling thread. */
+extern error_t __pthread_init_specific (struct __pthread *thread);
+
+/* Call the destructors on all of the thread specific data in THREAD.
+ THREAD must be the calling thread. */
+extern void __pthread_destroy_specific (struct __pthread *thread);
+
+
+/* Initialize newly create thread *THREAD's signal state data
+ structures. */
+extern error_t __pthread_sigstate_init (struct __pthread *thread);
+
+/* Destroy the signal state data structures associcated with thread
+ *THREAD. */
+extern void __pthread_sigstate_destroy (struct __pthread *thread);
+
+/* Modify thread *THREAD's signal state. */
+extern error_t __pthread_sigstate (struct __pthread *__restrict thread, int how,
+ const sigset_t *__restrict set,
+ sigset_t *__restrict oset,
+ int clear_pending);
+
+
+/* Default thread attributes. */
+extern const struct __pthread_attr __pthread_default_attr;
+
+/* Default barrier attributes. */
+extern const struct __pthread_barrierattr __pthread_default_barrierattr;
+
+/* Default mutex attributes. */
+extern const struct __pthread_mutexattr __pthread_default_mutexattr;
+
+/* Default rdlock attributes. */
+const struct __pthread_rwlockattr __pthread_default_rwlockattr;
+
+/* Default condition attributes. */
+const struct __pthread_condattr __pthread_default_condattr;
+
+
+#ifdef ENABLE_TLS
+
+/* From glibc. */
+
+/* Dynamic linker TLS allocation. */
+extern void *_dl_allocate_tls(void *);
+
+/* Dynamic linker TLS deallocation. */
+extern void _dl_deallocate_tls(void *, int);
+
+#endif /* ENABLE_TLS */
+
+#endif /* pt-internal.h */
diff --git a/libpthread/pthread/pt-join.c b/libpthread/pthread/pt-join.c
new file mode 100644
index 00000000..153058b5
--- /dev/null
+++ b/libpthread/pthread/pt-join.c
@@ -0,0 +1,88 @@
+/* Wait for thread termination.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+
+#include <pt-internal.h>
+
+/* Make calling thread wait for termination of thread THREAD. Return
+ the exit status of the thread in *STATUS. */
+int
+pthread_join (pthread_t thread, void **status)
+{
+ struct __pthread *pthread;
+ int err = 0;
+
+ /* Lookup the thread structure for THREAD. */
+ pthread = __pthread_getid (thread);
+ if (pthread == NULL)
+ return ESRCH;
+
+ __pthread_mutex_lock (&pthread->state_lock);
+ pthread_cleanup_push ((void (*)(void *)) __pthread_mutex_unlock,
+ &pthread->state_lock);
+
+ while (pthread->state == PTHREAD_JOINABLE)
+ pthread_cond_wait (&pthread->state_cond, &pthread->state_lock);
+
+ pthread_cleanup_pop (0);
+
+ switch (pthread->state)
+ {
+ case PTHREAD_EXITED:
+ __pthread_mutex_unlock (&pthread->state_lock);
+
+ /* THREAD has already exited. Salvage its exit status. */
+ if (status)
+ *status = pthread->status;
+
+ /* Make sure the thread is not running before we remove its
+ stack. (The only possibility is that it is in a call to
+ __pthread_thread_halt itself, but that is enough to cause a
+ sigsegv.) */
+ __pthread_thread_halt (pthread);
+
+ /* Destroy the stack, the kernel resources and the control
+ block. */
+ assert (pthread->stack);
+ __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
+ pthread->stack = 0;
+
+ __pthread_thread_dealloc (pthread);
+
+ __pthread_dealloc (pthread);
+ break;
+
+ case PTHREAD_TERMINATED:
+ /* Pretend THREAD wasn't there in the first place. */
+ __pthread_mutex_unlock (&pthread->state_lock);
+ err = ESRCH;
+ break;
+
+ default:
+ /* Thou shalt not join non-joinable threads! */
+ __pthread_mutex_unlock (&pthread->state_lock);
+ err = EINVAL;
+ break;
+ }
+
+ return err;
+}
diff --git a/libpthread/pthread/pt-self.c b/libpthread/pthread/pt-self.c
new file mode 100644
index 00000000..49768643
--- /dev/null
+++ b/libpthread/pthread/pt-self.c
@@ -0,0 +1,32 @@
+/* Get calling thread's ID.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+/* Return the thread ID of the calling thread. */
+pthread_t
+pthread_self (void)
+{
+ struct __pthread *self = _pthread_self ();
+ assert (self);
+
+ return self->thread;
+}
diff --git a/libpthread/pthread/pt-setcancelstate.c b/libpthread/pthread/pt-setcancelstate.c
new file mode 100644
index 00000000..e2d81833
--- /dev/null
+++ b/libpthread/pthread/pt-setcancelstate.c
@@ -0,0 +1,43 @@
+/* Set the cancel state for the calling thread.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+int
+pthread_setcancelstate (int state, int *oldstate)
+{
+ struct __pthread *p = _pthread_self ();
+
+ switch (state)
+ {
+ default:
+ return EINVAL;
+ case PTHREAD_CANCEL_ENABLE:
+ case PTHREAD_CANCEL_DISABLE:
+ break;
+ }
+
+ if (oldstate)
+ *oldstate = p->cancel_state;
+ p->cancel_state = state;
+
+ return 0;
+}
diff --git a/libpthread/pthread/pt-setcanceltype.c b/libpthread/pthread/pt-setcanceltype.c
new file mode 100644
index 00000000..3ce4259c
--- /dev/null
+++ b/libpthread/pthread/pt-setcanceltype.c
@@ -0,0 +1,43 @@
+/* Set the cancel type for the calling thread.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+int
+pthread_setcanceltype (int type, int *oldtype)
+{
+ struct __pthread *p = _pthread_self ();
+
+ switch (type)
+ {
+ default:
+ return EINVAL;
+ case PTHREAD_CANCEL_DEFERRED:
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ break;
+ }
+
+ if (oldtype)
+ *oldtype = p->cancel_type;
+ p->cancel_type = type;
+
+ return 0;
+}
diff --git a/libpthread/pthread/pt-sigmask.c b/libpthread/pthread/pt-sigmask.c
new file mode 100644
index 00000000..1b53873e
--- /dev/null
+++ b/libpthread/pthread/pt-sigmask.c
@@ -0,0 +1,33 @@
+/* Get or set a thread's signal mask.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <signal.h>
+
+#include <pt-internal.h>
+
+int
+pthread_sigmask (int how, const sigset_t *set,
+ sigset_t *oset)
+{
+ struct __pthread *self = _pthread_self ();
+
+ /* Do not clear SELF's pending signals. */
+ return __pthread_sigstate (self, how, set, oset, 0);
+}
diff --git a/libpthread/pthread/pt-spin-inlines.c b/libpthread/pthread/pt-spin-inlines.c
new file mode 100644
index 00000000..cfb21dd3
--- /dev/null
+++ b/libpthread/pthread/pt-spin-inlines.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* <bits/spin-lock.h> declares some extern inline functions. These
+ functions are declared additionally here for use when inlining is
+ not possible. */
+
+#define _FORCE_INLINES
+#define __PT_SPIN_INLINE /* empty */
+
+#include <pthread.h>
+
+/* Weak aliases for the spin lock functions. Note that
+ pthread_spin_lock is left out deliberately. We already provide an
+ implementation for it in pt-spin.c. */
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy);
+weak_alias (__pthread_spin_init, pthread_spin_init);
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock);
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock);
diff --git a/libpthread/pthread/pt-testcancel.c b/libpthread/pthread/pt-testcancel.c
new file mode 100644
index 00000000..01f1ac9c
--- /dev/null
+++ b/libpthread/pthread/pt-testcancel.c
@@ -0,0 +1,31 @@
+/* Add an explicit cancelation point.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+void
+pthread_testcancel (void)
+{
+ struct __pthread *p = _pthread_self ();
+
+ if (p->cancel_state == PTHREAD_CANCEL_ENABLE && p->cancel_pending)
+ pthread_exit (PTHREAD_CANCELED);
+}
diff --git a/libpthread/signal/README b/libpthread/signal/README
new file mode 100644
index 00000000..5487e2e3
--- /dev/null
+++ b/libpthread/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/libpthread/signal/TODO b/libpthread/signal/TODO
new file mode 100644
index 00000000..1148abb3
--- /dev/null
+++ b/libpthread/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/libpthread/signal/kill.c b/libpthread/signal/kill.c
new file mode 100644
index 00000000..27c9c32a
--- /dev/null
+++ b/libpthread/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/libpthread/signal/pt-kill-siginfo-np.c b/libpthread/signal/pt-kill-siginfo-np.c
new file mode 100644
index 00000000..9bdf6cc4
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sig-internal.c b/libpthread/signal/sig-internal.c
new file mode 100644
index 00000000..f73f38b4
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sig-internal.h b/libpthread/signal/sig-internal.h
new file mode 100644
index 00000000..6c86c796
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigaction.c b/libpthread/signal/sigaction.c
new file mode 100644
index 00000000..0126c99d
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigaltstack.c b/libpthread/signal/sigaltstack.c
new file mode 100644
index 00000000..8334811a
--- /dev/null
+++ b/libpthread/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/libpthread/signal/signal-dispatch.c b/libpthread/signal/signal-dispatch.c
new file mode 100644
index 00000000..40440b70
--- /dev/null
+++ b/libpthread/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/libpthread/signal/signal.h b/libpthread/signal/signal.h
new file mode 100644
index 00000000..a33d995c
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigpending.c b/libpthread/signal/sigpending.c
new file mode 100644
index 00000000..609b55d6
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigsuspend.c b/libpthread/signal/sigsuspend.c
new file mode 100644
index 00000000..73cf12a1
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigtimedwait.c b/libpthread/signal/sigtimedwait.c
new file mode 100644
index 00000000..52cd0176
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigwaiter.c b/libpthread/signal/sigwaiter.c
new file mode 100644
index 00000000..8d041ac1
--- /dev/null
+++ b/libpthread/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/libpthread/signal/sigwaitinfo.c b/libpthread/signal/sigwaitinfo.c
new file mode 100644
index 00000000..1b47079e
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/bits/barrier-attr.h b/libpthread/sysdeps/generic/bits/barrier-attr.h
new file mode 100644
index 00000000..a9900b71
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/barrier-attr.h
@@ -0,0 +1,32 @@
+/* Thread barrier attribute type. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_BARRIER_ATTR_H
+#define _BITS_BARRIER_ATTR_H 1
+
+enum __pthread_process_shared;
+
+/* This structure describes the attributes of a POSIX thread barrier.
+ Note that not all of them are supported on all systems. */
+struct __pthread_barrierattr
+{
+ enum __pthread_process_shared pshared;
+};
+
+#endif /* bits/barrier-attr.h */
diff --git a/libpthread/sysdeps/generic/bits/barrier.h b/libpthread/sysdeps/generic/bits/barrier.h
new file mode 100644
index 00000000..5e559312
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/barrier.h
@@ -0,0 +1,39 @@
+/* Thread barrier attribute type. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_BARRIER_H
+#define _BITS_BARRIER_H 1
+
+#include <bits/spin-lock.h>
+
+/* This structure describes the attributes of a POSIX barrier. */
+struct __pthread_barrier
+{
+ __pthread_spinlock_t lock;
+ struct __pthread *queue; /* List of waiters. */
+ unsigned pending; /* Number of that still need to wait on
+ barrier. */
+ unsigned count; /* Number of threads that must wait before
+ barrier is passed. */
+ struct __pthread_barrierattr *attr;
+ void *data;
+};
+
+
+#endif /* bits/barrier.h */
diff --git a/libpthread/sysdeps/generic/bits/cancelation.h b/libpthread/sysdeps/generic/bits/cancelation.h
new file mode 100644
index 00000000..46486f5e
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/cancelation.h
@@ -0,0 +1,51 @@
+/* Cancelation. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_CANCELATION_H
+#define _BITS_CANCELATION_H 1
+
+struct __pthread_cancelation_handler
+{
+ void (*handler)(void *);
+ void *arg;
+ struct __pthread_cancelation_handler *next;
+};
+
+/* Returns the thread local location of the cleanup handler stack. */
+struct __pthread_cancelation_handler **__pthread_get_cleanup_stack (void);
+
+#define __pthread_cleanup_push(rt, rtarg) \
+ { \
+ struct __pthread_cancelation_handler **__handlers \
+ = __pthread_get_cleanup_stack (); \
+ struct __pthread_cancelation_handler __handler = \
+ { \
+ (rt), \
+ (rtarg), \
+ *__handlers \
+ }; \
+ *__handlers = &__handler;
+
+#define __pthread_cleanup_pop(execute) \
+ if (execute) \
+ __handler.handler (__handler.arg); \
+ *__handlers = __handler.next; \
+ }
+
+#endif /* _BITS_CANCELATION_H */
diff --git a/libpthread/sysdeps/generic/bits/condition-attr.h b/libpthread/sysdeps/generic/bits/condition-attr.h
new file mode 100644
index 00000000..4cd4e8c4
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/condition-attr.h
@@ -0,0 +1,34 @@
+/* Condition attribute type. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_CONDITION_ATTR_H
+#define _BITS_CONDITION_ATTR_H 1
+
+#include <bits/types.h>
+
+enum __pthread_process_shared;
+
+/* User visible part of a condition attribute variable. */
+struct __pthread_condattr
+ {
+ enum __pthread_process_shared pshared;
+ __clockid_t clock;
+ };
+
+#endif /* bits/condition.h */
diff --git a/libpthread/sysdeps/generic/bits/condition.h b/libpthread/sysdeps/generic/bits/condition.h
new file mode 100644
index 00000000..bf13adab
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/condition.h
@@ -0,0 +1,39 @@
+/* Condition type. Generic version.
+ Copyright (C) 2000, 2005, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_CONDITION_H
+#define _BITS_CONDITION_H 1
+
+#include <bits/spin-lock.h>
+
+/* User visible part of a condition variable. */
+struct __pthread_cond
+ {
+ __pthread_spinlock_t __lock;
+ struct __pthread *__queue;
+ struct __pthread_condattr *__attr;
+ struct __pthread_condimpl *__impl;
+ void *__data;
+ };
+
+/* Initializer for a condition variable. */
+#define __PTHREAD_COND_INITIALIZER \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, NULL, NULL, NULL, NULL }
+
+#endif /* bits/condition.h */
diff --git a/libpthread/sysdeps/generic/bits/mutex-attr.h b/libpthread/sysdeps/generic/bits/mutex-attr.h
new file mode 100644
index 00000000..8514ebe8
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/mutex-attr.h
@@ -0,0 +1,41 @@
+/* Mutex attribute type. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_MUTEX_ATTR_H
+#define _BITS_MUTEX_ATTR_H 1
+
+enum __pthread_mutex_protocol;
+enum __pthread_process_shared;
+enum __pthread_mutex_type;
+
+/* This structure describes the attributes of a POSIX mutex
+ attribute. */
+struct __pthread_mutexattr
+{
+ int prioceiling;
+ enum __pthread_mutex_protocol protocol;
+ enum __pthread_process_shared pshared;
+ enum __pthread_mutex_type mutex_type;
+};
+
+/* Attributes for a recursive mutex. */
+extern const struct __pthread_mutexattr __pthread_errorcheck_mutexattr;
+extern const struct __pthread_mutexattr __pthread_recursive_mutexattr;
+
+#endif /* bits/mutex-attr.h */
diff --git a/libpthread/sysdeps/generic/bits/mutex.h b/libpthread/sysdeps/generic/bits/mutex.h
new file mode 100644
index 00000000..c734c393
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/mutex.h
@@ -0,0 +1,75 @@
+/* Mutex type. Generic version.
+
+ Copyright (C) 2000, 2002, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_MUTEX_H
+
+#ifndef __need_pthread_mutex
+# define _BITS_MUTEX_H 1
+#endif
+
+#ifndef __pthread_mutex_defined
+# if defined __need_pthread_mutex || defined _BITS_MUTEX_H
+# undef __need_pthread_mutex
+# define __pthread_mutex_defined
+
+# include <bits/spin-lock.h>
+# include <bits/mutex-attr.h>
+
+/* User visible part of a mutex. */
+struct __pthread_mutex
+ {
+ __pthread_spinlock_t __held;
+ __pthread_spinlock_t __lock;
+ /* In cthreads, mutex_init does not initialized thre third
+ pointer, as such, we cannot rely on its value for anything. */
+ char *cthreadscompat1;
+ struct __pthread *__queue;
+ struct __pthread_mutexattr *attr;
+ void *data;
+ /* Up to this point, we are completely compatible with cthreads
+ and what libc expects. */
+ void *owner;
+ unsigned locks;
+ /* If NULL then the default attributes apply. */
+ };
+
+/* Initializer for a mutex. N.B. this also happens to be compatible
+ with the cthread mutex initializer. */
+# define __PTHREAD_MUTEX_INITIALIZER \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, 0, 0, 0, 0 }
+
+# define __PTHREAD_ERRORCHECK_MUTEXATTR ((struct __pthread_mutexattr *) ((unsigned long) __PTHREAD_MUTEX_ERRORCHECK + 1))
+
+# define __PTHREAD_ERRORCHECK_MUTEX_INITIALIZER \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, \
+ __PTHREAD_ERRORCHECK_MUTEXATTR, 0, 0, 0 }
+
+# define __PTHREAD_RECURSIVE_MUTEXATTR ((struct __pthread_mutexattr *) ((unsigned long) __PTHREAD_MUTEX_RECURSIVE + 1))
+
+# define __PTHREAD_RECURSIVE_MUTEX_INITIALIZER \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, \
+ __PTHREAD_RECURSIVE_MUTEXATTR, 0, 0, 0 }
+
+# endif
+#endif /* Not __pthread_mutex_defined. */
+
+#endif /* bits/mutex.h */
diff --git a/libpthread/sysdeps/generic/bits/once.h b/libpthread/sysdeps/generic/bits/once.h
new file mode 100644
index 00000000..f4985d6f
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/once.h
@@ -0,0 +1,34 @@
+/* Dynamic package initialization data structures. Generic version.
+ Copyright (C) 2002, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_ONCE_H
+#define _BITS_ONCE_H 1
+
+#include <bits/spin-lock.h>
+
+struct __pthread_once
+{
+ int run;
+ __pthread_spinlock_t lock;
+};
+
+#define __PTHREAD_ONCE_INIT \
+ { 0, __PTHREAD_SPIN_LOCK_INITIALIZER }
+
+#endif /* bits/once.h */
diff --git a/libpthread/sysdeps/generic/bits/pthread-np.h b/libpthread/sysdeps/generic/bits/pthread-np.h
new file mode 100644
index 00000000..d5ddbb05
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/pthread-np.h
@@ -0,0 +1,27 @@
+/* Non-portable functions. Generic version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_PTHREAD_NP_H
+#define _BITS_PTHREAD_NP_H 1
+
+#endif /* bits/pthread-np.h */
diff --git a/libpthread/sysdeps/generic/bits/pthread.h b/libpthread/sysdeps/generic/bits/pthread.h
new file mode 100644
index 00000000..80e6b096
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/pthread.h
@@ -0,0 +1,38 @@
+/* Pthread data structures. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_PTHREAD_H
+#define _BITS_PTHREAD_H 1
+
+typedef int __pthread_t;
+
+/* Return true if __T1 and __T2 both name the same thread. Otherwise,
+ false. */
+extern int
+__pthread_equal (__pthread_t __t1, __pthread_t __t2);
+
+#ifdef __USE_EXTERN_INLINES
+__extern_inline int
+__pthread_equal (__pthread_t __t1, __pthread_t __t2)
+{
+ return __t1 == __t2;
+}
+#endif
+
+#endif /* bits/pthread.h */
diff --git a/libpthread/sysdeps/generic/bits/pthreadtypes.h b/libpthread/sysdeps/generic/bits/pthreadtypes.h
new file mode 100644
index 00000000..e5cbfd2a
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/pthreadtypes.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined _BITS_TYPES_H && !defined _PTHREAD_H
+# error "Never include <bits/pthreadtypes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#include <pthread.h>
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/sysdeps/generic/bits/rwlock-attr.h b/libpthread/sysdeps/generic/bits/rwlock-attr.h
new file mode 100644
index 00000000..dba99f1d
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/rwlock-attr.h
@@ -0,0 +1,32 @@
+/* Thread rwlock attribute type. Generic version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_RWLOCK_ATTR_H
+#define _BITS_RWLOCK_ATTR_H 1
+
+enum __pthread_process_shared;
+
+/* This structure describes the attributes of a POSIX thread rwlock.
+ Note that not all of them are supported on all systems. */
+struct __pthread_rwlockattr
+{
+ enum __pthread_process_shared pshared;
+};
+
+#endif /* bits/rwlock-attr.h */
diff --git a/libpthread/sysdeps/generic/bits/rwlock.h b/libpthread/sysdeps/generic/bits/rwlock.h
new file mode 100644
index 00000000..af6b1c86
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/rwlock.h
@@ -0,0 +1,46 @@
+/* rwlock type. Generic version.
+ Copyright (C) 2002, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_RWLOCK_H
+#define _BITS_RWLOCK_H
+
+#include <bits/spin-lock.h>
+
+/* User visible part of a rwlock. If __held is not held and readers
+ is 0, then the lock is unlocked. If __held is held and readers is
+ 0, then the lock is held by a writer. If __held is held and
+ readers is greater than 0, then the lock is held by READERS
+ readers. */
+struct __pthread_rwlock
+ {
+ __pthread_spinlock_t __held;
+ __pthread_spinlock_t __lock;
+ int readers;
+ struct __pthread *readerqueue;
+ struct __pthread *writerqueue;
+ struct __pthread_rwlockattr *__attr;
+ void *__data;
+ };
+
+/* Initializer for a rwlock. */
+#define __PTHREAD_RWLOCK_INITIALIZER \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, 0, 0, 0 }
+
+
+#endif /* bits/rwlock.h */
diff --git a/libpthread/sysdeps/generic/bits/semaphore.h b/libpthread/sysdeps/generic/bits/semaphore.h
new file mode 100644
index 00000000..5e987c15
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/semaphore.h
@@ -0,0 +1,43 @@
+/* Semaphore type. Generic version.
+ Copyright (C) 2005, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_SEMAPHORE_H
+#define _BITS_SEMAPHORE_H 1
+
+#ifndef _SEMAPHORE_H
+#error Never include <bits/semaphore.h> directly.
+#endif
+
+#include <pthread.h>
+
+/* User visible part of a semaphore. */
+struct __semaphore
+ {
+ __pthread_spinlock_t __lock;
+ struct __pthread *__queue;
+ int __pshared;
+ int __value;
+ void *__data;
+ };
+
+/* Initializer for a semaphore. */
+#define __SEMAPHORE_INITIALIZER(pshared, value) \
+ { __PTHREAD_SPIN_LOCK_INITIALIZER, NULL, (pshared), (value), NULL }
+
+#endif /* bits/mutex.h */
diff --git a/libpthread/sysdeps/generic/bits/thread-attr.h b/libpthread/sysdeps/generic/bits/thread-attr.h
new file mode 100644
index 00000000..f2e55f2b
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/thread-attr.h
@@ -0,0 +1,44 @@
+/* Thread attribute type. Generic version.
+ Copyright (C) 2000, 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_THREAD_ATTR_H
+#define _BITS_THREAD_ATTR_H 1
+
+#define __need_schedparam
+#include <bits/sched.h>
+
+enum __pthread_detachstate;
+enum __pthread_inheritsched;
+enum __pthread_contentionscope;
+
+/* This structure describes the attributes of a POSIX thread. Note
+ that not all of them are supported on all systems. */
+struct __pthread_attr
+{
+ struct __sched_param schedparam;
+ void *stackaddr;
+ size_t stacksize;
+ size_t guardsize;
+ enum __pthread_detachstate detachstate;
+ enum __pthread_inheritsched inheritsched;
+ enum __pthread_contentionscope contentionscope;
+ int schedpolicy;
+};
+
+#endif /* bits/thread-attr.h */
diff --git a/libpthread/sysdeps/generic/bits/thread-specific.h b/libpthread/sysdeps/generic/bits/thread-specific.h
new file mode 100644
index 00000000..b42d99e7
--- /dev/null
+++ b/libpthread/sysdeps/generic/bits/thread-specific.h
@@ -0,0 +1,25 @@
+/* Thread specific data. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_THREAD_SPECIFIC_H
+#define _BITS_THREAD_SPECIFIC_H 1
+
+typedef int __pthread_key;
+
+#endif /* bits/thread-specific.h */
diff --git a/libpthread/sysdeps/generic/killpg.c b/libpthread/sysdeps/generic/killpg.c
new file mode 100644
index 00000000..7f7ed87d
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/pt-atfork.c b/libpthread/sysdeps/generic/pt-atfork.c
new file mode 100644
index 00000000..32e1e78c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-atfork.c
@@ -0,0 +1,29 @@
+/* Register fork handlers. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_atfork (void (*prepare) (void),
+ void (*parent) (void),
+ void (*child) (void))
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-destroy.c b/libpthread/sysdeps/generic/pt-attr-destroy.c
new file mode 100644
index 00000000..c4b9aa54
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_attr_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_destroy (pthread_attr_t *attr)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getdetachstate.c b/libpthread/sysdeps/generic/pt-attr-getdetachstate.c
new file mode 100644
index 00000000..be406f1d
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getdetachstate.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getdetachstate. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getdetachstate (const pthread_attr_t *attr,
+ int *detachstate)
+{
+ *detachstate = attr->detachstate;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getguardsize.c b/libpthread/sysdeps/generic/pt-attr-getguardsize.c
new file mode 100644
index 00000000..c1d9f13e
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getguardsize.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getguardsize. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getguardsize (const pthread_attr_t *attr,
+ size_t *guardsize)
+{
+ *guardsize = attr->guardsize;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getinheritsched.c b/libpthread/sysdeps/generic/pt-attr-getinheritsched.c
new file mode 100644
index 00000000..cca4e3d7
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getinheritsched.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getinheritsched. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getinheritsched (const pthread_attr_t *attr,
+ int *inheritsched)
+{
+ *inheritsched = attr->inheritsched;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getschedparam.c b/libpthread/sysdeps/generic/pt-attr-getschedparam.c
new file mode 100644
index 00000000..190cf9d0
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getschedparam.c
@@ -0,0 +1,32 @@
+/* pthread_attr_getschedparam. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+int
+pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param)
+{
+ memcpy (param, &attr->schedparam, sizeof *param);
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getschedpolicy.c b/libpthread/sysdeps/generic/pt-attr-getschedpolicy.c
new file mode 100644
index 00000000..4349a238
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getschedpolicy.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getschedpolicy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getschedpolicy (const pthread_attr_t *attr,
+ int *policy)
+{
+ *policy = attr->schedpolicy;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getscope.c b/libpthread/sysdeps/generic/pt-attr-getscope.c
new file mode 100644
index 00000000..97198fa5
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getscope.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getscope. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getscope (const pthread_attr_t *attr,
+ int *contentionscope)
+{
+ *contentionscope = attr->contentionscope;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getstack.c b/libpthread/sysdeps/generic/pt-attr-getstack.c
new file mode 100644
index 00000000..7beb79f0
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getstack.c
@@ -0,0 +1,31 @@
+/* pthread_attr_getstack. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getstack (const pthread_attr_t *attr,
+ void **stackaddr,
+ size_t *stacksize)
+{
+ pthread_attr_getstackaddr (attr, stackaddr);
+ pthread_attr_getstacksize (attr, stacksize);
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getstackaddr.c b/libpthread/sysdeps/generic/pt-attr-getstackaddr.c
new file mode 100644
index 00000000..d43eeff7
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getstackaddr.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getstackaddr. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getstackaddr (const pthread_attr_t *attr,
+ void **stackaddr)
+{
+ *stackaddr = attr->stackaddr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-getstacksize.c b/libpthread/sysdeps/generic/pt-attr-getstacksize.c
new file mode 100644
index 00000000..c1bc6617
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-getstacksize.c
@@ -0,0 +1,29 @@
+/* pthread_attr_getstacksize. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_getstacksize (const pthread_attr_t *attr,
+ size_t *stacksize)
+{
+ *stacksize = attr->stacksize;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-init.c b/libpthread/sysdeps/generic/pt-attr-init.c
new file mode 100644
index 00000000..6a930e30
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-init.c
@@ -0,0 +1,28 @@
+/* pthread_attr_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_init (pthread_attr_t *attr)
+{
+ *attr = __pthread_default_attr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setdetachstate.c b/libpthread/sysdeps/generic/pt-attr-setdetachstate.c
new file mode 100644
index 00000000..688ba5d6
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setdetachstate.c
@@ -0,0 +1,38 @@
+/* pthread_attr_setdetachstate. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setdetachstate (pthread_attr_t *attr,
+ int detachstate)
+{
+ switch (detachstate)
+ {
+ case PTHREAD_CREATE_DETACHED:
+ case PTHREAD_CREATE_JOINABLE:
+ attr->detachstate = detachstate;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setguardsize.c b/libpthread/sysdeps/generic/pt-attr-setguardsize.c
new file mode 100644
index 00000000..b2ba0f0f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setguardsize.c
@@ -0,0 +1,29 @@
+/* pthread_attr_setguardsize. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setguardsize (pthread_attr_t *attr,
+ size_t guardsize)
+{
+ attr->guardsize = guardsize;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setinheritsched.c b/libpthread/sysdeps/generic/pt-attr-setinheritsched.c
new file mode 100644
index 00000000..e9012c58
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setinheritsched.c
@@ -0,0 +1,38 @@
+/* pthread_attr_setinheritsched. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setinheritsched (pthread_attr_t *attr,
+ int inheritsched)
+{
+ switch (inheritsched)
+ {
+ case PTHREAD_INHERIT_SCHED:
+ case PTHREAD_EXPLICIT_SCHED:
+ attr->inheritsched = inheritsched;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setschedparam.c b/libpthread/sysdeps/generic/pt-attr-setschedparam.c
new file mode 100644
index 00000000..5459f108
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setschedparam.c
@@ -0,0 +1,38 @@
+/* pthread_attr_getschedparam. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+int
+pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param)
+{
+ if (memcmp (param, &__pthread_default_attr.schedparam,
+ sizeof *param) == 0)
+ {
+ memcpy (&attr->schedparam, param, sizeof *param);
+ return 0;
+ }
+
+ return ENOTSUP;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setschedpolicy.c b/libpthread/sysdeps/generic/pt-attr-setschedpolicy.c
new file mode 100644
index 00000000..e481d04c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setschedpolicy.c
@@ -0,0 +1,42 @@
+/* pthread_attr_getschedpolicy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setschedpolicy (pthread_attr_t *attr,
+ int policy)
+{
+ switch (policy)
+ {
+ case SCHED_OTHER:
+ attr->schedpolicy = policy;
+ break;
+
+ case SCHED_FIFO:
+ case SCHED_RR:
+ return ENOTSUP;
+
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setscope.c b/libpthread/sysdeps/generic/pt-attr-setscope.c
new file mode 100644
index 00000000..c74a4f67
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setscope.c
@@ -0,0 +1,41 @@
+/* pthread_attr_setscope. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setscope (pthread_attr_t *attr,
+ int contentionscope)
+{
+ if (contentionscope == __pthread_default_attr.contentionscope)
+ {
+ attr->contentionscope = contentionscope;
+ return 0;
+ }
+
+ switch (contentionscope)
+ {
+ case PTHREAD_SCOPE_PROCESS:
+ case PTHREAD_SCOPE_SYSTEM:
+ return ENOTSUP;
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setstack.c b/libpthread/sysdeps/generic/pt-attr-setstack.c
new file mode 100644
index 00000000..360d27a3
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setstack.c
@@ -0,0 +1,51 @@
+/* pthread_attr_setstack. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+pthread_attr_setstack (pthread_attr_t *attr,
+ void *stackaddr,
+ size_t stacksize)
+{
+ int err;
+ size_t s;
+
+ /* pthread_attr_setstack should always succeed, thus we set the size
+ first as it is more discriminating. */
+ pthread_attr_getstacksize (attr, &s);
+
+ err = pthread_attr_setstacksize (attr, stacksize);
+ if (err)
+ return err;
+
+ err = pthread_attr_setstackaddr (attr, stackaddr);
+ if (err)
+ {
+ int e = pthread_attr_setstacksize (attr, s);
+ assert_perror (e);
+
+ return err;
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setstackaddr.c b/libpthread/sysdeps/generic/pt-attr-setstackaddr.c
new file mode 100644
index 00000000..431f2d0c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setstackaddr.c
@@ -0,0 +1,29 @@
+/* pthread_attr_setstackaddr. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setstackaddr (pthread_attr_t *attr,
+ void *stackaddr)
+{
+ attr->stackaddr = stackaddr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr-setstacksize.c b/libpthread/sysdeps/generic/pt-attr-setstacksize.c
new file mode 100644
index 00000000..d0e51022
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr-setstacksize.c
@@ -0,0 +1,41 @@
+/* pthread_attr_setstacksize. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_attr_setstacksize (pthread_attr_t *attr,
+ size_t stacksize)
+{
+ if (stacksize == __pthread_default_attr.stacksize)
+ {
+ attr->stacksize = stacksize;
+
+ /* The guard size cannot be larger than the stack itself, as
+ such, if the new stack size is smaller than the guard size,
+ we squash the guard size. */
+ if (attr->guardsize > attr->stacksize)
+ attr->guardsize = attr->stacksize;
+
+ return 0;
+ }
+
+ return ENOTSUP;
+}
diff --git a/libpthread/sysdeps/generic/pt-attr.c b/libpthread/sysdeps/generic/pt-attr.c
new file mode 100644
index 00000000..769f292a
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-attr.c
@@ -0,0 +1,41 @@
+/* Default attributes. Generic version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include <pt-internal.h>
+
+const struct __pthread_attr __pthread_default_attr =
+{
+ schedparam: { sched_priority: 0 },
+ stacksize: PTHREAD_STACK_DEFAULT,
+ stackaddr: NULL,
+#ifdef PAGESIZE
+ guardsize: PAGESIZE,
+#else
+ guardsize: 0,
+#endif /* PAGESIZE */
+ detachstate: PTHREAD_CREATE_JOINABLE,
+ inheritsched: PTHREAD_EXPLICIT_SCHED,
+ contentionscope: PTHREAD_SCOPE_SYSTEM,
+ schedpolicy: SCHED_OTHER
+};
diff --git a/libpthread/sysdeps/generic/pt-barrier-destroy.c b/libpthread/sysdeps/generic/pt-barrier-destroy.c
new file mode 100644
index 00000000..01b938b4
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrier-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_barrier_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_barrier_destroy (pthread_barrier_t *barrier)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-barrier-init.c b/libpthread/sysdeps/generic/pt-barrier-init.c
new file mode 100644
index 00000000..c42b3bb6
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrier-init.c
@@ -0,0 +1,53 @@
+/* pthread_barrier_init. Generic version.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <string.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+pthread_barrier_init (pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr,
+ unsigned count)
+{
+ if (count == 0)
+ return EINVAL;
+
+ memset (barrier, 0, sizeof *barrier);
+
+ barrier->lock = PTHREAD_SPINLOCK_INITIALIZER;
+ barrier->pending = count;
+ barrier->count = count;
+
+ if (! attr
+ || memcmp (attr, &__pthread_default_barrierattr, sizeof (*attr) == 0))
+ /* Use the default attributes. */
+ return 0;
+
+ /* Non-default attributes. */
+
+ barrier->attr = malloc (sizeof *attr);
+ if (! barrier->attr)
+ return ENOMEM;
+
+ *barrier->attr = *attr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-barrier-wait.c b/libpthread/sysdeps/generic/pt-barrier-wait.c
new file mode 100644
index 00000000..f1de250a
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrier-wait.c
@@ -0,0 +1,61 @@
+/* pthread_barrier_wait. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+pthread_barrier_wait (pthread_barrier_t *barrier)
+{
+ __pthread_spin_lock (&barrier->lock);
+ if (-- barrier->pending == 0)
+ {
+ barrier->pending = barrier->count;
+
+ if (barrier->count > 1)
+ {
+ struct __pthread *wakeup;
+
+ wakeup = barrier->queue;
+ barrier->queue = NULL;
+ __pthread_spin_unlock (&barrier->lock);
+
+ /* We can safely walk the list of waiting threads without
+ holding the lock since it is decoupled from the barrier
+ variable now. */
+ __pthread_dequeuing_iterate (wakeup, wakeup)
+ __pthread_wakeup (wakeup);
+ }
+
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ else
+ {
+ struct __pthread *self = _pthread_self ();
+
+ /* Add ourselves to the list of waiters. */
+ __pthread_enqueue (&barrier->queue, self);
+ __pthread_spin_unlock (&barrier->lock);
+
+ __pthread_block (self);
+ return 0;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-barrier.c b/libpthread/sysdeps/generic/pt-barrier.c
new file mode 100644
index 00000000..d772719f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrier.c
@@ -0,0 +1,26 @@
+/* Default barrier attributes. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+const struct __pthread_barrierattr __pthread_default_barrierattr =
+{
+ pshared: PTHREAD_PROCESS_PRIVATE
+};
diff --git a/libpthread/sysdeps/generic/pt-barrierattr-destroy.c b/libpthread/sysdeps/generic/pt-barrierattr-destroy.c
new file mode 100644
index 00000000..eb396347
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrierattr-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_barrierattr_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_barrierattr_destroy (pthread_barrierattr_t *attr)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-barrierattr-getpshared.c b/libpthread/sysdeps/generic/pt-barrierattr-getpshared.c
new file mode 100644
index 00000000..ed2cdd24
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrierattr-getpshared.c
@@ -0,0 +1,29 @@
+/* pthread_barrierattr_getpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_barrierattr_getpshared (const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+ *pshared = attr->pshared;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-barrierattr-init.c b/libpthread/sysdeps/generic/pt-barrierattr-init.c
new file mode 100644
index 00000000..45f16cc8
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrierattr-init.c
@@ -0,0 +1,28 @@
+/* pthread_barrierattr_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_barrierattr_init (pthread_barrierattr_t *attr)
+{
+ *attr = __pthread_default_barrierattr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-barrierattr-setpshared.c b/libpthread/sysdeps/generic/pt-barrierattr-setpshared.c
new file mode 100644
index 00000000..84ef2df8
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-barrierattr-setpshared.c
@@ -0,0 +1,39 @@
+/* pthread_barrierattr_setpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_barrierattr_setpshared (pthread_barrierattr_t *attr,
+ int pshared)
+{
+ switch (pshared)
+ {
+ case PTHREAD_PROCESS_PRIVATE:
+ attr->pshared = pshared;
+ return 0;
+
+ case PTHREAD_PROCESS_SHARED:
+ return ENOTSUP;
+
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-brdcast.c b/libpthread/sysdeps/generic/pt-cond-brdcast.c
new file mode 100644
index 00000000..3f55e33e
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-brdcast.c
@@ -0,0 +1,42 @@
+/* Broadcast a condition. Generic version.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+/* Unblock all threads that are blocked on condition variable COND. */
+int
+pthread_cond_broadcast (pthread_cond_t *cond)
+{
+ struct __pthread *wakeup;
+
+ __pthread_spin_lock (&cond->__lock);
+
+ wakeup = cond->__queue;
+ cond->__queue = NULL;
+ __pthread_spin_unlock (&cond->__lock);
+
+ /* We can safely walk the list of waiting threads without holding
+ the lock since it is now decoupled from the condition. */
+ __pthread_dequeuing_iterate (wakeup, wakeup)
+ __pthread_wakeup (wakeup);
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-destroy.c b/libpthread/sysdeps/generic/pt-cond-destroy.c
new file mode 100644
index 00000000..eba47784
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_cond_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_cond_destroy (pthread_cond_t *cond)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-init.c b/libpthread/sysdeps/generic/pt-cond-init.c
new file mode 100644
index 00000000..b9e9fb7a
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-init.c
@@ -0,0 +1,45 @@
+/* pthread_cond_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+int
+pthread_cond_init (pthread_cond_t *cond,
+ const pthread_condattr_t *attr)
+{
+ *cond = (pthread_cond_t) __PTHREAD_COND_INITIALIZER;
+
+ if (! attr
+ || memcmp (attr, &__pthread_default_condattr, sizeof (*attr) == 0))
+ /* Use the default attributes. */
+ return 0;
+
+ /* Non-default attributes. */
+
+ cond->__attr = malloc (sizeof *attr);
+ if (! cond->__attr)
+ return ENOMEM;
+
+ *cond->__attr = *attr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-signal.c b/libpthread/sysdeps/generic/pt-cond-signal.c
new file mode 100644
index 00000000..c5e1bc1d
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-signal.c
@@ -0,0 +1,54 @@
+/* Signal a condition. Generic version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+static int
+cond_signal (struct __pthread_cond *cond, int *unblocked)
+{
+ struct __pthread *wakeup;
+
+ __pthread_spin_lock (&cond->__lock);
+ wakeup = cond->__queue;
+ if (wakeup)
+ __pthread_dequeue (wakeup);
+ __pthread_spin_unlock (&cond->__lock);
+
+ if (wakeup)
+ {
+ /* We found a thread waiting for the condition to be signalled.
+ Wake it up! */
+ __pthread_wakeup (wakeup);
+ *unblocked = 1;
+ }
+
+ return 0;
+}
+
+/* Unblock at least one of the threads that are blocked on condition
+ variable COND. */
+int
+pthread_cond_signal (pthread_cond_t *cond)
+{
+ int unblocked = 0;
+
+ return cond_signal (cond, &unblocked);
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-timedwait.c b/libpthread/sysdeps/generic/pt-cond-timedwait.c
new file mode 100644
index 00000000..c10bdb30
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-timedwait.c
@@ -0,0 +1,106 @@
+/* Wait on a condition. Generic version.
+ Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+extern int __pthread_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+int
+pthread_cond_timedwait (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ return __pthread_cond_timedwait_internal (cond, mutex, abstime);
+}
+
+/* Block on condition variable COND until ABSTIME. As a GNU
+ extension, if ABSTIME is NULL, then wait forever. MUTEX should be
+ held by the calling thread. On return, MUTEX will be held by the
+ calling thread. */
+int
+__pthread_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ error_t err;
+ int canceltype;
+
+ void cleanup (void *arg)
+ {
+ struct __pthread *self = _pthread_self ();
+
+ __pthread_spin_lock (&cond->__lock);
+ if (self->prevp)
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&cond->__lock);
+
+ pthread_setcanceltype (canceltype, &canceltype);
+ __pthread_mutex_lock (mutex);
+ }
+
+ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+ return EINVAL;
+
+ struct __pthread *self = _pthread_self ();
+
+ /* Add ourselves to the list of waiters. */
+ __pthread_spin_lock (&cond->__lock);
+ __pthread_enqueue (&cond->__queue, self);
+ __pthread_spin_unlock (&cond->__lock);
+
+ __pthread_mutex_unlock (mutex);
+
+ /* Enter async cancelation mode. If cancelation is disabled, then
+ this does not change anything which is exactly what we want. */
+ pthread_cleanup_push (cleanup, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &canceltype);
+
+ if (abstime)
+ {
+ err = __pthread_timedblock (self, abstime);
+ if (err)
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ {
+ assert (err == ETIMEDOUT);
+
+ __pthread_spin_lock (&mutex->__lock);
+ if (self->prevp)
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&mutex->__lock);
+ }
+ }
+ else
+ {
+ err = 0;
+ __pthread_block (self);
+ }
+
+ pthread_cleanup_pop (1);
+
+ return err;
+}
diff --git a/libpthread/sysdeps/generic/pt-cond-wait.c b/libpthread/sysdeps/generic/pt-cond-wait.c
new file mode 100644
index 00000000..a03476df
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond-wait.c
@@ -0,0 +1,37 @@
+/* Wait on a condition. Generic version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+/* Implemented in pt-cond-timedwait.c. */
+extern int __pthread_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+
+/* Block on condition variable COND. MUTEX should be held by the
+ calling thread. On return, MUTEX will be held by the calling
+ thread. */
+int
+pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ return __pthread_cond_timedwait_internal (cond, mutex, 0);
+}
diff --git a/libpthread/sysdeps/generic/pt-cond.c b/libpthread/sysdeps/generic/pt-cond.c
new file mode 100644
index 00000000..033e767f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-cond.c
@@ -0,0 +1,29 @@
+/* Default condition attributes. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <time.h>
+
+#include <pt-internal.h>
+
+const struct __pthread_condattr __pthread_default_condattr =
+{
+ pshared: PTHREAD_PROCESS_PRIVATE,
+ clock: CLOCK_REALTIME
+};
diff --git a/libpthread/sysdeps/generic/pt-condattr-destroy.c b/libpthread/sysdeps/generic/pt-condattr-destroy.c
new file mode 100644
index 00000000..c8fd71b9
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_condattr_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_condattr_destroy (pthread_condattr_t *cond)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-condattr-getclock.c b/libpthread/sysdeps/generic/pt-condattr-getclock.c
new file mode 100644
index 00000000..5b9f8893
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-getclock.c
@@ -0,0 +1,31 @@
+/* pthread_condattr_getclock. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <time.h>
+
+#include <pt-internal.h>
+
+int
+pthread_condattr_getclock (const pthread_condattr_t *attr,
+ clockid_t *clock)
+{
+ *clock = attr->clock;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-condattr-getpshared.c b/libpthread/sysdeps/generic/pt-condattr-getpshared.c
new file mode 100644
index 00000000..c072a507
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-getpshared.c
@@ -0,0 +1,29 @@
+/* pthread_condattr_getpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_condattr_getpshared (const pthread_condattr_t *attr,
+ int *pshared)
+{
+ *pshared = attr->pshared;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-condattr-init.c b/libpthread/sysdeps/generic/pt-condattr-init.c
new file mode 100644
index 00000000..cf9e1989
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-init.c
@@ -0,0 +1,28 @@
+/* pthread_condattr_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_condattr_init (pthread_condattr_t *attr)
+{
+ *attr = __pthread_default_condattr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-condattr-setclock.c b/libpthread/sysdeps/generic/pt-condattr-setclock.c
new file mode 100644
index 00000000..984c17e2
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-setclock.c
@@ -0,0 +1,33 @@
+/* pthread_condattr_setclock. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock)
+{
+ if (__pthread_default_condattr.clock == clock)
+ {
+ attr->clock = clock;
+ return 0;
+ }
+
+ return EINVAL;
+}
diff --git a/libpthread/sysdeps/generic/pt-condattr-setpshared.c b/libpthread/sysdeps/generic/pt-condattr-setpshared.c
new file mode 100644
index 00000000..b9f0af83
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-condattr-setpshared.c
@@ -0,0 +1,39 @@
+/* pthread_condattr_setpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_condattr_setpshared (pthread_condattr_t *attr,
+ int pshared)
+{
+ switch (pshared)
+ {
+ case PTHREAD_PROCESS_PRIVATE:
+ attr->pshared = pshared;
+ return 0;
+
+ case PTHREAD_PROCESS_SHARED:
+ return ENOTSUP;
+
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-destroy-specific.c b/libpthread/sysdeps/generic/pt-destroy-specific.c
new file mode 100644
index 00000000..b627f872
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-destroy-specific.c
@@ -0,0 +1,28 @@
+/* __pthread_destory_specific. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+void
+__pthread_destory_specifc (struct __pthread *thread)
+{
+ /* Not support, thus there cannot be any. */
+ return;
+}
diff --git a/libpthread/sysdeps/generic/pt-equal.c b/libpthread/sysdeps/generic/pt-equal.c
new file mode 100644
index 00000000..8fbc519c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-equal.c
@@ -0,0 +1,29 @@
+/* Default attributes. Generic version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+/* Return true if __T1 and __T2 both name the same thread. Otherwise,
+ false. */
+int
+pthread_equal (pthread_t __t1, pthread_t __t2)
+{
+ return __t1 == __t2;
+}
diff --git a/libpthread/sysdeps/generic/pt-getconcurrency.c b/libpthread/sysdeps/generic/pt-getconcurrency.c
new file mode 100644
index 00000000..b55c8eef
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-getconcurrency.c
@@ -0,0 +1,27 @@
+/* Get the current level of desired concurrency. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_getconcurrency (void)
+{
+ return __pthread_concurrency;
+}
diff --git a/libpthread/sysdeps/generic/pt-getcpuclockid.c b/libpthread/sysdeps/generic/pt-getcpuclockid.c
new file mode 100644
index 00000000..81f6aabd
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-getcpuclockid.c
@@ -0,0 +1,34 @@
+/* Return a thread's cpu clockid. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <time.h>
+
+#include <pt-internal.h>
+
+int
+pthread_getcpuclockid (pthread_t thread, clockid_t *clock)
+{
+#ifdef CLOCK_THREAD_CPUTIME_ID
+ *clock = CLOCK_THREAD_CPUTIME_ID;
+ return 0;
+#else
+ return ENOSYS;
+#endif
+}
diff --git a/libpthread/sysdeps/generic/pt-getschedparam.c b/libpthread/sysdeps/generic/pt-getschedparam.c
new file mode 100644
index 00000000..c128d02e
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-getschedparam.c
@@ -0,0 +1,28 @@
+/* Get the scheduling parameters for a thread. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_getschedparam (pthread_t thread, int *policy,
+ struct sched_param *param)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-getspecific.c b/libpthread/sysdeps/generic/pt-getspecific.c
new file mode 100644
index 00000000..2a7c4a9e
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-getspecific.c
@@ -0,0 +1,27 @@
+/* pthread_getspecific. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_getspecific (pthread_key_t key)
+{
+ return EINVAL;
+}
diff --git a/libpthread/sysdeps/generic/pt-init-specific.c b/libpthread/sysdeps/generic/pt-init-specific.c
new file mode 100644
index 00000000..00744fb6
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-init-specific.c
@@ -0,0 +1,27 @@
+/* __pthread_init_specific. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+error_t
+__pthread_init_specific (struct __pthread *thread)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-key-create.c b/libpthread/sysdeps/generic/pt-key-create.c
new file mode 100644
index 00000000..7ef4b991
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-key-create.c
@@ -0,0 +1,27 @@
+/* pthread_key_create. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-key-delete.c b/libpthread/sysdeps/generic/pt-key-delete.c
new file mode 100644
index 00000000..6c86f8e2
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-key-delete.c
@@ -0,0 +1,27 @@
+/* pthread_key_delete. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_key_delete (pthread_key_t key)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-key.h b/libpthread/sysdeps/generic/pt-key.h
new file mode 100644
index 00000000..544eb20f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-key.h
@@ -0,0 +1,22 @@
+/* pthread_key internal declatations. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#define PTHREAD_KEY_MEMBERS
diff --git a/libpthread/sysdeps/generic/pt-kill.c b/libpthread/sysdeps/generic/pt-kill.c
new file mode 100644
index 00000000..0dfac344
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/pt-mutex-destroy.c b/libpthread/sysdeps/generic/pt-mutex-destroy.c
new file mode 100644
index 00000000..3bbc73fe
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-destroy.c
@@ -0,0 +1,39 @@
+/* Destroy a mutex. Generic version.
+ Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+_pthread_mutex_destroy (pthread_mutex_t *mutex)
+{
+ if (mutex->attr == __PTHREAD_ERRORCHECK_MUTEXATTR
+ || mutex->attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ /* Static attributes. */
+ ;
+ else
+ free (mutex->attr);
+
+ return 0;
+}
+
+strong_alias (_pthread_mutex_destroy, pthread_mutex_destroy);
diff --git a/libpthread/sysdeps/generic/pt-mutex-getprioceiling.c b/libpthread/sysdeps/generic/pt-mutex-getprioceiling.c
new file mode 100644
index 00000000..eb51639b
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-getprioceiling.c
@@ -0,0 +1,28 @@
+/* Get a mutex' priority ceiling. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutex-init.c b/libpthread/sysdeps/generic/pt-mutex-init.c
new file mode 100644
index 00000000..2f960286
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-init.c
@@ -0,0 +1,50 @@
+/* Initialize a mutex. Generic version.
+ Copyright (C) 2000, 2002, 2005, 2006, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+_pthread_mutex_init (pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *attr)
+{
+ *mutex = (pthread_mutex_t) __PTHREAD_MUTEX_INITIALIZER;
+
+ if (! attr
+ || memcmp (attr, &__pthread_default_mutexattr, sizeof (*attr) == 0))
+ /* The default attributes. */
+ return 0;
+
+ if (! mutex->attr
+ || mutex->attr == __PTHREAD_ERRORCHECK_MUTEXATTR
+ || mutex->attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ mutex->attr = malloc (sizeof *attr);
+
+ if (! mutex->attr)
+ return ENOMEM;
+
+ *mutex->attr = *attr;
+ return 0;
+}
+
+strong_alias (_pthread_mutex_init, pthread_mutex_init);
diff --git a/libpthread/sysdeps/generic/pt-mutex-lock.c b/libpthread/sysdeps/generic/pt-mutex-lock.c
new file mode 100644
index 00000000..528e593f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-lock.c
@@ -0,0 +1,37 @@
+/* Lock a mutex. Generic version.
+ Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Implemented in pt-mutex-timedlock.c. */
+extern int __pthread_mutex_timedlock_internal (struct __pthread_mutex *mutex,
+ const struct timespec *abstime);
+
+/* Lock MUTEX, block if we can't get it. */
+int
+__pthread_mutex_lock (struct __pthread_mutex *mutex)
+{
+ return __pthread_mutex_timedlock_internal (mutex, 0);
+}
+
+strong_alias (__pthread_mutex_lock, _pthread_mutex_lock);
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock);
diff --git a/libpthread/sysdeps/generic/pt-mutex-setprioceiling.c b/libpthread/sysdeps/generic/pt-mutex-setprioceiling.c
new file mode 100644
index 00000000..9fa8e50d
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-setprioceiling.c
@@ -0,0 +1,28 @@
+/* Set a mutex' priority ceiling. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prio,
+ int *oldprio)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutex-timedlock.c b/libpthread/sysdeps/generic/pt-mutex-timedlock.c
new file mode 100644
index 00000000..883e50af
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-timedlock.c
@@ -0,0 +1,187 @@
+/* Lock a mutex with a timeout. Generic version.
+ Copyright (C) 2000, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+#define LOSE do { * (int *) 0 = 0; } while (1)
+
+/* Try to lock MUTEX, block until *ABSTIME if it is already held. As
+ a GNU extension, if TIMESPEC is NULL then wait forever. */
+int
+__pthread_mutex_timedlock_internal (struct __pthread_mutex *mutex,
+ const struct timespec *abstime)
+{
+ struct __pthread *self;
+ const struct __pthread_mutexattr *attr = mutex->attr;
+
+ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR)
+ attr = &__pthread_errorcheck_mutexattr;
+ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ attr = &__pthread_recursive_mutexattr;
+
+ __pthread_spin_lock (&mutex->__lock);
+ if (__pthread_spin_trylock (&mutex->__held) == 0)
+ /* Successfully acquired the lock. */
+ {
+#ifdef ALWAYS_TRACK_MUTEX_OWNER
+#ifndef NDEBUG
+ self = _pthread_self ();
+ if (self)
+ /* The main thread may take a lock before the library is fully
+ initialized, in particular, before the main thread has a
+ TCB. */
+ {
+ assert (! mutex->owner);
+ mutex->owner = _pthread_self ();
+ }
+#endif
+#endif
+
+ if (attr)
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_NORMAL:
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ mutex->locks = 1;
+ case PTHREAD_MUTEX_ERRORCHECK:
+ mutex->owner = _pthread_self ();
+ break;
+
+ default:
+ LOSE;
+ }
+
+ __pthread_spin_unlock (&mutex->__lock);
+ return 0;
+ }
+
+ /* The lock is busy. */
+
+ self = _pthread_self ();
+ assert (self);
+
+ if (! attr || attr->mutex_type == PTHREAD_MUTEX_NORMAL)
+ {
+#if defined(ALWAYS_TRACK_MUTEX_OWNER)
+ assert (mutex->owner != self);
+#endif
+ }
+ else
+ {
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ if (mutex->owner == self)
+ {
+ __pthread_spin_unlock (&mutex->__lock);
+ return EDEADLK;
+ }
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ if (mutex->owner == self)
+ {
+ mutex->locks ++;
+ __pthread_spin_unlock (&mutex->__lock);
+ return 0;
+ }
+ break;
+
+ default:
+ LOSE;
+ }
+ }
+
+#if !defined(ALWAYS_TRACK_MUTEX_OWNER)
+ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL)
+#endif
+ assert (mutex->owner);
+
+ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+ return EINVAL;
+
+ /* Add ourselves to the queue. */
+ __pthread_enqueue (&mutex->__queue, self);
+ __pthread_spin_unlock (&mutex->__lock);
+
+ /* Block the thread. */
+ if (abstime)
+ {
+ error_t err;
+
+ err = __pthread_timedblock (self, abstime);
+ if (err)
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ {
+ assert (err == ETIMEDOUT);
+
+ __pthread_spin_lock (&mutex->__lock);
+ if (self->prevp)
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&mutex->__lock);
+
+ return err;
+ }
+ }
+ else
+ __pthread_block (self);
+
+#if !defined(ALWAYS_TRACK_MUTEX_OWNER)
+ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL)
+#endif
+ {
+ assert (mutex->owner == self);
+ }
+
+ if (attr)
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_NORMAL:
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ assert (mutex->locks == 0);
+ mutex->locks = 1;
+ case PTHREAD_MUTEX_ERRORCHECK:
+ mutex->owner = self;
+ break;
+
+ default:
+ LOSE;
+ }
+
+ return 0;
+}
+
+int
+pthread_mutex_timedlock (struct __pthread_mutex *mutex,
+ const struct timespec *abstime)
+{
+ return __pthread_mutex_timedlock_internal (mutex, abstime);
+}
diff --git a/libpthread/sysdeps/generic/pt-mutex-transfer-np.c b/libpthread/sysdeps/generic/pt-mutex-transfer-np.c
new file mode 100644
index 00000000..967f1c7c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-transfer-np.c
@@ -0,0 +1,66 @@
+/* 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);
+ const struct __pthread_mutexattr *attr = mutex->attr;
+
+ if (! thread)
+ return ESRCH;
+
+ if (thread == _pthread_self ())
+ return 0;
+
+ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR)
+ attr = &__pthread_errorcheck_mutexattr;
+ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ attr = &__pthread_recursive_mutexattr;
+
+ if (attr && attr->mutex_type == PTHREAD_MUTEX_ERRORCHECK)
+ {
+
+ if (mutex->owner != _pthread_self ())
+ return EPERM;
+
+ mutex->owner = thread;
+ }
+
+#ifndef NDEBUG
+# if !defined(ALWAYS_TRACK_MUTEX_OWNER)
+ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL)
+# endif
+ {
+ mutex->owner = thread;
+ }
+#endif
+
+ return 0;
+}
+
+strong_alias (__pthread_mutex_transfer_np, pthread_mutex_transfer_np)
diff --git a/libpthread/sysdeps/generic/pt-mutex-trylock.c b/libpthread/sysdeps/generic/pt-mutex-trylock.c
new file mode 100644
index 00000000..7a54cc9a
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-trylock.c
@@ -0,0 +1,112 @@
+/* Try to Lock a mutex. Generic version.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+#define LOSE do { * (int *) 0 = 0; } while (1)
+
+/* Lock MUTEX, return EBUSY if we can't get it. */
+int
+__pthread_mutex_trylock (struct __pthread_mutex *mutex)
+{
+ int err;
+ struct __pthread *self;
+ const struct __pthread_mutexattr *attr = mutex->attr;
+
+ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR)
+ attr = &__pthread_errorcheck_mutexattr;
+ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ attr = &__pthread_recursive_mutexattr;
+
+ __pthread_spin_lock (&mutex->__lock);
+ if (__pthread_spin_trylock (&mutex->__held) == 0)
+ /* Acquired the lock. */
+ {
+#if defined(ALWAYS_TRACK_MUTEX_OWNER)
+#ifndef NDEBUG
+ self = _pthread_self ();
+ if (self)
+ /* The main thread may take a lock before the library is fully
+ initialized, in particular, before the main thread has a
+ TCB. */
+ {
+ assert (! mutex->owner);
+ mutex->owner = _pthread_self ();
+ }
+#endif
+#endif
+
+ if (attr)
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_NORMAL:
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ mutex->locks = 1;
+ case PTHREAD_MUTEX_ERRORCHECK:
+ mutex->owner = _pthread_self ();
+ break;
+
+ default:
+ LOSE;
+ }
+
+ __pthread_spin_unlock (&mutex->__lock);
+ return 0;
+ }
+
+ err = EBUSY;
+
+ if (attr)
+ {
+ self = _pthread_self ();
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_NORMAL:
+ break;
+
+ case PTHREAD_MUTEX_ERRORCHECK:
+ /* We could check if MUTEX->OWNER is SELF, however, POSIX
+ does not permit pthread_mutex_trylock to return EDEADLK
+ instead of EBUSY, only pthread_mutex_lock. */
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ if (mutex->owner == self)
+ {
+ mutex->locks ++;
+ err = 0;
+ }
+ break;
+
+ default:
+ LOSE;
+ }
+ }
+
+ __pthread_spin_unlock (&mutex->__lock);
+
+ return err;
+}
+
+strong_alias (__pthread_mutex_trylock, _pthread_mutex_trylock);
+strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock);
diff --git a/libpthread/sysdeps/generic/pt-mutex-unlock.c b/libpthread/sysdeps/generic/pt-mutex-unlock.c
new file mode 100644
index 00000000..09d70f8f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutex-unlock.c
@@ -0,0 +1,108 @@
+/* Unlock a mutex. Generic version.
+ Copyright (C) 2000, 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+#define LOSE do { * (int *) 0 = 0; } while (1)
+
+/* Unlock MUTEX, rescheduling a waiting thread. */
+int
+__pthread_mutex_unlock (pthread_mutex_t *mutex)
+{
+ struct __pthread *wakeup;
+ const struct __pthread_mutexattr *attr = mutex->attr;
+
+ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR)
+ attr = &__pthread_errorcheck_mutexattr;
+ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR)
+ attr = &__pthread_recursive_mutexattr;
+
+ __pthread_spin_lock (&mutex->__lock);
+
+ if (! attr || attr->mutex_type == PTHREAD_MUTEX_NORMAL)
+ {
+#if defined(ALWAYS_TRACK_MUTEX_OWNER)
+# ifndef NDEBUG
+ if (_pthread_self ())
+ {
+ assert (mutex->owner);
+ assert (mutex->owner == _pthread_self ());
+ mutex->owner = NULL;
+ }
+# endif
+#endif
+ }
+ else
+ switch (attr->mutex_type)
+ {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_RECURSIVE:
+ if (mutex->owner != _pthread_self ())
+ {
+ __pthread_spin_unlock (&mutex->__lock);
+ return EPERM;
+ }
+
+ if (attr->mutex_type == PTHREAD_MUTEX_RECURSIVE)
+ if (--mutex->locks > 0)
+ {
+ __pthread_spin_unlock (&mutex->__lock);
+ return 0;
+ }
+
+ mutex->owner = 0;
+ break;
+
+ default:
+ LOSE;
+ }
+
+
+ if (mutex->__queue == NULL)
+ {
+ __pthread_spin_unlock (&mutex->__held);
+ __pthread_spin_unlock (&mutex->__lock);
+ return 0;
+ }
+
+ wakeup = mutex->__queue;
+ __pthread_dequeue (wakeup);
+
+#ifndef NDEBUG
+# if !defined (ALWAYS_TRACK_MUTEX_OWNER)
+ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL)
+# endif
+ {
+ mutex->owner = wakeup;
+ }
+#endif
+
+ /* We do not unlock MUTEX->held: we are transferring the ownership
+ to the thread that we are waking up. */
+
+ __pthread_spin_unlock (&mutex->__lock);
+ __pthread_wakeup (wakeup);
+
+ return 0;
+}
+
+strong_alias (__pthread_mutex_unlock, _pthread_mutex_unlock);
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock);
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-destroy.c b/libpthread/sysdeps/generic/pt-mutexattr-destroy.c
new file mode 100644
index 00000000..fe7e95d2
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_mutexattr_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c b/libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c
new file mode 100644
index 00000000..d03d7192
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c
@@ -0,0 +1,28 @@
+/* pthread_mutexattr_getprioceiling. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
+ int *prioceiling)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-getprotocol.c b/libpthread/sysdeps/generic/pt-mutexattr-getprotocol.c
new file mode 100644
index 00000000..d75021a3
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-getprotocol.c
@@ -0,0 +1,29 @@
+/* pthread_mutexattr_getprotocol. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
+ int *protocol)
+{
+ *protocol = attr->protocol;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-getpshared.c b/libpthread/sysdeps/generic/pt-mutexattr-getpshared.c
new file mode 100644
index 00000000..0dad13b8
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-getpshared.c
@@ -0,0 +1,29 @@
+/* pthread_mutexattr_getpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
+ int *pshared)
+{
+ *pshared = attr->pshared;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-gettype.c b/libpthread/sysdeps/generic/pt-mutexattr-gettype.c
new file mode 100644
index 00000000..ff2caea4
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-gettype.c
@@ -0,0 +1,28 @@
+/* pthread_mutexattr_gettype. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
+{
+ *type = attr->mutex_type;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-init.c b/libpthread/sysdeps/generic/pt-mutexattr-init.c
new file mode 100644
index 00000000..2f23673c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-init.c
@@ -0,0 +1,28 @@
+/* pthread_mutexattr_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_init (pthread_mutexattr_t *attr)
+{
+ *attr = __pthread_default_mutexattr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c b/libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c
new file mode 100644
index 00000000..a9bbd327
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c
@@ -0,0 +1,28 @@
+/* pthread_mutexattr_setprioceiling. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
+ int prioceiling)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-setprotocol.c b/libpthread/sysdeps/generic/pt-mutexattr-setprotocol.c
new file mode 100644
index 00000000..9a0d1b1f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-setprotocol.c
@@ -0,0 +1,42 @@
+/* pthread_mutexattr_setprotocol. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr,
+ int protocol)
+{
+ if (protocol == __pthread_default_mutexattr.protocol)
+ {
+ attr->protocol = protocol;
+ return 0;
+ }
+
+ switch (protocol)
+ {
+ case PTHREAD_PRIO_NONE:
+ case PTHREAD_PRIO_INHERIT:
+ case PTHREAD_PRIO_PROTECT:
+ return ENOTSUP;
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-setpshared.c b/libpthread/sysdeps/generic/pt-mutexattr-setpshared.c
new file mode 100644
index 00000000..bcbc4d91
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-setpshared.c
@@ -0,0 +1,39 @@
+/* pthread_mutexattr_setpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_setpshared (pthread_mutexattr_t *attr,
+ int pshared)
+{
+ switch (pshared)
+ {
+ case PTHREAD_PROCESS_PRIVATE:
+ attr->pshared = pshared;
+ return 0;
+
+ case PTHREAD_PROCESS_SHARED:
+ return ENOTSUP;
+
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr-settype.c b/libpthread/sysdeps/generic/pt-mutexattr-settype.c
new file mode 100644
index 00000000..e7ae213a
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr-settype.c
@@ -0,0 +1,37 @@
+/* pthread_mutexattr_settype. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
+{
+ switch (type)
+ {
+ case PTHREAD_MUTEX_NORMAL:
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_RECURSIVE:
+ attr->mutex_type = type;
+ return 0;
+
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-mutexattr.c b/libpthread/sysdeps/generic/pt-mutexattr.c
new file mode 100644
index 00000000..5ebde6ea
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-mutexattr.c
@@ -0,0 +1,45 @@
+/* Default mutex attributes. Generic version.
+ Copyright (C) 2000, 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+const struct __pthread_mutexattr __pthread_default_mutexattr =
+{
+ prioceiling: 0,
+ protocol: PTHREAD_PRIO_NONE,
+ pshared: PTHREAD_PROCESS_PRIVATE,
+ mutex_type: PTHREAD_MUTEX_DEFAULT
+};
+
+const struct __pthread_mutexattr __pthread_errorcheck_mutexattr =
+{
+ prioceiling: 0,
+ protocol: PTHREAD_PRIO_NONE,
+ pshared: PTHREAD_PROCESS_PRIVATE,
+ mutex_type: PTHREAD_MUTEX_ERRORCHECK
+};
+
+const struct __pthread_mutexattr __pthread_recursive_mutexattr =
+{
+ prioceiling: 0,
+ protocol: PTHREAD_PRIO_NONE,
+ pshared: PTHREAD_PROCESS_PRIVATE,
+ mutex_type: PTHREAD_MUTEX_RECURSIVE
+};
diff --git a/libpthread/sysdeps/generic/pt-once.c b/libpthread/sysdeps/generic/pt-once.c
new file mode 100644
index 00000000..5be5e484
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-once.c
@@ -0,0 +1,43 @@
+/* pthread_once. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <bits/memory.h>
+
+#include <pt-internal.h>
+
+int
+pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+ if (once_control->run == 0)
+ {
+ __pthread_spin_lock (&once_control->lock);
+
+ if (once_control->run == 0)
+ {
+ init_routine ();
+ __memory_barrier ();
+ once_control->run = 1;
+ }
+
+ __pthread_spin_unlock (&once_control->lock);
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-attr.c b/libpthread/sysdeps/generic/pt-rwlock-attr.c
new file mode 100644
index 00000000..1587feef
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-attr.c
@@ -0,0 +1,26 @@
+/* Default rwlock attributes. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+const struct __pthread_rwlockattr __pthread_default_rwlockattr =
+{
+ pshared: PTHREAD_PROCESS_PRIVATE
+};
diff --git a/libpthread/sysdeps/generic/pt-rwlock-destroy.c b/libpthread/sysdeps/generic/pt-rwlock-destroy.c
new file mode 100644
index 00000000..045eebd8
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-destroy.c
@@ -0,0 +1,29 @@
+/* Destroy a rwlock. Generic version.
+ Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ return 0;
+}
+
+strong_alias (_pthread_rwlock_destroy, pthread_rwlock_destroy);
diff --git a/libpthread/sysdeps/generic/pt-rwlock-init.c b/libpthread/sysdeps/generic/pt-rwlock-init.c
new file mode 100644
index 00000000..c9ff9b28
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-init.c
@@ -0,0 +1,45 @@
+/* Initialize a rwlock. Generic version.
+ Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <string.h>
+#include <pt-internal.h>
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock,
+ const pthread_rwlockattr_t *attr)
+{
+ *rwlock = (pthread_rwlock_t) __PTHREAD_RWLOCK_INITIALIZER;
+
+ if (! attr
+ || memcmp (attr, &__pthread_default_rwlockattr, sizeof (*attr) == 0))
+ /* Use the default attributes. */
+ return 0;
+
+ /* Non-default attributes. */
+
+ rwlock->__attr = malloc (sizeof *attr);
+ if (! rwlock->__attr)
+ return ENOMEM;
+
+ *rwlock->__attr = *attr;
+ return 0;
+}
+
+strong_alias (_pthread_rwlock_init, pthread_rwlock_init);
diff --git a/libpthread/sysdeps/generic/pt-rwlock-rdlock.c b/libpthread/sysdeps/generic/pt-rwlock-rdlock.c
new file mode 100644
index 00000000..480cf489
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-rdlock.c
@@ -0,0 +1,32 @@
+/* Acquire a rwlock for reading. Generic version.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+/* Implemented in pt-rwlock-timedrdlock.c. */
+extern int __pthread_rwlock_timedrdlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime);
+
+/* Acquire RWLOCK for reading, block if we can't get it. */
+int
+pthread_rwlock_rdlock (struct __pthread_rwlock *rwlock)
+{
+ return __pthread_rwlock_timedrdlock_internal (rwlock, 0);
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c b/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c
new file mode 100644
index 00000000..ba610fa5
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c
@@ -0,0 +1,113 @@
+/* Acquire a rwlock for reading. Generic version.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Acquire the rwlock *RWLOCK for reading blocking until *ABSTIME if
+ it is already held. As a GNU extension, if TIMESPEC is NULL then
+ wait forever. */
+int
+__pthread_rwlock_timedrdlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+{
+ struct __pthread *self;
+
+ __pthread_spin_lock (&rwlock->__lock);
+ if (__pthread_spin_trylock (&rwlock->__held) == 0)
+ /* Successfully acquired the lock. */
+ {
+ assert (rwlock->readerqueue == 0);
+ assert (rwlock->writerqueue == 0);
+ assert (rwlock->readers == 0);
+
+ rwlock->readers = 1;
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+ else
+ /* Lock is held, but is held by a reader? */
+ if (rwlock->readers > 0)
+ /* Just add ourself to number of readers. */
+ {
+ assert (rwlock->readerqueue == 0);
+ rwlock->readers ++;
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+
+ /* The lock is busy. */
+
+ /* Better be blocked by a writer. */
+ assert (rwlock->readers == 0);
+
+ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+ return EINVAL;
+
+ self = _pthread_self ();
+
+ /* Add ourself to the queue. */
+ __pthread_enqueue (&rwlock->readerqueue, self);
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ /* Block the thread. */
+ if (abstime)
+ {
+ error_t err;
+
+ err = __pthread_timedblock (self, abstime);
+ if (err)
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ {
+ assert (err == ETIMEDOUT);
+
+ __pthread_spin_lock (&rwlock->__lock);
+ if (self->prevp)
+ /* Disconnect ourself. */
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ return err;
+ }
+ }
+ else
+ __pthread_block (self);
+
+
+ /* The reader count has already been increment by whoever woke us
+ up. */
+
+ assert (rwlock->readers > 0);
+
+ return 0;
+}
+
+int
+pthread_rwlock_timedrdlock (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+{
+ return __pthread_rwlock_timedrdlock_internal (rwlock, abstime);
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c b/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c
new file mode 100644
index 00000000..04eab51f
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c
@@ -0,0 +1,95 @@
+/* Acquire a rwlock for writing. Generic version.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Acquire RWLOCK for writing blocking until *ABSTIME if we cannot get
+ it. As a special GNU extension, if ABSTIME is NULL then the wait
+ shall not time out. */
+int
+__pthread_rwlock_timedwrlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+{
+ struct __pthread *self;
+
+ __pthread_spin_lock (&rwlock->__lock);
+ if (__pthread_spin_trylock (&rwlock->__held) == 0)
+ /* Successfully acquired the lock. */
+ {
+ assert (rwlock->readerqueue == 0);
+ assert (rwlock->writerqueue == 0);
+ assert (rwlock->readers == 0);
+
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+
+ /* The lock is busy. */
+
+ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+ return EINVAL;
+
+ self = _pthread_self ();
+
+ /* Add ourselves to the queue. */
+ __pthread_enqueue (&rwlock->writerqueue, self);
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ /* Block the thread. */
+ if (abstime)
+ {
+ error_t err;
+
+ err = __pthread_timedblock (self, abstime);
+ if (err)
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ {
+ assert (err == ETIMEDOUT);
+
+ __pthread_spin_lock (&rwlock->__lock);
+ if (self->prevp)
+ /* Disconnect ourself. */
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ return err;
+ }
+ }
+ else
+ __pthread_block (self);
+
+ assert (rwlock->readers == 0);
+
+ return 0;
+}
+
+int
+pthread_rwlock_timedwrlock (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+{
+ return __pthread_rwlock_timedwrlock_internal (rwlock, abstime);
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-tryrdlock.c b/libpthread/sysdeps/generic/pt-rwlock-tryrdlock.c
new file mode 100644
index 00000000..2419efb1
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-tryrdlock.c
@@ -0,0 +1,56 @@
+/* Try to acquire a rwlock for reading. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Try to acquire RWLOCK. */
+int
+pthread_rwlock_tryrdlock (struct __pthread_rwlock *rwlock)
+{
+ __pthread_spin_lock (&rwlock->__lock);
+ if (__pthread_spin_trylock (&rwlock->__held) == 0)
+ /* Successfully acquired the lock. */
+ {
+ assert (rwlock->readerqueue == 0);
+ assert (rwlock->writerqueue == 0);
+ assert (rwlock->readers == 0);
+
+ rwlock->readers = 1;
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+ else
+ /* Lock is held, but is held by a reader? */
+ if (rwlock->readers > 0)
+ {
+ assert (rwlock->readerqueue == 0);
+ rwlock->readers ++;
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+
+ /* The lock is busy. */
+
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ return EBUSY;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-trywrlock.c b/libpthread/sysdeps/generic/pt-rwlock-trywrlock.c
new file mode 100644
index 00000000..6b9c5b56
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-trywrlock.c
@@ -0,0 +1,46 @@
+/* Try to acquire a rwlock for writing. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Try to acquire RWLOCK for writing. */
+int
+pthread_rwlock_trywrlock (struct __pthread_rwlock *rwlock)
+{
+ __pthread_spin_lock (&rwlock->__lock);
+ if (__pthread_spin_trylock (&rwlock->__held) == 0)
+ /* Successfully acquired the lock. */
+ {
+ assert (rwlock->readerqueue == 0);
+ assert (rwlock->writerqueue == 0);
+ assert (rwlock->readers == 0);
+
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+
+ /* The lock is busy. */
+
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ return EBUSY;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-unlock.c b/libpthread/sysdeps/generic/pt-rwlock-unlock.c
new file mode 100644
index 00000000..fb23a0b9
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-unlock.c
@@ -0,0 +1,90 @@
+/* Unlock a rwlock. Generic version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+/* Unlock *RWLOCK, rescheduling a waiting writer thread or, if there
+ are no threads waiting for a write lock, rescheduling the reader
+ threads. */
+int
+pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ struct __pthread *wakeup;
+
+ __pthread_spin_lock (&rwlock->__lock);
+
+ assert (__pthread_spin_trylock (&rwlock->__held) == EBUSY);
+
+ if (rwlock->readers > 1)
+ /* There are other readers. */
+ {
+ rwlock->readers --;
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+ }
+
+ if (rwlock->readers == 1)
+ /* Last reader. */
+ rwlock->readers = 0;
+
+
+ /* Wake someone else up. Try the writer queue first, then the
+ reader queue if that is empty. */
+
+ if (rwlock->writerqueue)
+ {
+ wakeup = rwlock->writerqueue;
+ __pthread_dequeue (wakeup);
+
+ /* We do not unlock RWLOCK->held: we are transferring the ownership
+ to the thread that we are waking up. */
+
+ __pthread_spin_unlock (&rwlock->__lock);
+ __pthread_wakeup (wakeup);
+
+ return 0;
+ }
+
+ if (rwlock->readerqueue)
+ {
+ __pthread_queue_iterate (rwlock->readerqueue, wakeup)
+ rwlock->readers ++;
+
+ wakeup = rwlock->readerqueue;
+ rwlock->readerqueue = 0;
+
+ __pthread_spin_unlock (&rwlock->__lock);
+
+ /* We can safely walk the list of waiting threads without holding
+ the lock since it is now decoupled from the rwlock. */
+ __pthread_dequeuing_iterate (wakeup, wakeup)
+ __pthread_wakeup (wakeup);
+
+ return 0;
+ }
+
+
+ /* Noone is waiting. Just unlock it. */
+
+ __pthread_spin_unlock (&rwlock->__held);
+ __pthread_spin_unlock (&rwlock->__lock);
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlock-wrlock.c b/libpthread/sysdeps/generic/pt-rwlock-wrlock.c
new file mode 100644
index 00000000..be85b906
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlock-wrlock.c
@@ -0,0 +1,34 @@
+/* Acquire a rwlock for writing. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+/* Implemented in pt-rwlock-timedwrlock.c. */
+extern int __pthread_rwlock_timedwrlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime);
+
+/* Acquire RWLOCK for writing. */
+int
+pthread_rwlock_wrlock (struct __pthread_rwlock *rwlock)
+{
+ return __pthread_rwlock_timedwrlock_internal (rwlock, 0);
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlockattr-destroy.c b/libpthread/sysdeps/generic/pt-rwlockattr-destroy.c
new file mode 100644
index 00000000..eabfcbe8
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlockattr-destroy.c
@@ -0,0 +1,27 @@
+/* pthread_rwlockattr_destroy. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
+{
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlockattr-getpshared.c b/libpthread/sysdeps/generic/pt-rwlockattr-getpshared.c
new file mode 100644
index 00000000..e8752c0c
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlockattr-getpshared.c
@@ -0,0 +1,29 @@
+/* pthread_rwlockattr_getpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr,
+ int *pshared)
+{
+ *pshared = attr->pshared;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlockattr-init.c b/libpthread/sysdeps/generic/pt-rwlockattr-init.c
new file mode 100644
index 00000000..34da6bf0
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlockattr-init.c
@@ -0,0 +1,28 @@
+/* pthread_rwlockattr_init. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
+{
+ *attr = __pthread_default_rwlockattr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-rwlockattr-setpshared.c b/libpthread/sysdeps/generic/pt-rwlockattr-setpshared.c
new file mode 100644
index 00000000..a861d034
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-rwlockattr-setpshared.c
@@ -0,0 +1,39 @@
+/* pthread_rwlockattr_setpshared. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr,
+ int pshared)
+{
+ switch (pshared)
+ {
+ case PTHREAD_PROCESS_PRIVATE:
+ attr->pshared = pshared;
+ return 0;
+
+ case PTHREAD_PROCESS_SHARED:
+ return ENOTSUP;
+
+ default:
+ return EINVAL;
+ }
+}
diff --git a/libpthread/sysdeps/generic/pt-setconcurrency.c b/libpthread/sysdeps/generic/pt-setconcurrency.c
new file mode 100644
index 00000000..cd55b1ba
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-setconcurrency.c
@@ -0,0 +1,34 @@
+/* Set the desired level of concurrency. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int __pthread_concurrency;
+
+int
+pthread_setconcurrency (int new_level)
+{
+ if (new_level < 0)
+ return EINVAL;
+
+ __pthread_concurrency = new_level;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/generic/pt-setschedparam.c b/libpthread/sysdeps/generic/pt-setschedparam.c
new file mode 100644
index 00000000..a70b0796
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-setschedparam.c
@@ -0,0 +1,28 @@
+/* Set the scheduling parameters for a thread. Generic version.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_setschedparam (pthread_t thread, int policy,
+ const struct sched_param *param)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-setschedprio.c b/libpthread/sysdeps/generic/pt-setschedprio.c
new file mode 100644
index 00000000..60668eb1
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-setschedprio.c
@@ -0,0 +1,27 @@
+/* Set the scheduling priority of a thread. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_setschedprio (pthread_t thread, int prio)
+{
+ return ENOSYS;
+}
diff --git a/libpthread/sysdeps/generic/pt-setspecific.c b/libpthread/sysdeps/generic/pt-setspecific.c
new file mode 100644
index 00000000..d520c5df
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-setspecific.c
@@ -0,0 +1,27 @@
+/* pthread_setspecific. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+int
+pthread_setspecific (pthread_key_t key, const void *value)
+{
+ return EINVAL;
+}
diff --git a/libpthread/sysdeps/generic/pt-startup.c b/libpthread/sysdeps/generic/pt-startup.c
new file mode 100644
index 00000000..c21a1819
--- /dev/null
+++ b/libpthread/sysdeps/generic/pt-startup.c
@@ -0,0 +1,25 @@
+/* Thread initialization. Generic version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pt-internal.h>
+
+void
+__pthread_startup (void)
+{
+}
diff --git a/libpthread/sysdeps/generic/raise.c b/libpthread/sysdeps/generic/raise.c
new file mode 100644
index 00000000..410f557d
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sem-close.c b/libpthread/sysdeps/generic/sem-close.c
new file mode 100644
index 00000000..9f48032f
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-close.c
@@ -0,0 +1,32 @@
+/* Close a named semaphore. Generic version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+int
+__sem_close (sem_t *sem)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+strong_alias (__sem_close, sem_close);
diff --git a/libpthread/sysdeps/generic/sem-destroy.c b/libpthread/sysdeps/generic/sem-destroy.c
new file mode 100644
index 00000000..6486599c
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-destroy.c
@@ -0,0 +1,38 @@
+/* Destroy a semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+int
+__sem_destroy (sem_t *sem)
+{
+ if (sem->__queue)
+ /* There are threads waiting on *SEM. */
+ {
+ errno = EBUSY;
+ return -1;
+ }
+
+ return 0;
+}
+
+strong_alias (__sem_destroy, sem_destroy);
diff --git a/libpthread/sysdeps/generic/sem-getvalue.c b/libpthread/sysdeps/generic/sem-getvalue.c
new file mode 100644
index 00000000..7762089b
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-getvalue.c
@@ -0,0 +1,33 @@
+/* Get the value of a semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <pt-internal.h>
+
+int
+__sem_getvalue (sem_t *restrict sem, int *restrict value)
+{
+ __pthread_spin_lock (&sem->__lock);
+ *value = sem->__value;
+ __pthread_spin_unlock (&sem->__lock);
+
+ return 0;
+}
+
+strong_alias (__sem_getvalue, sem_getvalue);
diff --git a/libpthread/sysdeps/generic/sem-init.c b/libpthread/sysdeps/generic/sem-init.c
new file mode 100644
index 00000000..d2414f5d
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-init.c
@@ -0,0 +1,46 @@
+/* Initialize a semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+int
+__sem_init (sem_t *sem, int pshared, unsigned value)
+{
+ if (pshared != 0)
+ {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+#ifdef SEM_VALUE_MAX
+ if (value > SEM_VALUE_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+#endif
+
+ *sem = (sem_t) __SEMAPHORE_INITIALIZER (pshared, value);
+ return 0;
+}
+
+strong_alias (__sem_init, sem_init);
diff --git a/libpthread/sysdeps/generic/sem-open.c b/libpthread/sysdeps/generic/sem-open.c
new file mode 100644
index 00000000..bae87ed0
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-open.c
@@ -0,0 +1,32 @@
+/* Open a named semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+sem_t *
+__sem_open (const char *name, int open_flags, ...)
+{
+ errno = EOPNOTSUPP;
+ return SEM_FAILED;
+}
+
+strong_alias (__sem_open, sem_open);
diff --git a/libpthread/sysdeps/generic/sem-post.c b/libpthread/sysdeps/generic/sem-post.c
new file mode 100644
index 00000000..6d438bf2
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-post.c
@@ -0,0 +1,62 @@
+/* Post a semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+__sem_post (sem_t *sem)
+{
+ struct __pthread *wakeup;
+
+ __pthread_spin_lock (&sem->__lock);
+ if (sem->__value > 0)
+ /* Do a quick up. */
+ {
+ assert (! sem->__queue);
+ sem->__value ++;
+ __pthread_spin_unlock (&sem->__lock);
+ return 0;
+ }
+
+ if (! sem->__queue)
+ /* No one waiting. */
+ {
+ sem->__value = 1;
+ __pthread_spin_unlock (&sem->__lock);
+ return 0;
+ }
+
+ /* Wake someone up. */
+
+ /* First dequeue someone. */
+ wakeup = sem->__queue;
+ __pthread_dequeue (wakeup);
+
+ /* Then drop the lock and transfer control. */
+ __pthread_spin_unlock (&sem->__lock);
+
+ __pthread_wakeup (wakeup);
+
+ return 0;
+}
+
+strong_alias (__sem_post, sem_post);
diff --git a/libpthread/sysdeps/generic/sem-timedwait.c b/libpthread/sysdeps/generic/sem-timedwait.c
new file mode 100644
index 00000000..e34539a9
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-timedwait.c
@@ -0,0 +1,91 @@
+/* Wait on a semaphore with a timeout. Generic version.
+ Copyright (C) 2005, 2006, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+int
+__sem_timedwait_internal (sem_t *restrict sem,
+ const struct timespec *restrict timeout)
+{
+ struct __pthread *self;
+
+ __pthread_spin_lock (&sem->__lock);
+ if (sem->__value > 0)
+ /* Successful down. */
+ {
+ sem->__value --;
+ __pthread_spin_unlock (&sem->__lock);
+ return 0;
+ }
+
+ if (timeout && (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Add ourselves to the queue. */
+ self = _pthread_self ();
+
+ __pthread_enqueue (&sem->__queue, self);
+ __pthread_spin_unlock (&sem->__lock);
+
+ /* Block the thread. */
+ if (timeout)
+ {
+ error_t err;
+
+ err = __pthread_timedblock (self, timeout);
+ if (err)
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ {
+ assert (err == ETIMEDOUT);
+
+ __pthread_spin_lock (&sem->__lock);
+ if (self->prevp)
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&sem->__lock);
+
+ errno = err;
+ return -1;
+ }
+ }
+ else
+ __pthread_block (self);
+
+ return 0;
+}
+
+int
+__sem_timedwait (sem_t *restrict sem,
+ const struct timespec *restrict timeout)
+{
+ return __sem_timedwait_internal (sem, timeout);
+}
+
+strong_alias (__sem_timedwait, sem_timedwait);
diff --git a/libpthread/sysdeps/generic/sem-trywait.c b/libpthread/sysdeps/generic/sem-trywait.c
new file mode 100644
index 00000000..437e2822
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-trywait.c
@@ -0,0 +1,42 @@
+/* Lock a semaphore if it does not require blocking. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+int
+__sem_trywait (sem_t *sem)
+{
+ __pthread_spin_lock (&sem->__lock);
+ if (sem->__value > 0)
+ /* Successful down. */
+ {
+ sem->__value --;
+ __pthread_spin_unlock (&sem->__lock);
+ return 0;
+ }
+ __pthread_spin_unlock (&sem->__lock);
+
+ errno = EAGAIN;
+ return -1;
+}
+
+strong_alias (__sem_trywait, sem_trywait);
diff --git a/libpthread/sysdeps/generic/sem-unlink.c b/libpthread/sysdeps/generic/sem-unlink.c
new file mode 100644
index 00000000..570ed614
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-unlink.c
@@ -0,0 +1,32 @@
+/* Unlink a named semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+int
+__sem_unlink (const char *name)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+strong_alias (__sem_unlink, sem_unlink);
diff --git a/libpthread/sysdeps/generic/sem-wait.c b/libpthread/sysdeps/generic/sem-wait.c
new file mode 100644
index 00000000..8347480c
--- /dev/null
+++ b/libpthread/sysdeps/generic/sem-wait.c
@@ -0,0 +1,32 @@
+/* Wait on a semaphore. Generic version.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <semaphore.h>
+#include <pt-internal.h>
+
+extern int __sem_timedwait_internal (sem_t *restrict sem,
+ const struct timespec *restrict timeout);
+
+int
+__sem_wait (sem_t *sem)
+{
+ return __sem_timedwait_internal (sem, 0);
+}
+
+strong_alias (__sem_wait, sem_wait);
diff --git a/libpthread/sysdeps/generic/sigaddset.c b/libpthread/sysdeps/generic/sigaddset.c
new file mode 100644
index 00000000..14edb71c
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sigdelset.c b/libpthread/sysdeps/generic/sigdelset.c
new file mode 100644
index 00000000..5456467f
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sigemptyset.c b/libpthread/sysdeps/generic/sigemptyset.c
new file mode 100644
index 00000000..690c15b6
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sigfillset.c b/libpthread/sysdeps/generic/sigfillset.c
new file mode 100644
index 00000000..f0ac0781
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/siginterrupt.c b/libpthread/sysdeps/generic/siginterrupt.c
new file mode 100644
index 00000000..0899efbb
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sigismember.c b/libpthread/sysdeps/generic/sigismember.c
new file mode 100644
index 00000000..b3d65c97
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/signal.c b/libpthread/sysdeps/generic/signal.c
new file mode 100644
index 00000000..7555d0a1
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/generic/sigwait.c b/libpthread/sysdeps/generic/sigwait.c
new file mode 100644
index 00000000..7d10bf8b
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/hurd/pt-destroy-specific.c b/libpthread/sysdeps/hurd/pt-destroy-specific.c
new file mode 100644
index 00000000..f7896e5e
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-destroy-specific.c
@@ -0,0 +1,79 @@
+/* __pthread_destory_specific. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <hurd/ihash.h>
+
+#include <pt-internal.h>
+
+void
+__pthread_destroy_specific (struct __pthread *thread)
+{
+ error_t err;
+ int i;
+ int seen_one;
+
+ /* Check if there is any thread specific data. */
+ if (! thread->thread_specifics)
+ return;
+
+ __pthread_key_lock_ready ();
+
+ /* Iterate and call the destructors on any thread specific data. */
+ for (;;)
+ {
+ seen_one = 0;
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ for (i = 0; i < __pthread_key_count; i ++)
+ {
+ void *value;
+
+ if (__pthread_key_destructors[i] == PTHREAD_KEY_INVALID)
+ continue;
+
+ value = hurd_ihash_find (thread->thread_specifics, i);
+ if (value)
+ {
+ err = hurd_ihash_remove (thread->thread_specifics, i);
+ assert (err == 1);
+
+ if (__pthread_key_destructors[i])
+ {
+ seen_one = 1;
+ __pthread_key_destructors[i] (value);
+ }
+ }
+ }
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+
+ if (! seen_one)
+ break;
+
+ /* This may take a very long time. Let those blocking on
+ pthread_key_create or pthread_key_delete make progress. */
+ sched_yield ();
+ }
+
+ hurd_ihash_free (thread->thread_specifics);
+ thread->thread_specifics = 0;
+}
diff --git a/libpthread/sysdeps/hurd/pt-getspecific.c b/libpthread/sysdeps/hurd/pt-getspecific.c
new file mode 100644
index 00000000..71ec63c6
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-getspecific.c
@@ -0,0 +1,39 @@
+/* pthread_getspecific. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <hurd/ihash.h>
+
+#include <pt-internal.h>
+
+void *
+pthread_getspecific (pthread_key_t key)
+{
+ struct __pthread *self;
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ return NULL;
+
+ self = _pthread_self ();
+ if (! self->thread_specifics)
+ return 0;
+
+ return hurd_ihash_find (self->thread_specifics, key);
+}
diff --git a/libpthread/sysdeps/hurd/pt-init-specific.c b/libpthread/sysdeps/hurd/pt-init-specific.c
new file mode 100644
index 00000000..c1bacbcb
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-init-specific.c
@@ -0,0 +1,30 @@
+/* __pthread_init_specific. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <pt-internal.h>
+
+error_t
+__pthread_init_specific (struct __pthread *thread)
+{
+ thread->thread_specifics = 0;
+ return 0;
+}
diff --git a/libpthread/sysdeps/hurd/pt-key-create.c b/libpthread/sysdeps/hurd/pt-key-create.c
new file mode 100644
index 00000000..b3e01412
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-key-create.c
@@ -0,0 +1,109 @@
+/* pthread_key_create. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <pt-internal.h>
+
+pthread_mutex_t __pthread_key_lock;
+
+void (**__pthread_key_destructors) (void *arg);
+int __pthread_key_size;
+int __pthread_key_count;
+int __pthread_key_invalid_count;
+
+int
+pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
+{
+ /* Where to look for the next key slot. */
+ static int index;
+
+ __pthread_key_lock_ready ();
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ do_search:
+ /* Use the search hint and try to find a free slot. */
+ for (; index < __pthread_key_count
+ && __pthread_key_destructors[index] != PTHREAD_KEY_INVALID;
+ index ++)
+ ;
+
+ /* See if we actually found a free element. */
+ if (index < __pthread_key_count)
+ {
+ assert (__pthread_key_destructors[index] == PTHREAD_KEY_INVALID);
+ assert (__pthread_key_invalid_count > 0);
+
+ __pthread_key_invalid_count --;
+ __pthread_key_destructors[index] = destructor;
+ *key = index ++;
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return 0;
+ }
+
+ assert (index == __pthread_key_count);
+
+ /* No space at the end. */
+ if (__pthread_key_size == __pthread_key_count)
+ {
+ /* See if it is worth looking for a free element. */
+ if (__pthread_key_invalid_count > 4
+ && __pthread_key_invalid_count > __pthread_key_size / 8)
+ {
+ index = 0;
+ goto do_search;
+ }
+
+
+ /* Resize the array. */
+ {
+ void *t;
+ int newsize;
+
+ if (__pthread_key_size == 0)
+ newsize = 8;
+ else
+ newsize = __pthread_key_size * 2;
+
+ t = realloc (__pthread_key_destructors,
+ newsize * sizeof (*__pthread_key_destructors));
+ if (! t)
+ {
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return ENOMEM;
+ }
+
+ __pthread_key_size = newsize;
+ __pthread_key_destructors = t;
+ }
+ }
+
+ __pthread_key_destructors[index] = destructor;
+ *key = index;
+
+ index ++;
+ __pthread_key_count ++;
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return 0;
+}
diff --git a/libpthread/sysdeps/hurd/pt-key-delete.c b/libpthread/sysdeps/hurd/pt-key-delete.c
new file mode 100644
index 00000000..9d88647e
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-key-delete.c
@@ -0,0 +1,64 @@
+/* pthread_key_delete. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+int
+pthread_key_delete (pthread_key_t key)
+{
+ error_t err = 0;
+
+ __pthread_key_lock_ready ();
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ err = EINVAL;
+ else
+ {
+ int i;
+
+ __pthread_key_destructors[key] = PTHREAD_KEY_INVALID;
+ __pthread_key_invalid_count ++;
+
+ pthread_rwlock_rdlock (&__pthread_threads_lock);
+ for (i = 0; i < __pthread_num_threads; ++i)
+ {
+ struct __pthread *t;
+
+ t = __pthread_threads[i];
+
+ if (t == NULL)
+ continue;
+
+ /* Just remove the key, no need to care whether it was
+ already there. */
+ if (t->thread_specifics)
+ hurd_ihash_remove (t->thread_specifics, key);
+ }
+ pthread_rwlock_unlock (&__pthread_threads_lock);
+ }
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+
+ return err;
+}
diff --git a/libpthread/sysdeps/hurd/pt-key.h b/libpthread/sysdeps/hurd/pt-key.h
new file mode 100644
index 00000000..494e01d7
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-key.h
@@ -0,0 +1,76 @@
+/* pthread_key internal declatations for the Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <hurd/ihash.h>
+
+#define PTHREAD_KEY_MEMBERS \
+ hurd_ihash_t thread_specifics;
+
+#define PTHREAD_KEY_INVALID (void *) (-1)
+
+
+/* __PTHREAD_KEY_DESTRUCTORS is an array of destructors with
+ __PTHREAD_KEY_SIZE elements. If an element with index less than
+ __PTHREAD_KEY_COUNT is invalid, it shall contain the value
+ PTHREAD_KEY_INVALID which shall be distinct from NULL.
+
+ Normally, we just add new keys to the end of the array and realloc
+ it as necessary. The pthread_key_create routine may decide to
+ rescan the array if __PTHREAD_KEY_FREE is large. */
+extern void (**__pthread_key_destructors) (void *arg);
+extern int __pthread_key_size;
+extern int __pthread_key_count;
+/* Number of invalid elements in the array. Does not include elements
+ for which memory has been allocated but which have not yet been
+ used (i.e. those elements with indexes greater than
+ __PTHREAD_KEY_COUNT). */
+extern int __pthread_key_invalid_count;
+
+/* Protects the above variables. This must be a recursive lock: the
+ destructors may call pthread_key_delete. */
+extern pthread_mutex_t __pthread_key_lock;
+
+#include <assert.h>
+
+static inline void
+__pthread_key_lock_ready (void)
+{
+ static pthread_once_t o = PTHREAD_ONCE_INIT;
+
+ void do_init (void)
+ {
+ int err;
+ pthread_mutexattr_t attr;
+
+ err = pthread_mutexattr_init (&attr);
+ assert_perror (err);
+
+ err = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert_perror (err);
+
+ err = pthread_mutex_init (&__pthread_key_lock, &attr);
+ assert_perror (err);
+
+ err = pthread_mutexattr_destroy (&attr);
+ assert_perror (err);
+ }
+
+ pthread_once (&o, do_init);
+}
diff --git a/libpthread/sysdeps/hurd/pt-kill.c b/libpthread/sysdeps/hurd/pt-kill.c
new file mode 100644
index 00000000..d204e3f6
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-kill.c
@@ -0,0 +1,52 @@
+/* pthread_kill. Hurd version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <hurd/signal.h>
+
+#include <pt-internal.h>
+
+int
+pthread_kill (pthread_t thread, int sig)
+{
+ struct __pthread *pthread;
+ struct hurd_signal_detail detail;
+ struct hurd_sigstate *ss;
+
+ /* Lookup the thread structure for THREAD. */
+ pthread = __pthread_getid (thread);
+ if (pthread == NULL)
+ return ESRCH;
+
+ ss = _hurd_thread_sigstate (pthread->kernel_thread);
+ assert (ss);
+
+ if (!sig)
+ return 0;
+
+ detail.exc = 0;
+ detail.code = sig;
+ detail.error = 0;
+
+ _hurd_raise_signal (ss, sig, &detail);
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/hurd/pt-setspecific.c b/libpthread/sysdeps/hurd/pt-setspecific.c
new file mode 100644
index 00000000..d0b7302f
--- /dev/null
+++ b/libpthread/sysdeps/hurd/pt-setspecific.c
@@ -0,0 +1,47 @@
+/* pthread_setspecific. Generic version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <hurd/ihash.h>
+
+#include <pt-internal.h>
+
+int
+pthread_setspecific (pthread_key_t key, const void *value)
+{
+ error_t err;
+ struct __pthread *self = _pthread_self ();
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ return EINVAL;
+
+ if (! self->thread_specifics)
+ {
+ err = hurd_ihash_create (&self->thread_specifics, HURD_IHASH_NO_LOCP);
+ if (err)
+ return ENOMEM;
+ }
+
+ err = hurd_ihash_add (self->thread_specifics, key, (void *) value);
+ if (err)
+ return ENOMEM;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/ia32/bits/atomic.h b/libpthread/sysdeps/ia32/bits/atomic.h
new file mode 100644
index 00000000..0dfc1f60
--- /dev/null
+++ b/libpthread/sysdeps/ia32/bits/atomic.h
@@ -0,0 +1,66 @@
+/* Atomic operations. i386 version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+typedef __volatile int __atomic_t;
+
+static inline void
+__atomic_inc (__atomic_t *__var)
+{
+ __asm__ __volatile ("lock; incl %0" : "=m" (*__var) : "m" (*__var));
+}
+
+static inline void
+__atomic_dec (__atomic_t *__var)
+{
+ __asm__ __volatile ("lock; decl %0" : "=m" (*__var) : "m" (*__var));
+}
+
+static inline int
+__atomic_dec_and_test (__atomic_t *__var)
+{
+ unsigned char __ret;
+
+ __asm__ __volatile ("lock; decl %0; sete %1"
+ : "=m" (*__var), "=qm" (__ret) : "m" (*__var));
+ return __ret != 0;
+}
+
+/* We assume that an __atomicptr_t is only used for pointers to
+ word-aligned objects, and use the lowest bit for a simple lock. */
+typedef __volatile int * __atomicptr_t;
+
+/* Actually we don't implement that yet, and assume that we run on
+ something that has the i486 instruction set. */
+static inline int
+__atomicptr_compare_and_swap (__atomicptr_t *__ptr, void *__oldval,
+ void * __newval)
+{
+ char __ret;
+ int __dummy;
+
+ __asm__ __volatile ("lock; cmpxchgl %3, %1; sete %0"
+ : "=q" (__ret), "=m" (*__ptr), "=a" (__dummy)
+ : "r" (__newval), "m" (*__ptr), "a" (__oldval));
+ return __ret;
+}
+
+#endif
diff --git a/libpthread/sysdeps/ia32/bits/memory.h b/libpthread/sysdeps/ia32/bits/memory.h
new file mode 100644
index 00000000..932c4086
--- /dev/null
+++ b/libpthread/sysdeps/ia32/bits/memory.h
@@ -0,0 +1,40 @@
+/* Memory barrier operations. i386 version.
+ Copyright (C) 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_MEMORY_H
+#define _BITS_MEMORY_H 1
+
+/* Prevent read and write reordering across this function. */
+static inline void
+__memory_barrier (void)
+{
+ int i;
+
+ /* Any lock'ed instruction will do. We just do a simple
+ increment. */
+ __asm__ __volatile ("lock; incl %0" : "=m" (i) : "m" (i) : "memory");
+}
+
+/* Prevent read reordering across this function. */
+#define __memory_read_barrier __memory_barrier
+
+/* Prevent write reordering across this function. */
+#define __memory_write_barrier __memory_barrier
+
+#endif
diff --git a/libpthread/sysdeps/ia32/bits/spin-lock-inline.h b/libpthread/sysdeps/ia32/bits/spin-lock-inline.h
new file mode 100644
index 00000000..e5ed3def
--- /dev/null
+++ b/libpthread/sysdeps/ia32/bits/spin-lock-inline.h
@@ -0,0 +1,98 @@
+/* Machine-specific definitions for spin locks. i386 version.
+ Copyright (C) 2000, 2005, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_SPIN_LOCK_INLINE_H
+#define _BITS_SPIN_LOCK_INLINE_H 1
+
+#include <features.h>
+#include <bits/spin-lock.h>
+
+__BEGIN_DECLS
+
+#if defined __USE_EXTERN_INLINES || defined _FORCE_INLINES
+
+# ifndef __EBUSY
+# include <errno.h>
+# define __EBUSY EBUSY
+# endif
+
+# ifndef __PT_SPIN_INLINE
+# define __PT_SPIN_INLINE __extern_inline
+# endif
+
+__PT_SPIN_INLINE int __pthread_spin_destroy (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_destroy (__pthread_spinlock_t *__lock)
+{
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock,
+ int __pshared);
+
+__PT_SPIN_INLINE int
+__pthread_spin_init (__pthread_spinlock_t *__lock, int __pshared)
+{
+ *__lock = __PTHREAD_SPIN_LOCK_INITIALIZER;
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_trylock (__pthread_spinlock_t *__lock)
+{
+ int __locked;
+ __asm__ __volatile ("xchgl %0, %1"
+ : "=&r" (__locked), "=m" (*__lock) : "0" (1) : "memory");
+ return __locked ? __EBUSY : 0;
+}
+
+__extern_inline int __pthread_spin_lock (__pthread_spinlock_t *__lock);
+extern int _pthread_spin_lock (__pthread_spinlock_t *__lock);
+
+__extern_inline int
+__pthread_spin_lock (__pthread_spinlock_t *__lock)
+{
+ if (__pthread_spin_trylock (__lock))
+ return _pthread_spin_lock (__lock);
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_unlock (__pthread_spinlock_t *__lock)
+{
+ int __unlocked;
+ __asm__ __volatile ("xchgl %0, %1"
+ : "=&r" (__unlocked), "=m" (*__lock) : "0" (0) : "memory");
+ return 0;
+}
+
+#endif /* Use extern inlines or force inlines. */
+
+__END_DECLS
+
+#endif /* bits/spin-lock.h */
diff --git a/libpthread/sysdeps/ia32/bits/spin-lock.h b/libpthread/sysdeps/ia32/bits/spin-lock.h
new file mode 100644
index 00000000..5ae81e18
--- /dev/null
+++ b/libpthread/sysdeps/ia32/bits/spin-lock.h
@@ -0,0 +1,39 @@
+/* Machine-specific definitions for spin locks. i386 version.
+ Copyright (C) 2000, 2005, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_SPIN_LOCK_H
+#define _BITS_SPIN_LOCK_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* The type of a spin lock object. */
+typedef __volatile int __pthread_spinlock_t;
+
+/* Initializer for a spin lock object. */
+# define __PTHREAD_SPIN_LOCK_INITIALIZER ((__pthread_spinlock_t) 0)
+
+__END_DECLS
+
+#endif /* bits/spin-lock.h */
diff --git a/libpthread/sysdeps/ia32/machine-sp.h b/libpthread/sysdeps/ia32/machine-sp.h
new file mode 100644
index 00000000..cef6ab72
--- /dev/null
+++ b/libpthread/sysdeps/ia32/machine-sp.h
@@ -0,0 +1,30 @@
+/* Machine-specific function to return the stack pointer. i386 version.
+ Copyright (C) 1994, 1997, 2001, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _MACHINE_SP_H
+#define _MACHINE_SP_H
+
+/* Return the current stack pointer. */
+
+#define __thread_stack_pointer() ({ \
+ register void *__sp__ asm("esp"); \
+ __sp__; \
+})
+
+#endif /* machine-sp.h */
diff --git a/libpthread/sysdeps/ia32/pt-machdep.h b/libpthread/sysdeps/ia32/pt-machdep.h
new file mode 100644
index 00000000..6d456367
--- /dev/null
+++ b/libpthread/sysdeps/ia32/pt-machdep.h
@@ -0,0 +1,29 @@
+/* Machine dependent pthreads internal defenitions. i386 version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PT_MACHDEP_H
+#define _PT_MACHDEP_H 1
+
+struct pthread_mcontext
+{
+ void *pc;
+ void *sp;
+};
+
+#endif /* pt-machdep.h */
diff --git a/libpthread/sysdeps/l4/bits/pthread-np.h b/libpthread/sysdeps/l4/bits/pthread-np.h
new file mode 100644
index 00000000..6a02bdc0
--- /dev/null
+++ b/libpthread/sysdeps/l4/bits/pthread-np.h
@@ -0,0 +1,35 @@
+/* Non-portable functions. L4 version.
+ Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_PTHREAD_NP_H
+#define _BITS_PTHREAD_NP_H 1
+
+#include <l4.h>
+
+/* Add the thread TID to the internal kernel thread pool. */
+extern int pthread_pool_add_np (l4_thread_id_t tid);
+
+/* Get the first thread from the pool. */
+extern l4_thread_id_t pthread_pool_get_np (void);
+
+#endif /* bits/pthread-np.h */
diff --git a/libpthread/sysdeps/l4/hurd/bits/pthread-np.h b/libpthread/sysdeps/l4/hurd/bits/pthread-np.h
new file mode 100644
index 00000000..a90793df
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/bits/pthread-np.h
@@ -0,0 +1,31 @@
+/* Non-portable functions. Viengoos version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_PTHREAD_NP_H
+#define _BITS_PTHREAD_NP_H 1
+
+#include <hurd/addr.h>
+
+int pthread_setactivity_np (addr_t activity);
+
+#endif /* bits/pthread-np.h */
diff --git a/libpthread/sysdeps/l4/hurd/ia32/pt-machdep.c b/libpthread/sysdeps/l4/hurd/ia32/pt-machdep.c
new file mode 100644
index 00000000..dbf5cd7e
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/ia32/pt-machdep.c
@@ -0,0 +1,20 @@
+/* Machine dependent pthreads code. Hurd/i386 version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Nothing to do. */
diff --git a/libpthread/sysdeps/l4/hurd/ia32/pt-setup.c b/libpthread/sysdeps/l4/hurd/ia32/pt-setup.c
new file mode 100644
index 00000000..579905c9
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/ia32/pt-setup.c
@@ -0,0 +1,117 @@
+/* Setup thread stack. Viengoos/i386 version.
+ Copyright (C) 2000, 2002, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+
+#include <pt-internal.h>
+#include <hurd/thread.h>
+#include <hurd/exceptions.h>
+
+/* The stack layout used on the i386 is:
+
+ -----------------
+ | ARG |
+ -----------------
+ | START_ROUTINE |
+ -----------------
+ | Return address |
+ ----------------- <- %ebp
+ | Frame pointer |
+ -----------------
+
+ We do the following: setup the stack to return to the entry routine.
+
+
+*/
+
+/* The stack contains:
+
+ arg
+ start_routine
+ 0 <- fake return address
+ C entry_point
+*/
+extern uintptr_t _pthread_entry_point;
+__asm__ ("\n\
+ .globl _pthread_entry_point, __pthread_entry_point\n\
+_pthread_entry_point:\n\
+__pthread_entry_point:\n\
+ pushl $0\n\
+ popf\n\
+\n\
+ xor %ebp, %ebp\n\
+ ret\n");
+
+/* Set up the stack for THREAD, such that it appears as if
+ START_ROUTINE and ARG were passed to the new thread's entry-point.
+ Return the stack pointer for the new thread. We also take the
+ opportunity to install THREAD in our utcb. */
+static void *
+stack_setup (struct __pthread *thread,
+ void *(*start_routine)(void *), void *arg,
+ void (*entry_point)(void *(*)(void *), void *))
+{
+ uintptr_t *top;
+
+ /* Calculate top of the new stack. */
+ top = (uintptr_t *) ((uintptr_t) thread->stackaddr + thread->stacksize);
+
+ /* Align on 0x10 for MMX operations. */
+ top = (uintptr_t) top & ~0xf;
+
+ if (start_routine)
+ {
+ /* Set up call frame. */
+ *--top = (uintptr_t) arg; /* Argument to START_ROUTINE. */
+ *--top = (uintptr_t) start_routine;
+ *--top = 0; /* Fake return address. */
+ *--top = (uintptr_t) entry_point;
+ }
+
+ return top;
+}
+
+int
+__pthread_setup (struct __pthread *thread,
+ void (*entry_point)(void *(*)(void *), void *),
+ void *(*start_routine)(void *), void *arg)
+{
+ thread->mcontext.pc = (void *) &_pthread_entry_point;
+ thread->mcontext.sp = (void *) stack_setup (thread, start_routine, arg,
+ entry_point);
+
+ if (__pthread_num_threads == 1)
+ return 0;
+
+ assert (! ADDR_IS_VOID (thread->exception_area[0]));
+
+ struct exception_page *exception_page = thread->exception_area_va;
+
+ /* SP is set to the end of the exception area minus one word, which
+ is the location of the exception page. */
+ exception_page->exception_handler_sp
+ = (uintptr_t) thread->exception_area_va + EXCEPTION_AREA_SIZE;
+ exception_page->exception_handler_sp -= sizeof (void *);
+ * (void **) exception_page->exception_handler_sp = thread->exception_area_va;
+
+ exception_page->exception_handler_ip = (uintptr_t) &exception_handler_entry;
+ exception_page->exception_handler_end = (uintptr_t) &exception_handler_end;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c b/libpthread/sysdeps/l4/hurd/ia32/signal-dispatch-lowlevel.c
new file mode 100644
index 00000000..37ef8215
--- /dev/null
+++ b/libpthread/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,
+ 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));
+
+ 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,
+ HURD_EXREGS_SET_SP_IP
+ | HURD_EXREGS_START | HURD_EXREGS_ABORT_IPC,
+ in, &out);
+ }
+}
diff --git a/libpthread/sysdeps/l4/hurd/powerpc/pt-machdep.c b/libpthread/sysdeps/l4/hurd/powerpc/pt-machdep.c
new file mode 100644
index 00000000..754d203e
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/powerpc/pt-machdep.c
@@ -0,0 +1,20 @@
+/* Machine dependent pthreads code. Hurd/PowerPC version.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Nothing to do. */
diff --git a/libpthread/sysdeps/l4/hurd/powerpc/pt-setup.c b/libpthread/sysdeps/l4/hurd/powerpc/pt-setup.c
new file mode 100644
index 00000000..d3cf4ec3
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/powerpc/pt-setup.c
@@ -0,0 +1,93 @@
+/* Setup thread stack. Hurd/PowerPC version.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+
+#include <pt-internal.h>
+
+/* Arguments is passed in registers on the PowerPC. But the
+ exchange registers syscall only allows us to set the PC and the
+ stack pointer so we put the entry point and start function on
+ the stack. */
+struct start_info
+{
+ void (*entry_point) (void *(*)(void *), void *);
+ void *(*start_routine) (void *);
+ void *arg;
+};
+
+void first_entry_1 (void);
+
+/* Stage 1 entry function. The start_info structure is inlined on the
+ stack. Put values into registers and call entry function. */
+asm (" ;\
+first_entry_1: ;\
+ lwz 0, 0(1) ;\
+ lwz 3, 4(1) ;\
+ lwz 4, 8(1) ;\
+ mtctr 0 ;\
+ bctrl ;\
+");
+
+/* Set up the stack for THREAD, such that it appears as if
+ START_ROUTINE and ARG were passed to the new thread's entry-point.
+ Return the stack pointer for the new thread. We also take the
+ opportunity to install THREAD in our utcb. */
+static void *
+stack_setup (struct __pthread *thread,
+ void (*entry_point)(void *(*)(void *), void *),
+ void *(*start_routine)(void *), void *arg)
+{
+ l4_word_t *top;
+
+ /* Calculate top of the new stack. */
+ top = (l4_word_t *) ((l4_word_t) thread->stackaddr + thread->stacksize);
+
+ /* Initial stack frame. */
+ top[-4] = 0;
+ top = top - 4;
+
+ if (start_routine)
+ {
+ struct start_info *info = ((struct start_info *) top) - 1;
+
+ info->entry_point = entry_point;
+ info->start_routine = start_routine;
+ info->arg = arg;
+ return (void *) info;
+ }
+ return top;
+}
+
+int
+__pthread_setup (struct __pthread *thread,
+ void (*entry_point)(void *(*)(void *), void *),
+ void *(*start_routine)(void *), void *arg)
+{
+ thread->mcontext.pc = first_entry_1;
+ thread->mcontext.sp = stack_setup (thread, entry_point,
+ start_routine, arg);
+
+ if (l4_same_threads (thread->threadid, l4_myself ()))
+ l4_set_user_defined_handle ((l4_word_t) thread);
+ else
+ l4_set_user_defined_handle_of (thread->threadid,
+ (l4_word_t) thread);
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-block.c b/libpthread/sysdeps/l4/hurd/pt-block.c
new file mode 100644
index 00000000..2315b1c4
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-block.c
@@ -0,0 +1,30 @@
+/* Block a thread. Viengoos version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pt-internal.h>
+
+#include <hurd/stddef.h>
+#include <hurd/futex.h>
+
+/* Block THREAD. */
+void
+__pthread_block (struct __pthread *thread)
+{
+ futex_wait (&thread->threadid, thread->threadid);
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-kill.c b/libpthread/sysdeps/l4/hurd/pt-kill.c
new file mode 100644
index 00000000..c72e82f4
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-kill.c
@@ -0,0 +1,3 @@
+/* The generic version is good enough for us, however, the generic
+ Hurd on Mach version supplies a specialized version */
+#include "../generic/pt-kill.c"
diff --git a/libpthread/sysdeps/l4/hurd/pt-setactivity-np.c b/libpthread/sysdeps/l4/hurd/pt-setactivity-np.c
new file mode 100644
index 00000000..f2f07233
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-setactivity-np.c
@@ -0,0 +1,39 @@
+/* Set a thread's activity activity. Viengoos version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pt-internal.h>
+
+#include <hurd/addr.h>
+#include <hurd/thread.h>
+
+int
+pthread_setactivity_np (addr_t activity)
+{
+ struct __pthread *self = _pthread_self ();
+
+ struct hurd_thread_exregs_in in;
+ in.activity = activity;
+
+ struct hurd_thread_exregs_out out;
+ int err = rm_thread_exregs (ADDR_VOID, self->object,
+ HURD_EXREGS_SET_ACTIVITY,
+ in, &out);
+
+ return err;
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-sigstate-destroy.c b/libpthread/sysdeps/l4/hurd/pt-sigstate-destroy.c
new file mode 100644
index 00000000..997a0369
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-sigstate-destroy.c
@@ -0,0 +1,28 @@
+/* Destroy the signal state. Hurd on L4 version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+void
+__pthread_sigstate_destroy (struct __pthread *thread)
+{
+ /* Nothing to do. */
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-sigstate-init.c b/libpthread/sysdeps/l4/hurd/pt-sigstate-init.c
new file mode 100644
index 00000000..4c40fdb3
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-sigstate-init.c
@@ -0,0 +1,44 @@
+/* Initialize the signal state. Hurd on L4 version.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#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/libpthread/sysdeps/l4/hurd/pt-sigstate.c b/libpthread/sysdeps/l4/hurd/pt-sigstate.c
new file mode 100644
index 00000000..66dd08cf
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-sigstate.c
@@ -0,0 +1,81 @@
+/* Set a thread's signal state. Hurd on L4 version.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+
+#include <pt-internal.h>
+
+error_t
+__pthread_sigstate (struct __pthread *thread, int how,
+ const sigset_t *set, sigset_t *oset,
+ int clear_pending)
+{
+ 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/libpthread/sysdeps/l4/hurd/pt-startup.c b/libpthread/sysdeps/l4/hurd/pt-startup.c
new file mode 100644
index 00000000..b6461de7
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-startup.c
@@ -0,0 +1,30 @@
+/* Thread initialization. Hurd/L4 version.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+#include <pt-internal.h>
+
+#include <hurd/exceptions.h>
+
+void
+__pthread_startup (void)
+{
+ struct __pthread *pthread = _pthread_self ();
+ pthread->threadid = l4_myself ();
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-sysdep.c b/libpthread/sysdeps/l4/hurd/pt-sysdep.c
new file mode 100644
index 00000000..c23364c7
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-sysdep.c
@@ -0,0 +1,61 @@
+/* System dependent pthreads code. Hurd version.
+ 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <pt-internal.h>
+
+int
+sched_yield (void)
+{
+ l4_yield ();
+ return 0;
+}
+
+/* Forward. */
+static void init_routine (void (*) (void *), void *)
+ __attribute__ ((noreturn));
+
+/* OK, the name of this variable isn't really appropriate, but I don't
+ want to change it yet. */
+void (*_pthread_init_routine)(void (*) (void *), void *) = &init_routine;
+
+/* This function is called from the Hurd-specific startup code. It
+ should return a new stack pointer for the main thread. The caller
+ will switch to this new stack before doing anything serious. */
+static void
+init_routine (void (*entry) (void *), void *arg)
+{
+ /* Initialize the library. */
+ __pthread_initialize ();
+
+ struct __pthread *thread;
+ int err;
+
+ /* Create the pthread structure for the main thread (i.e. us). */
+ err = __pthread_create_internal (&thread, 0,
+ (void *(*)(void *)) entry, arg);
+ assert_perror (err);
+
+ /* Switch stacks. */
+ l4_start_sp_ip (l4_myself (), thread->mcontext.sp,
+ thread->mcontext.pc);
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-sysdep.h b/libpthread/sysdeps/l4/hurd/pt-sysdep.h
new file mode 100644
index 00000000..08bcd143
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-sysdep.h
@@ -0,0 +1,61 @@
+/* Internal definitions for pthreads library.
+ Copyright (C) 2000, 2002, 2005, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PT_SYSDEP_H
+#define _PT_SYSDEP_H 1
+
+#include <l4.h>
+#include <hurd/storage.h>
+#include <sys/mman.h>
+
+/* XXX */
+#define _POSIX_THREAD_THREADS_MAX 64
+
+/* The default stack size: 2MB. */
+#define PTHREAD_STACK_DEFAULT (2 * 1024 * 1024)
+
+#include <hurd/exceptions.h>
+
+#define EXCEPTION_AREA_SIZE EXCEPTION_STACK_SIZE
+#define EXCEPTION_AREA_SIZE_LOG2 EXCEPTION_STACK_SIZE_LOG2
+/* The exception page is the first object. */
+#define EXCEPTION_PAGE 0
+
+#define PTHREAD_SYSDEP_MEMBERS \
+ addr_t object; \
+ l4_thread_id_t threadid; \
+ addr_t exception_area[EXCEPTION_AREA_SIZE / PAGESIZE]; \
+ void *exception_area_va; \
+ l4_word_t my_errno;
+
+extern inline struct __pthread *
+__attribute__((__always_inline__))
+_pthread_self (void)
+{
+ return (struct __pthread *) l4_user_defined_handle ();
+}
+
+extern inline void
+__attribute__((__always_inline__))
+__pthread_stack_dealloc (void *stackaddr, size_t stacksize)
+{
+ munmap (stackaddr, stacksize);
+}
+
+#endif /* pt-sysdep.h */
diff --git a/libpthread/sysdeps/l4/hurd/pt-thread-alloc.c b/libpthread/sysdeps/l4/hurd/pt-thread-alloc.c
new file mode 100644
index 00000000..ada7b3b8
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-thread-alloc.c
@@ -0,0 +1,95 @@
+/* Allocate kernel thread. Viengoos version.
+ Copyright (C) 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <hurd/startup.h>
+#include <hurd/storage.h>
+#include <hurd/as.h>
+#include <hurd/addr.h>
+
+#include <pt-internal.h>
+
+extern struct hurd_startup_data *__hurd_startup_data;
+
+extern addr_t meta_data_activity;
+
+int
+__pthread_thread_alloc (struct __pthread *thread)
+{
+ /* The main thread is already running of course. */
+ if (__pthread_num_threads == 1)
+ {
+ thread->object = __hurd_startup_data->thread;
+ thread->threadid = l4_myself ();
+ return 0;
+ }
+ else
+ {
+ addr_t exception_area = as_alloc (EXCEPTION_AREA_SIZE_LOG2, 1, true);
+
+ thread->exception_area_va
+ = ADDR_TO_PTR (addr_extend (exception_area,
+ 0, EXCEPTION_AREA_SIZE_LOG2));
+
+ int i;
+ for (i = 0; i < EXCEPTION_AREA_SIZE / PAGESIZE; i ++)
+ {
+ addr_t slot = addr_chop (PTR_TO_ADDR (thread->exception_area_va
+ + i * PAGESIZE),
+ PAGESIZE_LOG2);
+ as_ensure (slot);
+
+ struct storage storage = storage_alloc (ADDR_VOID, cap_page,
+ STORAGE_LONG_LIVED,
+ OBJECT_POLICY_DEFAULT,
+ slot);
+ if (ADDR_IS_VOID (storage.addr))
+ {
+ int j;
+ for (j = 0; j < i; j ++)
+ storage_free (thread->exception_area[j], false);
+ as_free (exception_area, false);
+ return EAGAIN;
+ }
+
+ thread->exception_area[i] = storage.addr;
+ }
+
+ struct storage storage;
+ storage = storage_alloc (meta_data_activity, cap_thread,
+ /* Threads are rarely shortly lived. */
+ STORAGE_MEDIUM_LIVED, OBJECT_POLICY_DEFAULT,
+ ADDR_VOID);
+ if (ADDR_IS_VOID (storage.addr))
+ {
+ int j;
+ for (j = 0; j < EXCEPTION_AREA_SIZE / PAGESIZE; j ++)
+ storage_free (thread->exception_area[j], false);
+ as_free (exception_area, false);
+ return EAGAIN;
+ }
+
+ thread->object = storage.addr;
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-thread-halt.c b/libpthread/sysdeps/l4/hurd/pt-thread-halt.c
new file mode 100644
index 00000000..98fefaab
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-thread-halt.c
@@ -0,0 +1,104 @@
+/* Deallocate the kernel thread resources. Viengoos version.
+ Copyright (C) 2007, 2008 Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+#include <hurd/exceptions.h>
+#include <hurd/mutex.h>
+#include <hurd/as.h>
+#include <hurd/addr.h>
+
+/* If we try to deallocate our self, we will end up causing a
+ deadlock. Thus, when a thread tries to free itself, we add it
+ here. The next thread to free a thread will free it. */
+ss_mutex_t saved_object_lock;
+static addr_t saved_object;
+
+void
+__pthread_thread_halt (struct __pthread *thread, int need_dealloc)
+{
+ /* We may deallocate THREAD. First save any data we need. */
+
+ addr_t exception_area[EXCEPTION_AREA_SIZE / PAGESIZE];
+ memcpy (exception_area, thread->exception_area,
+ sizeof (thread->exception_area));
+ memset (thread->exception_area, 0, sizeof (thread->exception_area));
+
+ void *va = thread->exception_area_va;
+
+ addr_t object = thread->object;
+ l4_thread_id_t tid = thread->threadid;
+
+ if (need_dealloc)
+ __pthread_dealloc (thread);
+
+ /* The THREAD data structure is no longer valid. */
+ thread = NULL;
+
+ /* Deallocate any saved object. */
+ ss_mutex_lock (&saved_object_lock);
+ if (! ADDR_IS_VOID (saved_object))
+ {
+ storage_free (saved_object, false);
+ saved_object = ADDR_VOID;
+ }
+ ss_mutex_unlock (&saved_object_lock);
+
+ /* Free the exception area. */
+
+ /* Clean up the exception page. */
+ exception_page_cleanup
+ (ADDR_TO_PTR (addr_extend (exception_area[EXCEPTION_PAGE],
+ 0, PAGESIZE_LOG2)));
+
+ /* Free the storage. */
+ int i;
+ for (i = 0; i < EXCEPTION_AREA_SIZE / PAGESIZE; i ++)
+ {
+ assert (! ADDR_IS_VOID (exception_area[i]));
+ storage_free (exception_area[i], false);
+ }
+
+ /* And the address space. */
+ as_free (addr_chop (PTR_TO_ADDR (va), EXCEPTION_AREA_SIZE_LOG2), false);
+
+ if (tid == l4_myself ())
+ /* If we try to storage_free (storage.addr), we will freeze in the
+ middle. That's no good. We set SAVED_OBJECT to our thread
+ object and the next thread in will free us. */
+ {
+ ss_mutex_lock (&saved_object_lock);
+ saved_object = object;
+ ss_mutex_unlock (&saved_object_lock);
+ }
+ else
+ storage_free (object, false);
+
+ if (tid == l4_myself ())
+ {
+ l4_send_timeout (l4_myself (), L4_NEVER);
+ panic ("Failed to stop thread %x.%x!",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()));
+ }
+ else
+ thread_stop (object);
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-thread-start.c b/libpthread/sysdeps/l4/hurd/pt-thread-start.c
new file mode 100644
index 00000000..9db399ce
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-thread-start.c
@@ -0,0 +1,70 @@
+/* Start thread. L4 version.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <hurd/thread.h>
+#include <hurd/exceptions.h>
+
+#include <pt-internal.h>
+
+int
+__pthread_thread_start (struct __pthread *thread)
+{
+ error_t err;
+
+ if (__pthread_num_threads == 1)
+ /* The main thread is already running of course. */
+ {
+ assert (__pthread_total == 1);
+ assert (l4_is_thread_equal (l4_myself (), thread->threadid));
+ l4_set_user_defined_handle ((l4_word_t) thread);
+ }
+ else
+ {
+ struct hurd_thread_exregs_in in;
+ struct hurd_thread_exregs_out out;
+
+ in.aspace = ADDR (0, 0);
+ in.aspace_cap_properties = CAP_PROPERTIES_VOID;
+ in.aspace_cap_properties_flags = CAP_COPY_COPY_SOURCE_GUARD;
+
+ in.activity = ADDR_VOID;
+
+ in.exception_page = addr_chop (PTR_TO_ADDR (thread->exception_area_va),
+ PAGESIZE_LOG2);
+
+ in.sp = (l4_word_t) thread->mcontext.sp;
+ in.ip = (l4_word_t) thread->mcontext.pc;
+
+ in.user_handle = (l4_word_t) thread;
+ err = rm_thread_exregs (ADDR_VOID, thread->object,
+ HURD_EXREGS_SET_ASPACE
+ | HURD_EXREGS_SET_ACTIVITY
+ | HURD_EXREGS_SET_EXCEPTION_PAGE
+ | HURD_EXREGS_SET_SP_IP
+ | HURD_EXREGS_SET_USER_HANDLE
+ | HURD_EXREGS_START
+ | HURD_EXREGS_ABORT_IPC,
+ in, &out);
+ assert (err == 0);
+ }
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/hurd/pt-wakeup.c b/libpthread/sysdeps/l4/hurd/pt-wakeup.c
new file mode 100644
index 00000000..e568a6f9
--- /dev/null
+++ b/libpthread/sysdeps/l4/hurd/pt-wakeup.c
@@ -0,0 +1,46 @@
+/* Wakeup a thread. Viengoos version.
+ Copyright (C) 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pt-internal.h>
+
+#include <hurd/stddef.h>
+#include <hurd/futex.h>
+#include <stdint.h>
+
+/* Wakeup THREAD. */
+void
+__pthread_wakeup (struct __pthread *thread)
+{
+ /* We need to loop here as the blocked thread may not yet be
+ blocked! Here's what happens when a thread blocks: it registers
+ itself as blocked, drops the relevant lock and then actually
+ blocks (via __pthread_block). This means that after dropping the
+ lock and before blocking, it may be interrupted and another
+ thread may try to wake it. */
+ long ret;
+ do
+ {
+ ret = futex_wake (&thread->threadid, INT_MAX);
+ assertx (ret <= 1, "tid: %x, ret: %d", thread->threadid, ret);
+
+ if (ret == 0)
+ l4_thread_switch (thread->threadid);
+ }
+ while (ret == 0);
+}
diff --git a/libpthread/sysdeps/l4/hurd/sig-sysdep.h b/libpthread/sysdeps/l4/hurd/sig-sysdep.h
new file mode 100644
index 00000000..33e13857
--- /dev/null
+++ b/libpthread/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/libpthread/sysdeps/l4/hurd/sigprocmask.c b/libpthread/sysdeps/l4/hurd/sigprocmask.c
new file mode 100644
index 00000000..a38b3795
--- /dev/null
+++ b/libpthread/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);
+}
diff --git a/libpthread/sysdeps/l4/pt-block.c b/libpthread/sysdeps/l4/pt-block.c
new file mode 100644
index 00000000..69e1d358
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-block.c
@@ -0,0 +1,47 @@
+/* Block a thread. L4 version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+
+#include <pt-internal.h>
+
+#include <hurd/stddef.h>
+
+/* Block THREAD. */
+void
+__pthread_block (struct __pthread *thread)
+{
+ debug (5, "%x.%x/%x blocking",
+ l4_thread_no (thread->threadid), l4_version (thread->threadid),
+ thread->threadid);
+
+ l4_accept (L4_UNTYPED_WORDS_ACCEPTOR);
+ l4_msg_tag_t tag = l4_receive (l4_anythread);
+ if (l4_ipc_failed (tag))
+ {
+ debug (1, "%x.%x failed to block: %d, offset: %x",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ (l4_error_code () >> 1) & 0x7,
+ l4_error_code () >> 4);
+ assert (! l4_ipc_failed (tag));
+ }
+ else
+ debug (5, "%x.%x unblocked",
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
+}
diff --git a/libpthread/sysdeps/l4/pt-docancel.c b/libpthread/sysdeps/l4/pt-docancel.c
new file mode 100644
index 00000000..a3965d0d
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-docancel.c
@@ -0,0 +1,42 @@
+/* Cancel a thread.
+ Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+static void
+call_exit (void)
+{
+ pthread_exit (0);
+}
+
+int
+__pthread_do_cancel (struct __pthread *p)
+{
+ assert (p->cancel_pending == 1);
+ assert (p->cancel_state == PTHREAD_CANCEL_ENABLE);
+
+ if (l4_is_thread_equal (l4_myself (), p->threadid))
+ call_exit ();
+ else
+ l4_start_sp_ip (p->threadid, (l4_word_t) p->mcontext.sp,
+ (l4_word_t) call_exit);
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/pt-pool-np.c b/libpthread/sysdeps/l4/pt-pool-np.c
new file mode 100644
index 00000000..e83022ba
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-pool-np.c
@@ -0,0 +1,54 @@
+/* Thread pool for L4 threads.
+ Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pt-internal.h>
+#include <l4/thread.h>
+
+static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER;
+
+_L4_thread_id_t pool_list = l4_nilthread;
+
+/* Add the thread TID to the pthread kernel thread pool. */
+int
+pthread_pool_add_np (l4_thread_id_t tid)
+{
+ __pthread_mutex_lock (&pool_lock);
+ /* FIXME: Do error checking. */
+ l4_set_user_defined_handle_of (tid, pool_list);
+ pool_list = tid;
+ __pthread_mutex_unlock (&pool_lock);
+
+ return 0;
+}
+
+
+/* Get the first thread from the pool. */
+l4_thread_id_t
+pthread_pool_get_np (void)
+{
+ _L4_thread_id_t tid;
+
+ __pthread_mutex_lock (&pool_lock);
+ /* FIXME: Do error checking. */
+ tid = pool_list;
+ if (tid != l4_nilthread)
+ pool_list = l4_user_defined_handle_of (tid);
+ __pthread_mutex_unlock (&pool_lock);
+ return tid;
+}
diff --git a/libpthread/sysdeps/l4/pt-spin.c b/libpthread/sysdeps/l4/pt-spin.c
new file mode 100644
index 00000000..b6978b0c
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-spin.c
@@ -0,0 +1,63 @@
+/* Spin locks. L4 version.
+ Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+
+#include <pthread.h>
+#include <sched.h>
+
+/* The default for single processor machines; don't spin, it's
+ pointless. */
+#ifndef __PTHREAD_SPIN_COUNT
+# define __PTHREAD_SPIN_COUNT 1
+#endif
+
+/* The number of times to spin while trying to lock a spin lock object
+ before yielding the processor. */
+int __pthread_spin_count = __PTHREAD_SPIN_COUNT;
+
+
+/* Lock the spin lock object LOCK. If the lock is held by another
+ thread spin until it becomes available. */
+int
+_pthread_spin_lock (__pthread_spinlock_t *lock)
+{
+ l4_time_t timeout;
+ int i;
+
+ /* Start with a small timeout of 2 microseconds, then back off
+ exponentially. */
+ timeout = l4_time_period (2);
+
+ while (1)
+ {
+ for (i = 0; i < __pthread_spin_count; i++)
+ {
+ if (__pthread_spin_trylock (lock) == 0)
+ return 0;
+ }
+ l4_sleep (timeout);
+
+ timeout = l4_time_mul2 (timeout);
+ if (timeout == L4_NEVER)
+ timeout = L4_TIME_PERIOD_MAX;
+ }
+}
+
+weak_alias (_pthread_spin_lock, pthread_spin_lock);
diff --git a/libpthread/sysdeps/l4/pt-stack-alloc.c b/libpthread/sysdeps/l4/pt-stack-alloc.c
new file mode 100644
index 00000000..b7ec12b4
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-stack-alloc.c
@@ -0,0 +1,43 @@
+/* Allocate a new stack. L4 Hurd version.
+ Copyright (C) 2000, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+#include <sys/mman.h>
+
+/* Allocate a new stack of size STACKSIZE. If successful, store the
+ address of the newly allocated stack in *STACKADDR and return 0.
+ Otherwise return an error code (EINVAL for an invalid stack size,
+ EAGAIN if the system lacked the necessary resources to allocate a
+ new stack). */
+int
+__pthread_stack_alloc (void **stackaddr, size_t stacksize)
+{
+ void *buffer = mmap (0, stacksize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (buffer == MAP_FAILED)
+ return EAGAIN;
+
+ *stackaddr = buffer;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/pt-thread-alloc.c b/libpthread/sysdeps/l4/pt-thread-alloc.c
new file mode 100644
index 00000000..ec69afb5
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-thread-alloc.c
@@ -0,0 +1,43 @@
+/* Allocate kernel thread. L4 version.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+int
+__pthread_thread_alloc (struct __pthread *thread)
+{
+ error_t err;
+
+ /* The main thread is already running of course. */
+ if (__pthread_num_threads == 1)
+ thread->threadid = l4_myself ();
+ else
+ {
+ thread->threadid = pthread_pool_get_np ();
+ if (thread->threadid != l4_nilthread)
+ return 0;
+
+ return EAGAIN;
+ }
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/pt-thread-dealloc.c b/libpthread/sysdeps/l4/pt-thread-dealloc.c
new file mode 100644
index 00000000..c09e4860
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-thread-dealloc.c
@@ -0,0 +1,32 @@
+/* Deallocate the kernel thread resources. L4 version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <l4.h>
+
+#include <pt-internal.h>
+
+/* Deallocate any kernel resources associated with THREAD except don't
+ halt the thread itself. On return, the thread will be marked as
+ dead and __pthread_halt will be called. */
+void
+__pthread_thread_dealloc (struct __pthread *thread)
+{
+}
diff --git a/libpthread/sysdeps/l4/pt-thread-halt.c b/libpthread/sysdeps/l4/pt-thread-halt.c
new file mode 100644
index 00000000..aa2bf43d
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-thread-halt.c
@@ -0,0 +1,45 @@
+/* Deallocate the kernel thread resources. L4version.
+ Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+/* Deallocate the kernel thread resources associated with THREAD. */
+void
+__pthread_thread_halt (struct __pthread *thread, int need_dealloc)
+{
+ l4_thread_id_t tid = thread->threadid;
+
+ if (need_dealloc)
+ __pthread_dealloc (thread);
+
+ /* There is potential race here: once if TID is the current thread,
+ then once we add TID to the pool, someone can reallocate it
+ before we call stop. However, to start the thread, the caller
+ atomically starts and sets the sp and ip, thus, if the stop has
+ not yet executed at that point, it won't. */
+
+ if (tid != l4_myself ())
+ l4_stop (tid);
+ pthread_pool_add_np (tid);
+ if (tid == l4_myself ())
+ l4_stop (tid);
+}
diff --git a/libpthread/sysdeps/l4/pt-thread-start.c b/libpthread/sysdeps/l4/pt-thread-start.c
new file mode 100644
index 00000000..144c58bb
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-thread-start.c
@@ -0,0 +1,40 @@
+/* Start thread. L4 version.
+ Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <pt-internal.h>
+
+/* Start THREAD. Get the kernel thread scheduled and running. */
+int
+__pthread_thread_start (struct __pthread *thread)
+{
+ if (__pthread_num_threads == 1)
+ /* The main thread is already running of course. */
+ {
+ assert (__pthread_total == 1);
+ assert (l4_is_thread_equal (l4_myself (), thread->threadid));
+ }
+ else
+ l4_start_sp_ip (thread->threadid, (l4_word_t) thread->mcontext.sp,
+ (l4_word_t) thread->mcontext.pc);
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/pt-timedblock.c b/libpthread/sysdeps/l4/pt-timedblock.c
new file mode 100644
index 00000000..ce7972bd
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-timedblock.c
@@ -0,0 +1,35 @@
+/* Block a thread with a timeout. L4 version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <pt-internal.h>
+
+/* Block THREAD. */
+error_t
+__pthread_timedblock (struct __pthread *thread,
+ const struct timespec *abstime)
+{
+#warning Need gettimeofday to implement properly.
+ __pthread_block (thread);
+ return 0;
+}
diff --git a/libpthread/sysdeps/l4/pt-wakeup.c b/libpthread/sysdeps/l4/pt-wakeup.c
new file mode 100644
index 00000000..de378465
--- /dev/null
+++ b/libpthread/sysdeps/l4/pt-wakeup.c
@@ -0,0 +1,54 @@
+/* Wakeup a thread. L4 version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+
+#include <pt-internal.h>
+
+#include <hurd/stddef.h>
+
+/* Wakeup THREAD. */
+void
+__pthread_wakeup (struct __pthread *thread)
+{
+ debug (5, "%x.%x/%x waking %x.%x/%x",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()), l4_myself (),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid),
+ thread->threadid);
+
+ /* Signal the waiter. */
+ l4_msg_t msg;
+ l4_msg_clear (msg);
+ l4_msg_set_untyped_words (msg, 0);
+ l4_msg_load (msg);
+
+ l4_msg_tag_t tag = l4_send (thread->threadid);
+ if (l4_ipc_failed (tag))
+ {
+ int err = l4_error_code ();
+ debug (1, "%x.%x failed to wake %x.%x: %s (%d)",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid),
+ l4_strerror (err), err);
+ }
+ else
+ debug (5, "%x.%x woke %x.%x",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
+}
diff --git a/libpthread/sysdeps/mach/bits/spin-lock-inline.h b/libpthread/sysdeps/mach/bits/spin-lock-inline.h
new file mode 100644
index 00000000..f9f7c299
--- /dev/null
+++ b/libpthread/sysdeps/mach/bits/spin-lock-inline.h
@@ -0,0 +1,90 @@
+/* Definitions of user-visible names for spin locks.
+ Copyright (C) 1994, 1997, 2002, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_SPIN_LOCK_INLINE_H
+#define _BITS_SPIN_LOCK_INLINE_H 1
+
+#include <features.h>
+#include <bits/spin-lock.h>
+#include <machine-lock.h> /* This does all the work. */
+
+__BEGIN_DECLS
+
+#if defined __USE_EXTERN_INLINES || defined _FORCE_INLINES
+
+# ifndef __EBUSY
+# include <errno.h>
+# define __EBUSY EBUSY
+# endif
+
+# ifndef __PT_SPIN_INLINE
+# define __PT_SPIN_INLINE __extern_inline
+# endif
+
+__PT_SPIN_INLINE int __pthread_spin_destroy (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_destroy (__pthread_spinlock_t *__lock)
+{
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock,
+ int __pshared);
+
+__PT_SPIN_INLINE int
+__pthread_spin_init (__pthread_spinlock_t *__lock, int __pshared)
+{
+ *__lock = __PTHREAD_SPIN_LOCK_INITIALIZER;
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_trylock (__pthread_spinlock_t *__lock)
+{
+ return __spin_try_lock (__lock) ? 0 : __EBUSY;
+}
+
+__extern_inline int __pthread_spin_lock (__pthread_spinlock_t *__lock);
+extern int _pthread_spin_lock (__pthread_spinlock_t *__lock);
+
+__extern_inline int
+__pthread_spin_lock (__pthread_spinlock_t *__lock)
+{
+ if (__pthread_spin_trylock (__lock))
+ return _pthread_spin_lock (__lock);
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_unlock (__pthread_spinlock_t *__lock)
+{
+ __spin_unlock (__lock);
+ return 0;
+}
+
+#endif /* Use extern inlines or force inlines. */
+
+__END_DECLS
+
+#endif /* bits/spin-lock.h */
diff --git a/libpthread/sysdeps/mach/bits/spin-lock.h b/libpthread/sysdeps/mach/bits/spin-lock.h
new file mode 100644
index 00000000..537dac9d
--- /dev/null
+++ b/libpthread/sysdeps/mach/bits/spin-lock.h
@@ -0,0 +1,38 @@
+/* Definitions of user-visible names for spin locks.
+ Copyright (C) 1994, 1997, 2002, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_SPIN_LOCK_H
+#define _BITS_SPIN_LOCK_H 1
+
+#include <features.h>
+#include <machine-lock.h> /* This does all the work. */
+
+__BEGIN_DECLS
+
+/* The type of a spin lock object. */
+typedef __spin_lock_t __pthread_spinlock_t;
+
+/* Initializer for a spin lock object. */
+#ifndef __PTHREAD_SPIN_LOCK_INITIALIZER
+#error __PTHREAD_SPIN_LOCK_INITIALIZER undefined: should be defined by <lock-intern.h>.
+#endif
+
+__END_DECLS
+
+#endif /* bits/spin-lock.h */
diff --git a/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c b/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c
new file mode 100644
index 00000000..f3c8cf50
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c
@@ -0,0 +1,83 @@
+/* Machine dependent pthreads code. Hurd/i386 version.
+ Copyright (C) 2000, 2002, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+
+#include <mach.h>
+#include <mach/i386/thread_status.h>
+#include <mach/i386/mach_i386.h>
+#include <mach/mig_errors.h>
+#include <mach/thread_status.h>
+
+#define HURD_TLS_DESC_DECL(desc, tcb) \
+ struct descriptor desc = \
+ { /* low word: */ \
+ 0xffff /* limit 0..15 */ \
+ | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \
+ , /* high word: */ \
+ ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \
+ | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \
+ | (0xf << 16) /* limit 16..19 */ \
+ | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \
+ | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \
+ }
+
+int
+__thread_set_pcsptp (thread_t thread,
+ int set_ip, void *ip,
+ int set_sp, void *sp,
+ int set_tp, void *tp)
+{
+ error_t err;
+ struct i386_thread_state state;
+ mach_msg_type_number_t state_count;
+
+ state_count = i386_THREAD_STATE_COUNT;
+
+ err = __thread_get_state (thread, i386_REGS_SEGS_STATE,
+ (thread_state_t) &state, &state_count);
+ if (err)
+ return err;
+
+ if (set_sp)
+ state.uesp = (unsigned int) sp;
+ if (set_ip)
+ state.eip = (unsigned int) ip;
+ if (set_tp) {
+ HURD_TLS_DESC_DECL(desc, tp);
+ int sel;
+
+ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0));
+ if (__builtin_expect (sel, 0x48) & 4) /* LDT selector */
+ err = __i386_set_ldt (thread, sel, &desc, 1);
+ else
+ err = __i386_set_gdt (thread, &sel, desc);
+ if (err)
+ return err;
+ state.gs = sel;
+ }
+
+ err = __thread_set_state (thread, i386_REGS_SEGS_STATE,
+ (thread_state_t) &state,
+ i386_THREAD_STATE_COUNT);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c b/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c
new file mode 100644
index 00000000..5420dc8e
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c
@@ -0,0 +1,108 @@
+/* Setup thread stack. Hurd/i386 version.
+ Copyright (C) 2000, 2002, 2005, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdint.h>
+#include <assert.h>
+#include <mach.h>
+
+#include <pt-internal.h>
+
+/* The stack layout used on the i386 is:
+
+ -----------------
+ | ARG |
+ -----------------
+ | START_ROUTINE |
+ -----------------
+ | 0 |
+ -----------------
+ | |
+ | Fast TSD |
+ | |
+ -----------------
+
+ We need to reserve __hurd_threadvar_max `unsigned long int's' of
+ (fast) thread-specific data (TSD) for the Hurd. */
+
+/* Set up the stack for THREAD, such that it appears as if
+ START_ROUTINE and ARG were passed to the new thread's entry-point.
+ Return the stack pointer for the new thread. */
+static void *
+stack_setup (struct __pthread *thread,
+ void *(*start_routine)(void *), void *arg)
+{
+ error_t err;
+ uintptr_t *bottom, *top;
+
+ /* Calculate the top of the new stack. */
+ bottom = thread->stackaddr;
+ top = (uintptr_t *) ((uintptr_t) bottom + thread->stacksize);
+
+ /* Next, make room for the TSDs. */
+ top -= __hurd_threadvar_max;
+
+ /* Save the self pointer. */
+ top[_HURD_THREADVAR_THREAD] = (uintptr_t) thread;
+
+ if (start_routine)
+ {
+ /* And then the call frame. */
+ top -= 2;
+ top = (uintptr_t *) ((uintptr_t) top & ~0xf);
+ top[1] = (uintptr_t) arg; /* Argument to START_ROUTINE. */
+ top[0] = (uintptr_t) start_routine;
+ *--top = 0; /* Fake return address. */
+ }
+
+ if (thread->guardsize)
+ {
+ err = __vm_protect (__mach_task_self (), (vm_address_t) bottom,
+ thread->guardsize, 0, 0);
+ assert_perror (err);
+ }
+
+ return top;
+}
+
+int
+__pthread_setup (struct __pthread *thread,
+ void (*entry_point)(void *(*)(void *), void *),
+ void *(*start_routine)(void *), void *arg)
+{
+ error_t err;
+ mach_port_t ktid;
+
+ thread->mcontext.pc = entry_point;
+ thread->mcontext.sp = stack_setup (thread, start_routine, arg);
+
+ thread->tcb->self = thread->kernel_thread;
+
+ ktid = __mach_thread_self ();
+ if (thread->kernel_thread != ktid)
+ {
+ err = __thread_set_pcsptp (thread->kernel_thread,
+ 1, thread->mcontext.pc,
+ 1, thread->mcontext.sp,
+ 1, thread->tcb);
+ assert_perror (err);
+ }
+ __mach_port_deallocate (__mach_task_self (), ktid);
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-attr-setstackaddr.c b/libpthread/sysdeps/mach/hurd/pt-attr-setstackaddr.c
new file mode 100644
index 00000000..1225ed5b
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-attr-setstackaddr.c
@@ -0,0 +1,35 @@
+/* pthread_attr_setstackaddr. Hurd on Mach version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+/* We use fixed sized stacks which require proper alignment. */
+#define __pthread_stacksize __pthread_default_attr.stacksize
+
+int
+pthread_attr_setstackaddr (pthread_attr_t *attr,
+ void *stackaddr)
+{
+ if ((long) stackaddr & (__pthread_stacksize - 1))
+ return EINVAL;
+
+ attr->stackaddr = stackaddr;
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-attr-setstacksize.c b/libpthread/sysdeps/mach/hurd/pt-attr-setstacksize.c
new file mode 100644
index 00000000..6471c0a3
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-attr-setstacksize.c
@@ -0,0 +1,35 @@
+/* pthread_attr_setstacksize. Hurd on Mach version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <pt-internal.h>
+
+/* We use fixed sized stacks which require proper alignment. */
+#define __pthread_stacksize __pthread_default_attr.stacksize
+
+int
+pthread_attr_setstacksize (pthread_attr_t *attr,
+ size_t stacksize)
+{
+ if (stacksize != __pthread_stacksize)
+ return EINVAL;
+
+ attr->stacksize = stacksize;
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-docancel.c b/libpthread/sysdeps/mach/hurd/pt-docancel.c
new file mode 100644
index 00000000..105c6fda
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-docancel.c
@@ -0,0 +1,64 @@
+/* Cancel a thread.
+ Copyright (C) 2002, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+static void
+call_exit (void)
+{
+ pthread_exit (0);
+}
+
+int
+__pthread_do_cancel (struct __pthread *p)
+{
+ mach_port_t ktid;
+ int me;
+
+ assert (p->cancel_pending == 1);
+ assert (p->cancel_state == PTHREAD_CANCEL_ENABLE);
+
+ ktid = __mach_thread_self ();
+ me = p->kernel_thread == ktid;
+ __mach_port_deallocate (__mach_task_self (), ktid);
+
+ if (me)
+ call_exit ();
+ else
+ {
+ error_t err;
+
+ err = __thread_suspend (p->kernel_thread);
+ assert_perror (err);
+
+ err = __thread_abort (p->kernel_thread);
+ assert_perror (err);
+
+ err = __thread_set_pcsptp (p->kernel_thread,
+ 1, (void *) call_exit, 0, 0, 0, 0);
+ assert_perror (err);
+
+ err = __thread_resume (p->kernel_thread);
+ assert_perror (err);
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-sigstate-destroy.c b/libpthread/sysdeps/mach/hurd/pt-sigstate-destroy.c
new file mode 100644
index 00000000..8e56c5cf
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-sigstate-destroy.c
@@ -0,0 +1,28 @@
+/* Destroy the signal state. Hurd on Mach version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+
+#include <pt-internal.h>
+
+void
+__pthread_sigstate_destroy (struct __pthread *thread)
+{
+ /* Nothing to do. */
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-sigstate-init.c b/libpthread/sysdeps/mach/hurd/pt-sigstate-init.c
new file mode 100644
index 00000000..da5a9455
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-sigstate-init.c
@@ -0,0 +1,37 @@
+/* Initialize the signal state. Hurd on Mach version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <hurd/threadvar.h>
+
+#include <pt-internal.h>
+
+error_t
+__pthread_sigstate_init (struct __pthread *thread)
+{
+ void **location =
+ (void *) __hurd_threadvar_location_from_sp (_HURD_THREADVAR_SIGSTATE,
+ thread->stackaddr);
+
+ /* The real initialization happens internally in glibc the first
+ time that _hurd_thead_sigstate is called. */
+ *location = 0;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-sigstate.c b/libpthread/sysdeps/mach/hurd/pt-sigstate.c
new file mode 100644
index 00000000..68c79c5b
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-sigstate.c
@@ -0,0 +1,69 @@
+/* Set a thread's signal state. Hurd on Mach version.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <hurd/signal.h>
+
+#include <pt-internal.h>
+
+error_t
+__pthread_sigstate (struct __pthread *thread, int how,
+ const sigset_t *set, sigset_t *oset,
+ int clear_pending)
+{
+ error_t err = 0;
+ struct hurd_sigstate *ss;
+
+ ss = _hurd_thread_sigstate (thread->kernel_thread);
+ assert (ss);
+
+ __pthread_spin_lock (&ss->lock);
+
+ if (oset)
+ *oset = ss->blocked;
+
+ if (set)
+ switch (how)
+ {
+ case SIG_BLOCK:
+ ss->blocked |= *set;
+ break;
+
+ case SIG_SETMASK:
+ ss->blocked = *set;
+ break;
+
+ case SIG_UNBLOCK:
+ ss->blocked &= ~*set;
+ break;
+
+ default:
+ err = EINVAL;
+ break;
+ }
+
+ if (! err && clear_pending)
+ __sigemptyset (&ss->pending);
+
+ __pthread_spin_unlock (&ss->lock);
+
+ return err;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-sysdep.c b/libpthread/sysdeps/mach/hurd/pt-sysdep.c
new file mode 100644
index 00000000..5e070067
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-sysdep.c
@@ -0,0 +1,72 @@
+/* System dependent pthreads code. Hurd version.
+ Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <mach.h>
+#include <mach/mig_support.h>
+
+#include <hurd/threadvar.h>
+
+#include <pt-internal.h>
+
+/* Forward. */
+static void *init_routine (void);
+
+/* OK, the name of this variable isn't really appropriate, but I don't
+ want to change it yet. */
+void *(*_cthread_init_routine)(void) = &init_routine;
+
+/* This function is called from the Hurd-specific startup code. It
+ should return a new stack pointer for the main thread. The caller
+ will switch to this new stack before doing anything serious. */
+static void *
+init_routine (void)
+{
+ struct __pthread *thread;
+ int err;
+
+ /* Initialize the library. */
+ __pthread_initialize ();
+
+ /* Create the pthread structure for the main thread (i.e. us). */
+ err = __pthread_create_internal (&thread, 0, 0, 0);
+ assert_perror (err);
+
+ ((void **) (__hurd_threadvar_stack_offset))[_HURD_THREADVAR_THREAD]
+ = thread;
+
+ /* Decrease the number of threads, to take into account that the
+ signal thread (which will be created by the glibc startup code
+ when we return from here) shouldn't be seen as a user thread. */
+ __pthread_total--;
+
+ /* Make MiG code thread aware. */
+ __mig_init (thread->stackaddr);
+
+ /* Make sure we can find the per-thread variables. */
+ __hurd_threadvar_stack_mask = ~(__pthread_default_attr.stacksize - 1);
+ __hurd_threadvar_stack_offset
+ = (__pthread_default_attr.stacksize
+ - __hurd_threadvar_max * sizeof (uintptr_t));
+
+ return thread->mcontext.sp;
+}
diff --git a/libpthread/sysdeps/mach/hurd/pt-sysdep.h b/libpthread/sysdeps/mach/hurd/pt-sysdep.h
new file mode 100644
index 00000000..13e235d9
--- /dev/null
+++ b/libpthread/sysdeps/mach/hurd/pt-sysdep.h
@@ -0,0 +1,72 @@
+/* Internal defenitions for pthreads library.
+ Copyright (C) 2000, 2002, 2007, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PT_SYSDEP_H
+#define _PT_SYSDEP_H 1
+
+#include <mach.h>
+
+#include <hurd/threadvar.h>
+
+/* XXX */
+#define _POSIX_THREAD_THREADS_MAX 64
+
+/* The default stack size. */
+#define PTHREAD_STACK_DEFAULT (2 * 1024 * 1024)
+
+#define PTHREAD_SYSDEP_MEMBERS \
+ thread_t kernel_thread; \
+ mach_msg_header_t wakeupmsg; \
+ int have_kernel_resources;
+
+#define _HURD_THREADVAR_THREAD _HURD_THREADVAR_DYNAMIC_USER
+
+#define _pthread_self() \
+ ({ \
+ struct __pthread *thread; \
+ \
+ assert (__pthread_threads); \
+ thread = *(struct __pthread **) \
+ __hurd_threadvar_location (_HURD_THREADVAR_THREAD); \
+ \
+ assert (thread); \
+ assert (({ mach_port_t ktid = __mach_thread_self (); \
+ int ok = thread->kernel_thread == ktid; \
+ __mach_port_deallocate (__mach_task_self (), ktid);\
+ ok; })); \
+ thread; \
+ })
+
+extern inline void
+__attribute__((__always_inline__))
+__pthread_stack_dealloc (void *stackaddr, size_t stacksize)
+{
+ __vm_deallocate (__mach_task_self (), (vm_offset_t) stackaddr, stacksize);
+}
+
+/* Change thread THREAD's program counter to PC if SET_PC is true,
+ its stack pointer to SP if SET_IP is true, and its thread pointer
+ to TP if SET_TP is true. */
+extern int __thread_set_pcsptp (thread_t thread,
+ int set_pc, void *pc,
+ int set_sp, void *sp,
+ int set_tp, void *tp);
+
+
+#endif /* pt-sysdep.h */
diff --git a/libpthread/sysdeps/mach/pt-block.c b/libpthread/sysdeps/mach/pt-block.c
new file mode 100644
index 00000000..a947b27c
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-block.c
@@ -0,0 +1,39 @@
+/* Block a thread. Mach version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <mach.h>
+#include <mach/message.h>
+
+#include <pt-internal.h>
+
+/* Block THREAD. */
+void
+__pthread_block (struct __pthread *thread)
+{
+ mach_msg_header_t msg;
+ error_t err;
+
+ err = __mach_msg (&msg, MACH_RCV_MSG, 0, sizeof msg,
+ thread->wakeupmsg.msgh_remote_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ assert_perror (err);
+}
diff --git a/libpthread/sysdeps/mach/pt-spin.c b/libpthread/sysdeps/mach/pt-spin.c
new file mode 100644
index 00000000..d9a2a32a
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-spin.c
@@ -0,0 +1,36 @@
+/* Spin locks. Mach version.
+ Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <machine-lock.h>
+
+/* In glibc. */
+extern void __spin_lock_solid (__pthread_spinlock_t *lock);
+
+/* Lock the spin lock object LOCK. If the lock is held by another
+ thread spin until it becomes available. */
+int
+_pthread_spin_lock (__pthread_spinlock_t *lock)
+{
+ __spin_lock_solid (lock);
+ return 0;
+}
+
+weak_alias (_pthread_spin_lock, pthread_spin_lock);
+weak_alias (_pthread_spin_lock, __pthread_spin_lock);
diff --git a/libpthread/sysdeps/mach/pt-stack-alloc.c b/libpthread/sysdeps/mach/pt-stack-alloc.c
new file mode 100644
index 00000000..0956fc7d
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-stack-alloc.c
@@ -0,0 +1,74 @@
+/* Allocate a new stack. Mach version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+
+#include <mach.h>
+#include <mach/machine/vm_param.h>
+
+#include <pt-internal.h>
+
+#define __pthread_stacksize __pthread_default_attr.stacksize
+
+/* The next address to use for stack allocation. */
+static vm_address_t next_stack_base = VM_MIN_ADDRESS;
+
+
+/* Allocate a new stack of size STACKSIZE. If successful, store the
+ address of the newly allocated stack in *STACKADDR and return 0.
+ Otherwise return an error code (EINVAL for an invalid stack size,
+ EAGAIN if the system lacked the necessary resources to allocate a
+ new stack). */
+int
+__pthread_stack_alloc (void **stackaddr, size_t stacksize)
+{
+ vm_offset_t base;
+ int i = 0;
+
+ if (stacksize != __pthread_stacksize)
+ return EINVAL;
+
+ get_stack:
+ i ++;
+ for (base = next_stack_base;
+ base < VM_MAX_ADDRESS
+ && __vm_allocate (__mach_task_self (), &base,
+ __pthread_stacksize, FALSE) != KERN_SUCCESS;
+ base += __pthread_stacksize)
+ ;
+
+ if (base >= VM_MAX_ADDRESS)
+ {
+ if (i == 1)
+ {
+ next_stack_base = VM_MIN_ADDRESS;
+ goto get_stack;
+ }
+ else
+ return EAGAIN;
+ }
+
+ if (base >= VM_MAX_ADDRESS)
+ return EAGAIN;
+
+ next_stack_base = base + __pthread_stacksize;
+
+ (*stackaddr) = (void *) base;
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/pt-thread-alloc.c b/libpthread/sysdeps/mach/pt-thread-alloc.c
new file mode 100644
index 00000000..3d7c0465
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-thread-alloc.c
@@ -0,0 +1,106 @@
+/* Start thread. Mach version.
+ Copyright (C) 2000, 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
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <mach.h>
+
+#include <pt-internal.h>
+
+/* Prepare a wakeup message. */
+static error_t
+create_wakeupmsg (struct __pthread *thread)
+{
+ kern_return_t err;
+
+ /* Build wakeup message. */
+ thread->wakeupmsg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+ thread->wakeupmsg.msgh_size = 0;
+
+ err = __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &thread->wakeupmsg.msgh_remote_port);
+ if (err)
+ return EAGAIN;
+
+ thread->wakeupmsg.msgh_local_port = MACH_PORT_NULL;
+ thread->wakeupmsg.msgh_seqno = 0;
+ thread->wakeupmsg.msgh_id = 0;
+
+ err = __mach_port_insert_right (__mach_task_self (),
+ thread->wakeupmsg.msgh_remote_port,
+ thread->wakeupmsg.msgh_remote_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (err)
+ {
+ __mach_port_destroy (__mach_task_self (),
+ thread->wakeupmsg.msgh_remote_port);
+ return EAGAIN;
+ }
+
+ return 0;
+}
+
+/* Allocate any resouces for THREAD. The new kernel thread should not
+ be eligible to be scheduled. */
+int
+__pthread_thread_alloc (struct __pthread *thread)
+{
+ if (thread->have_kernel_resources)
+ return 0;
+
+ error_t err;
+
+ err = create_wakeupmsg (thread);
+ if (err)
+ return err;
+
+ /* If there are no pthreads in the system then the pthread library
+ is bootstrapping and the main thread must create initialize
+ itself. The thread itself is already running, it just has not
+ pthread context. We want to reuse what it already has (including
+ the kernel thread), however, we must determine which thread is
+ the main thread.
+
+ We cannot test if __pthread_total is one as we later decrement
+ before creating the signal thread. Currently, we check if
+ __pthread_num_threads--the number of allocated thread
+ structures--is one. __pthread_alloc has already been called in
+ __pthread_create_internal for us. This predicate could be improved,
+ however, it is sufficient for now. */
+ if (__pthread_num_threads == 1)
+ {
+ assert (__pthread_total == 0);
+ thread->kernel_thread = __mach_thread_self ();
+ /* We implicitly hold a reference drop the one that we just
+ acquired. */
+ __mach_port_deallocate (__mach_task_self (), thread->kernel_thread);
+ }
+ else
+ {
+ err = __thread_create (__mach_task_self (), &thread->kernel_thread);
+ if (err)
+ return EAGAIN;
+ }
+
+ thread->have_kernel_resources = 1;
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/pt-thread-dealloc.c b/libpthread/sysdeps/mach/pt-thread-dealloc.c
new file mode 100644
index 00000000..55d8c4d5
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-thread-dealloc.c
@@ -0,0 +1,41 @@
+/* Deallocate the kernel thread resources. Mach version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <mach.h>
+
+#include <pt-internal.h>
+
+/* Deallocate any kernel resources associated with THREAD except don't
+ halt the thread itself. On return, the thread will be marked as
+ dead and __pthread_halt will be called. */
+void
+__pthread_thread_dealloc (struct __pthread *thread)
+{
+ /* Why no assert? Easy. When Mach kills a task, it starts by
+ invalidating the task port and then terminating the threads one
+ by one. But while it is terminating them, they are still
+ eligible to be scheduled. Imagine we have two threads, one calls
+ exit, one calls pthread_exit. The second one may run this after
+ the mask port can been destroyed thus gratuitously triggering the
+ assert. */
+ __mach_port_destroy (__mach_task_self (),
+ thread->wakeupmsg.msgh_remote_port);
+}
diff --git a/libpthread/sysdeps/mach/pt-thread-halt.c b/libpthread/sysdeps/mach/pt-thread-halt.c
new file mode 100644
index 00000000..973cde1e
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-thread-halt.c
@@ -0,0 +1,37 @@
+/* Deallocate the kernel thread resources. Mach version.
+ Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <mach.h>
+
+#include <pt-internal.h>
+
+/* Stop the kernel thread associated with THREAD. If NEED_DEALLOC is
+ true, the function must call __pthread_dealloc on THREAD.
+
+ NB: The thread executing this function may be the thread which is
+ being halted, thus the last action should be halting the thread
+ itself. */
+void
+__pthread_thread_halt (struct __pthread *thread)
+{
+ error_t err = __thread_terminate (thread->kernel_thread);
+ assert_perror (err);
+}
diff --git a/libpthread/sysdeps/mach/pt-thread-start.c b/libpthread/sysdeps/mach/pt-thread-start.c
new file mode 100644
index 00000000..11b017ff
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-thread-start.c
@@ -0,0 +1,49 @@
+/* Start thread. Mach version.
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <mach.h>
+
+#include <pt-internal.h>
+
+/* Start THREAD. Get the kernel thread scheduled and running. */
+int
+__pthread_thread_start (struct __pthread *thread)
+{
+ error_t err;
+
+ if (__pthread_num_threads == 1)
+ {
+ /* The main thread is already running: do nothing. */
+ assert (__pthread_total == 1);
+ assert (({ mach_port_t ktid = __mach_thread_self ();
+ int ok = thread->kernel_thread == ktid;
+ __mach_port_deallocate (__mach_task_self (),
+ thread->kernel_thread);
+ ok; }));
+ }
+ else
+ {
+ err = __thread_resume (thread->kernel_thread);
+ assert_perror (err);
+ }
+
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/pt-timedblock.c b/libpthread/sysdeps/mach/pt-timedblock.c
new file mode 100644
index 00000000..6f547265
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-timedblock.c
@@ -0,0 +1,68 @@
+/* Block a thread with a timeout. Mach version.
+ Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <mach.h>
+#include <mach/message.h>
+
+#include <pt-internal.h>
+
+/* Block THREAD. */
+error_t
+__pthread_timedblock (struct __pthread *thread,
+ const struct timespec *abstime)
+{
+ error_t err;
+ mach_msg_header_t msg;
+ mach_msg_timeout_t timeout;
+ struct timeval now;
+
+ /* We have an absolute time and now we have to convert it to a
+ relative time. Arg. */
+
+ err = gettimeofday(&now, NULL);
+ assert (! err);
+
+ if (now.tv_sec > abstime->tv_sec
+ || (now.tv_sec == abstime->tv_sec
+ && now.tv_usec > ((abstime->tv_nsec + 999) / 1000)))
+ return ETIMEDOUT;
+
+ timeout = (abstime->tv_sec - now.tv_sec) * 1000;
+
+ if (((abstime->tv_nsec + 999) / 1000) >= now.tv_usec)
+ timeout += (((abstime->tv_nsec + 999) / 1000) - now.tv_usec + 999) / 1000;
+ else
+ /* Need to do a carry. */
+ timeout -= (now.tv_usec + 999) / 1000 -
+ ((abstime->tv_nsec + 999999) / 1000000);
+
+ err = __mach_msg (&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
+ sizeof msg, thread->wakeupmsg.msgh_remote_port,
+ timeout, MACH_PORT_NULL);
+ if (err == EMACH_RCV_TIMED_OUT)
+ return ETIMEDOUT;
+
+ assert_perror (err);
+ return 0;
+}
diff --git a/libpthread/sysdeps/mach/pt-wakeup.c b/libpthread/sysdeps/mach/pt-wakeup.c
new file mode 100644
index 00000000..4920d102
--- /dev/null
+++ b/libpthread/sysdeps/mach/pt-wakeup.c
@@ -0,0 +1,38 @@
+/* Wakeup a thread. Mach version.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <mach.h>
+#include <mach/message.h>
+
+#include <pt-internal.h>
+
+/* Wakeup THREAD. */
+void
+__pthread_wakeup (struct __pthread *thread)
+{
+ error_t err;
+
+ err = __mach_msg (&thread->wakeupmsg, MACH_SEND_MSG,
+ sizeof (thread->wakeupmsg), 0, MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ assert_perror (err);
+}
diff --git a/libpthread/sysdeps/posix/pt-spin.c b/libpthread/sysdeps/posix/pt-spin.c
new file mode 100644
index 00000000..cb809c64
--- /dev/null
+++ b/libpthread/sysdeps/posix/pt-spin.c
@@ -0,0 +1,54 @@
+/* Spin locks.
+ Copyright (C) 2000, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <sched.h>
+
+/* The default for single processor machines; don't spin, it's
+ pointless. */
+#ifndef __PTHREAD_SPIN_COUNT
+# define __PTHREAD_SPIN_COUNT 1
+#endif
+
+/* The number of times to spin while trying to lock a spin lock object
+ before yielding the processor. */
+int __pthread_spin_count = __PTHREAD_SPIN_COUNT;
+
+
+/* Lock the spin lock object LOCK. If the lock is held by another
+ thread spin until it becomes available. */
+int
+_pthread_spin_lock (__pthread_spinlock_t *lock)
+{
+ int i;
+
+ while (1)
+ {
+ for (i = 0; i < __pthread_spin_count; i++)
+ {
+ if (__pthread_spin_trylock (lock) == 0)
+ return 0;
+ }
+
+ __sched_yield ();
+ }
+}
+
+weak_alias (_pthread_spin_lock, pthread_spin_lock);
+weak_alias (_pthread_spin_lock, __pthread_spin_lock);
diff --git a/libpthread/sysdeps/powerpc/bits/machine-lock.h b/libpthread/sysdeps/powerpc/bits/machine-lock.h
new file mode 100644
index 00000000..cba6b0a6
--- /dev/null
+++ b/libpthread/sysdeps/powerpc/bits/machine-lock.h
@@ -0,0 +1,78 @@
+/* Machine-specific definition for spin locks. PowerPC version.
+ Copyright (C) 1994,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _MACHINE_LOCK_H
+#define _MACHINE_LOCK_H
+
+/* The type of a spin lock variable. */
+
+typedef __volatile long int __spin_lock_t;
+
+/* Value to initialize `__spin_lock_t' variables to. */
+
+#define __SPIN_LOCK_INITIALIZER 0L
+
+
+#ifndef _EXTERN_INLINE
+#define _EXTERN_INLINE extern __inline
+#endif
+
+/* Unlock LOCK. */
+
+_EXTERN_INLINE void
+__spin_unlock (__spin_lock_t *__lock)
+{
+ long int __locked;
+ __asm__ __volatile__ ("\
+0: lwarx %0,0,%1\n\
+ stwcx. %2,0,%1\n\
+ bne- 0b\n\
+" : "=&r" (__locked) : "r" (__lock), "r" (0) : "cr0");
+}
+
+/* Try to lock LOCK; return nonzero if we locked it, zero if another has. */
+
+_EXTERN_INLINE int
+__spin_try_lock (register __spin_lock_t *__lock)
+{
+ long int __rtn;
+ __asm__ __volatile__ ("\
+0: lwarx %0,0,%1\n\
+ stwcx. %2,0,%1\n\
+ bne- 0b\n\
+" : "=&r" (__rtn) : "r" (__lock), "r" (1) : "cr0");
+ return !__rtn;
+}
+
+/* Return nonzero if LOCK is locked. */
+
+_EXTERN_INLINE int
+__spin_lock_locked (__spin_lock_t *__lock)
+{
+ long int __rtn;
+ __asm__ __volatile__ ("\
+0: lwarx %0,0,%1\n\
+ stwcx. %0,0,%1\n\
+ bne- 0b\n\
+" : "=&r" (__rtn) : "r" (__lock) : "cr0");
+ return __rtn;
+}
+
+
+#endif /* machine-lock.h */
diff --git a/libpthread/sysdeps/powerpc/bits/memory.h b/libpthread/sysdeps/powerpc/bits/memory.h
new file mode 100644
index 00000000..96624c3e
--- /dev/null
+++ b/libpthread/sysdeps/powerpc/bits/memory.h
@@ -0,0 +1,36 @@
+/* Memory barrier operations. PowerPC version.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_MEMORY_H
+#define _BITS_MEMORY_H 1
+
+/* Prevent read and write reordering across this function. */
+inline void
+__memory_barrier (void)
+{
+ asm ("sync" ::: "memory");
+}
+
+/* Prevent read reordering across this function. */
+#define __memory_read_barrier __memory_barrier
+
+/* Prevent write reordering across this function. */
+#define __memory_write_barrier __memory_barrier
+
+#endif
diff --git a/libpthread/sysdeps/powerpc/bits/spin-lock.h b/libpthread/sysdeps/powerpc/bits/spin-lock.h
new file mode 100644
index 00000000..1dc25710
--- /dev/null
+++ b/libpthread/sysdeps/powerpc/bits/spin-lock.h
@@ -0,0 +1,108 @@
+/* Machine-specific definitions for spin locks. PowerPC version.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * Never include this file directly; use <pthread.h> or <cthreads.h> instead.
+ */
+
+#ifndef _BITS_SPIN_LOCK_H
+#define _BITS_SPIN_LOCK_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* The type of a spin lock object. */
+typedef __volatile int __pthread_spinlock_t;
+
+/* Initializer for a spin lock object. */
+# define __SPIN_LOCK_INITIALIZER ((__pthread_spinlock_t) 0)
+
+#if defined __USE_EXTERN_INLINES || defined _FORCE_INLINES
+
+# ifndef __EBUSY
+# include <errno.h>
+# define __EBUSY EBUSY
+# endif
+
+# ifndef __PT_SPIN_INLINE
+# define __PT_SPIN_INLINE extern __inline
+# endif
+
+__PT_SPIN_INLINE int __pthread_spin_destroy (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_destroy (__pthread_spinlock_t *__lock)
+{
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock,
+ int __pshared);
+
+__PT_SPIN_INLINE int
+__pthread_spin_init (__pthread_spinlock_t *__lock, int __pshared)
+{
+ *__lock = __SPIN_LOCK_INITIALIZER;
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_trylock (__pthread_spinlock_t *__lock)
+{
+ long int __rtn;
+ __asm__ __volatile__ ("\
+0: lwarx %0,0,%1\n\
+ stwcx. %2,0,%1\n\
+ bne- 0b\n\
+" : "=&r" (__rtn) : "r" (__lock), "r" (1) : "cr0");
+ return __rtn ? __EBUSY : 0;
+}
+
+extern inline int __pthread_spin_lock (__pthread_spinlock_t *__lock);
+extern int _pthread_spin_lock (__pthread_spinlock_t *__lock);
+
+extern inline int
+__pthread_spin_lock (__pthread_spinlock_t *__lock)
+{
+ if (__pthread_spin_trylock (__lock))
+ return _pthread_spin_lock (__lock);
+ return 0;
+}
+
+__PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock);
+
+__PT_SPIN_INLINE int
+__pthread_spin_unlock (__pthread_spinlock_t *__lock)
+{
+ long int __locked;
+ __asm__ __volatile__ ("\
+0: lwarx %0,0,%1\n\
+ stwcx. %2,0,%1\n\
+ bne- 0b\n\
+" : "=&r" (__locked) : "r" (__lock), "r" (0) : "cr0");
+}
+
+#endif /* Use extern inlines or force inlines. */
+
+__END_DECLS
+
+#endif /* bits/spin-lock.h */
diff --git a/libpthread/sysdeps/powerpc/machine-sp.h b/libpthread/sysdeps/powerpc/machine-sp.h
new file mode 100644
index 00000000..aa787c59
--- /dev/null
+++ b/libpthread/sysdeps/powerpc/machine-sp.h
@@ -0,0 +1,31 @@
+/* Machine-specific function to return the stack pointer. i386 version.
+ Copyright (C) 1994,97,2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _MACHINE_SP_H
+#define _MACHINE_SP_H
+
+/* Return the current stack pointer. */
+
+#define __thread_stack_pointer() ({ \
+ void *__sp__; \
+ __asm__ ("mr %0, 1" : "=r" (__sp__)); \
+ __sp__; \
+})
+
+#endif /* machine-sp.h */
diff --git a/libpthread/sysdeps/powerpc/pt-machdep.h b/libpthread/sysdeps/powerpc/pt-machdep.h
new file mode 100644
index 00000000..6d456367
--- /dev/null
+++ b/libpthread/sysdeps/powerpc/pt-machdep.h
@@ -0,0 +1,29 @@
+/* Machine dependent pthreads internal defenitions. i386 version.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PT_MACHDEP_H
+#define _PT_MACHDEP_H 1
+
+struct pthread_mcontext
+{
+ void *pc;
+ void *sp;
+};
+
+#endif /* pt-machdep.h */
diff --git a/libpthread/tests/.cvsignore b/libpthread/tests/.cvsignore
new file mode 100644
index 00000000..70845e08
--- /dev/null
+++ b/libpthread/tests/.cvsignore
@@ -0,0 +1 @@
+Makefile.in
diff --git a/libpthread/tests/Makefile b/libpthread/tests/Makefile
new file mode 100644
index 00000000..5ebc01d3
--- /dev/null
+++ b/libpthread/tests/Makefile
@@ -0,0 +1,29 @@
+CFLAGS=-Wall -g
+
+LDLIBS = -lpthread
+
+CHECK_SRC := test-1.c test-2.c test-3.c test-6.c test-7.c test-8.c \
+ test-9.c test-10.c test-11.c test-12.c test-13.c test-14.c \
+ test-15.c test-16.c test-17.c test-__pthread_destroy_specific-skip.c
+
+CHECK_OBJS := $(addsuffix .o,$(basename $(notdir $(CHECK_SRC))))
+CHECK_PROGS := $(basename $(notdir $(CHECK_SRC))) \
+ $(addsuffix -static, $(basename $(CHECK_SRC)))
+
+%-static: %.o
+ $(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS)
+
+check: $(CHECK_OBJS) $(CHECK_PROGS)
+ for i in $(CHECK_PROGS); do \
+ echo -n Running $$i...\ ; \
+ if ./$$i 2>&1 > $$i.out; \
+ then \
+ echo Success.; \
+ else \
+ echo Failure.; \
+ fi \
+ done
+
+clean:
+ rm -f $(CHECK_OBJS) $(CHECK_PROGS) \
+ $(addsuffix .out,$(basename $(notdir $(CHECK_PROGS)))) \ No newline at end of file
diff --git a/libpthread/tests/test-1.c b/libpthread/tests/test-1.c
new file mode 100644
index 00000000..6ec1afb3
--- /dev/null
+++ b/libpthread/tests/test-1.c
@@ -0,0 +1,50 @@
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+
+#define THREADS 500
+
+void *
+foo (void *arg)
+{
+ pthread_mutex_t *mutex = arg;
+ pthread_mutex_lock (mutex);
+ pthread_mutex_unlock (mutex);
+ return mutex;
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ error_t err;
+ pthread_t tid[THREADS];
+ pthread_mutex_t mutex[THREADS];
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ pthread_mutex_init (&mutex[i], 0);
+ pthread_mutex_lock (&mutex[i]);
+ err = pthread_create (&tid[i], 0, foo, &mutex[i]);
+ if (err)
+ error (1, err, "pthread_create");
+ sched_yield ();
+ }
+
+ for (i = THREADS - 1; i >= 0; i --)
+ {
+ void *ret;
+ pthread_mutex_unlock (&mutex[i]);
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+ assert (ret == &mutex[i]);
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-10.c b/libpthread/tests/test-10.c
new file mode 100644
index 00000000..bec05c14
--- /dev/null
+++ b/libpthread/tests/test-10.c
@@ -0,0 +1,46 @@
+/* Test error checking mutexes. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+
+ err = pthread_mutexattr_init (&mattr);
+ if (err)
+ error (1, err, "pthread_mutexattr_init");
+
+ err = pthread_mutexattr_settype (&mattr, PTHREAD_MUTEX_ERRORCHECK);
+ if (err)
+ error (1, err, "pthread_mutexattr_settype");
+
+ err = pthread_mutex_init (&mutex, &mattr);
+ if (err)
+ error (1, err, "pthread_mutex_init");
+
+ err = pthread_mutexattr_destroy (&mattr);
+ if (err)
+ error (1, err, "pthread_mutexattr_destroy");
+
+ err = pthread_mutex_lock (&mutex);
+ assert (err == 0);
+
+ err = pthread_mutex_lock (&mutex);
+ assert (err == EDEADLK);
+
+ err = pthread_mutex_unlock (&mutex);
+ assert (err == 0);
+
+ err = pthread_mutex_unlock (&mutex);
+ assert (err == EPERM);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-11.c b/libpthread/tests/test-11.c
new file mode 100644
index 00000000..de779a40
--- /dev/null
+++ b/libpthread/tests/test-11.c
@@ -0,0 +1,143 @@
+/* Test rwlocks. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+
+#define THREADS 1
+
+int a;
+int b;
+
+/* Get a read lock and assert that a == b. */
+void *
+test1 (void *arg)
+{
+ error_t err;
+ pthread_rwlock_t *lock = arg;
+ int i;
+
+ for (i = 0; i < 200; i ++)
+ {
+ err = pthread_rwlock_rdlock (lock);
+ assert (err == 0);
+
+ assert (a == b);
+
+ sched_yield ();
+
+ assert (a == b);
+
+ err = pthread_rwlock_unlock (lock);
+ assert (err == 0);
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ pthread_rwlockattr_t attr;
+ pthread_rwlock_t lock;
+ int pshared;
+
+ int i;
+ pthread_t tid[THREADS];
+ void *ret;
+
+ err = pthread_rwlockattr_init (&attr);
+ if (err)
+ error (1, err, "pthread_rwlockattr_init");
+
+ err = pthread_rwlockattr_getpshared (&attr, &pshared);
+ if (err)
+ error (1, err, "pthread_rwlockattr_getpshared");
+
+ /* Assert the default state as mandated by POSIX. */
+ assert (pshared == PTHREAD_PROCESS_PRIVATE);
+
+ err = pthread_rwlockattr_setpshared (&attr, pshared);
+ if (err)
+ error (1, err, "pthread_rwlockattr_setpshared");
+
+ err = pthread_rwlock_init (&lock, &attr);
+ if (err)
+ error (1, err, "pthread_rwlock_init");
+
+ err = pthread_rwlockattr_destroy (&attr);
+ if (err)
+ error (1, err, "pthread_rwlockattr_destroy");
+
+ /* Now test the lock. */
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, test1, &lock);
+ if (err)
+ error (1, err, "pthread_create");
+ }
+
+ for (i = 0; i < 10; i ++)
+ {
+ sched_yield ();
+
+ /* Get a write lock. */
+ pthread_rwlock_wrlock (&lock);
+ /* Increment a and b giving other threads a chance to run in
+ between. */
+ sched_yield ();
+ a ++;
+ sched_yield ();
+ b ++;
+ sched_yield ();
+ /* Unlock. */
+ pthread_rwlock_unlock (&lock);
+ }
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+ }
+
+ /* Read lock it. */
+ err = pthread_rwlock_tryrdlock (&lock);
+ assert (err == 0);
+
+ /* Try to write lock it. It should fail with EBUSY. */
+ err = pthread_rwlock_trywrlock (&lock);
+ assert (err == EBUSY);
+
+ /* Drop the read lock. */
+ err = pthread_rwlock_unlock (&lock);
+ assert (err == 0);
+
+ /* Get a write lock. */
+ err = pthread_rwlock_trywrlock (&lock);
+ assert (err == 0);
+
+ /* Fail trying to acquire another write lock. */
+ err = pthread_rwlock_trywrlock (&lock);
+ assert (err == EBUSY);
+
+ /* Try to get a read lock which should also fail. */
+ err = pthread_rwlock_tryrdlock (&lock);
+ assert (err == EBUSY);
+
+ /* Unlock it. */
+ err = pthread_rwlock_unlock (&lock);
+ assert (err == 0);
+
+
+ err = pthread_rwlock_destroy (&lock);
+ if (err)
+ error (1, err, "pthread_rwlock_destroy");
+
+ return 0;
+}
diff --git a/libpthread/tests/test-12.c b/libpthread/tests/test-12.c
new file mode 100644
index 00000000..2b784908
--- /dev/null
+++ b/libpthread/tests/test-12.c
@@ -0,0 +1,29 @@
+/* Test concurrency level. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ int err;
+
+ i = pthread_getconcurrency ();
+ assert (i == 0);
+
+ err = pthread_setconcurrency (-1);
+ assert (err == EINVAL);
+
+ err = pthread_setconcurrency (4);
+ assert (err == 0);
+
+ i = pthread_getconcurrency ();
+ assert (i == 4);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-13.c b/libpthread/tests/test-13.c
new file mode 100644
index 00000000..13b09051
--- /dev/null
+++ b/libpthread/tests/test-13.c
@@ -0,0 +1,66 @@
+/* Test condition attributes and pthread_cond_timedwait. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/time.h>
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int i;
+ pthread_condattr_t attr;
+ pthread_cond_t cond;
+ struct timespec ts;
+ pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+ struct timeval before, after;
+ int diff;
+
+ err = pthread_condattr_init (&attr);
+ if (err)
+ error (1, err, "pthread_condattr_init");
+
+ err = pthread_condattr_getpshared (&attr, &i);
+ if (err)
+ error (1, err, "pthread_condattr_getpshared");
+ assert (i == PTHREAD_PROCESS_PRIVATE);
+
+ err = pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_PRIVATE);
+ assert (err == 0);
+
+ err = pthread_cond_init (&cond, &attr);
+ if (err)
+ error (1, err, "pthread_cond_init");
+
+ err = pthread_condattr_destroy (&attr);
+ if (err)
+ error (1, err, "pthread_condattr_destroy");
+
+ gettimeofday (&before, 0);
+ ts.tv_sec = before.tv_sec + 1;
+ ts.tv_nsec = before.tv_usec * 1000;
+
+ printf ("Starting wait @ %d\n", (int) before.tv_sec);
+
+ pthread_mutex_lock (&m);
+ err = pthread_cond_timedwait (&cond, &m, &ts);
+
+ gettimeofday (&after, 0);
+
+ printf ("End wait @ %d (err = %d)\n", (int) after.tv_sec, err);
+
+ assert (err == ETIMEDOUT);
+
+ diff = after.tv_sec * 1000000 + after.tv_usec
+ - before.tv_sec * 1000000 - before.tv_usec;
+
+ if (diff < 900000 || diff > 1100000)
+ error (1, EGRATUITOUS, "pthread_cond_timedwait waited %d us", diff);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-14.c b/libpthread/tests/test-14.c
new file mode 100644
index 00000000..b1dbfa66
--- /dev/null
+++ b/libpthread/tests/test-14.c
@@ -0,0 +1,44 @@
+/* Test pthread_mutex_timedlock. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/time.h>
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct timespec ts;
+ pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+ struct timeval before, after;
+ int diff;
+
+ gettimeofday (&before, 0);
+ ts.tv_sec = before.tv_sec + 1;
+ ts.tv_nsec = before.tv_usec * 1000;
+
+ printf ("Starting wait @ %d\n", (int) before.tv_sec);
+
+ pthread_mutex_lock (&m);
+ /* A default mutex shall dead lock if locked twice. As such we do
+ not need spawn a second thread. */
+ err = pthread_mutex_timedlock (&m, &ts);
+ assert (err == ETIMEDOUT);
+
+ gettimeofday (&after, 0);
+
+ printf ("End wait @ %d\n", (int) after.tv_sec);
+
+ diff = after.tv_sec * 1000000 + after.tv_usec
+ - before.tv_sec * 1000000 - before.tv_usec;
+
+ if (diff < 900000 || diff > 1100000)
+ error (1, EGRATUITOUS, "pthread_mutex_timedlock waited %d us", diff);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-15.c b/libpthread/tests/test-15.c
new file mode 100644
index 00000000..173f8b6b
--- /dev/null
+++ b/libpthread/tests/test-15.c
@@ -0,0 +1,87 @@
+/* Test pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#define THREADS 10
+
+pthread_rwlock_t rwlock;
+
+void *
+test (void *arg)
+{
+ error_t err;
+ int foo = (int) arg;
+ struct timespec ts;
+ struct timeval before, after;
+ int diff;
+
+ gettimeofday (&before, 0);
+ ts.tv_sec = before.tv_sec + 1;
+ ts.tv_nsec = before.tv_usec * 1000;
+
+ printf ("Thread %d starting wait @ %d\n", pthread_self (),
+ (int) before.tv_sec);
+
+ if (foo % 2 == 0)
+ err = pthread_rwlock_timedrdlock (&rwlock, &ts);
+ else
+ err = pthread_rwlock_timedwrlock (&rwlock, &ts);
+
+ assert (err == ETIMEDOUT);
+
+ gettimeofday (&after, 0);
+
+ printf ("Thread %d ending wait @ %d\n", pthread_self (),
+ (int) after.tv_sec);
+
+ diff = after.tv_sec * 1000000 + after.tv_usec
+ - before.tv_sec * 1000000 - before.tv_usec;
+
+ if (diff < 900000 || diff > 1100000)
+ error (1, EGRATUITOUS, "pthread_mutex_timedlock waited %d us", diff);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int i;
+ pthread_t tid[THREADS];
+
+ err = pthread_rwlock_init (&rwlock, 0);
+ if (err)
+ error (1, err, "pthread_rwlock_init");
+
+ /* Lock it so all the threads will block. */
+ err = pthread_rwlock_wrlock (&rwlock);
+ assert (err == 0);
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, test, (void *) i);
+ if (err)
+ error (1, err, "pthread_create");
+ }
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ void *ret;
+
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ assert (ret == 0);
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-16.c b/libpthread/tests/test-16.c
new file mode 100644
index 00000000..3660f5f7
--- /dev/null
+++ b/libpthread/tests/test-16.c
@@ -0,0 +1,71 @@
+/* Test pthread_kill.c. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <hurd/signal.h>
+
+pthread_t testthread;
+
+int i;
+
+void *
+test (void *arg)
+{
+ error_t err;
+
+ printf ("test: %d\n", pthread_self ());
+
+ err = pthread_kill (pthread_self (), SIGINFO);
+ if (err)
+ error (1, err, "pthread_kill");
+
+ /* To avoid using condition variables in a signal handler. */
+ while (i == 0)
+ sched_yield ();
+
+ return 0;
+}
+
+static void
+handler (int sig)
+{
+ assert (pthread_equal (pthread_self (), testthread));
+ printf ("handler: %d\n", pthread_self ());
+ i = 1;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct sigaction sa;
+ void *ret;
+
+ printf ("main: %d\n", pthread_self ());
+
+ sa.sa_handler = handler;
+ sa.sa_mask = 0;
+ sa.sa_flags = 0;
+
+ err = sigaction (SIGINFO, &sa, 0);
+ if (err)
+ error (1, err, "sigaction");
+
+ err = pthread_create (&testthread, 0, test, 0);
+ if (err)
+ error (1, err, "pthread_create");
+
+ err = pthread_join (testthread, &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ assert (ret == 0);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-2.c b/libpthread/tests/test-2.c
new file mode 100644
index 00000000..701462e8
--- /dev/null
+++ b/libpthread/tests/test-2.c
@@ -0,0 +1,39 @@
+/* Test detachability. */
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <unistd.h>
+
+void *
+thread (void *arg)
+{
+ while (1)
+ sched_yield ();
+}
+
+int
+main (int argc, char **argv)
+{
+ int err;
+ pthread_t tid;
+ void *ret;
+
+ err = pthread_create (&tid, 0, thread, 0);
+ if (err)
+ error (1, err, "pthread_create");
+
+ err = pthread_detach (tid);
+ if (err)
+ error (1, err, "pthread_detach");
+
+ err = pthread_detach (tid);
+ assert (err == EINVAL);
+
+ err = pthread_join (tid, &ret);
+ assert (err == EINVAL);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-3.c b/libpthread/tests/test-3.c
new file mode 100644
index 00000000..7db2e43f
--- /dev/null
+++ b/libpthread/tests/test-3.c
@@ -0,0 +1,55 @@
+/* Test the thread attribute get and set methods. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <sched.h>
+#include <assert.h>
+#include <errno.h>
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ pthread_attr_t attr;
+
+ int i;
+ struct sched_param sp;
+ void *p;
+ size_t sz;
+
+ err = pthread_attr_init (&attr);
+ assert_perror (err);
+
+ err = pthread_attr_destroy (&attr);
+ assert_perror (err);
+
+ err = pthread_attr_init (&attr);
+ assert_perror (err);
+
+#define TEST1(foo, rv, v) \
+ err = pthread_attr_get##foo (&attr, rv); \
+ assert_perror (err); \
+ \
+ err = pthread_attr_set##foo (&attr, v); \
+ assert_perror (err);
+
+#define TEST(foo, rv, v) TEST1(foo, rv, v)
+
+ TEST(inheritsched, &i, i);
+ TEST(schedparam, &sp, &sp);
+ TEST(schedpolicy, &i, i);
+ TEST(scope, &i, i);
+ TEST(stackaddr, &p, p);
+ TEST(detachstate, &i, i);
+ TEST(guardsize, &sz, sz);
+ TEST(stacksize, &sz, sz);
+
+ err = pthread_attr_getstack (&attr, &p, &sz);
+ assert_perror (err);
+
+ err = pthread_attr_setstack (&attr, p, sz);
+ assert_perror (err);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-4.c b/libpthread/tests/test-4.c
new file mode 100644
index 00000000..de9c8fe4
--- /dev/null
+++ b/libpthread/tests/test-4.c
@@ -0,0 +1,86 @@
+/* Test the stack guard. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+size_t stacksize;
+
+void *
+thr (void *arg)
+{
+ int i;
+ char *foo;
+
+ foo = alloca (3 * stacksize / 4);
+ for (i = 0; i < sizeof foo; i ++)
+ foo[i] = -1;
+
+ return (void *) 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ pid_t child;
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ error (1, errno, "fork");
+ break;
+
+ case 0:
+ {
+ pthread_attr_t attr;
+ pthread_t tid;
+ void *ret;
+
+ err = pthread_attr_init (&attr);
+ assert_perror (err);
+
+ err = pthread_attr_getstacksize (&attr, &stacksize);
+ assert_perror (err);
+
+ err = pthread_attr_setguardsize (&attr, stacksize / 2);
+ if (err == ENOTSUP)
+ {
+ printf ("Stack guard attribute not supported.\n");
+ return 1;
+ }
+ assert_perror (err);
+
+ err = pthread_create (&tid, &attr, thr, 0);
+ assert_perror (err);
+
+ err = pthread_attr_destroy (&attr);
+ assert_perror (err);
+
+ err = pthread_join (tid, &ret);
+ /* Should never be successful. */
+ printf ("Thread did not segfault!?!\n");
+ assert_perror (err);
+ return 0;
+ }
+
+ default:
+ {
+ pid_t pid;
+ int status;
+
+ pid = waitpid (child, &status, 0);
+ printf ("pid = %d; child = %d; status = %d\n", pid, child, status);
+ assert (pid == child);
+ assert (status != 0);
+ }
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-5.c b/libpthread/tests/test-5.c
new file mode 100644
index 00000000..0f5000b2
--- /dev/null
+++ b/libpthread/tests/test-5.c
@@ -0,0 +1,75 @@
+/* Test signals. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <assert.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+void *
+thr (void *arg)
+{
+ * (int *)0 = 0;
+ return 0;
+}
+
+int foobar;
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ pid_t child;
+
+ struct rlimit limit;
+
+ limit.rlim_cur = 0;
+ limit.rlim_max = 0;
+
+ err = setrlimit (RLIMIT_CORE, &limit);
+ if (err)
+ error (1, err, "setrlimit");
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ error (1, errno, "fork");
+ break;
+
+ case 0:
+ {
+ pthread_t tid;
+ void *ret;
+
+ err = pthread_create (&tid, 0, thr, 0);
+ if (err)
+ error (1, err, "pthread_create");
+
+ err = pthread_join (tid, &ret);
+ assert_perror (err);
+
+ /* Should have never returned. Our parent expects us to fail
+ thus we succeed and indicate the error. */
+ return 0;
+ }
+
+ default:
+ {
+ pid_t pid;
+ int status;
+
+ pid = waitpid (child, &status, 0);
+ printf ("pid = %d; child = %d; status = %d\n", pid, child, status);
+ assert (pid == child);
+ assert (status != 0);
+ }
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-6.c b/libpthread/tests/test-6.c
new file mode 100644
index 00000000..edf2919e
--- /dev/null
+++ b/libpthread/tests/test-6.c
@@ -0,0 +1,96 @@
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <error.h>
+#include <assert.h>
+#include <errno.h>
+
+#define THREADS 500
+#define WAITS 3
+
+void *
+dowait (void *arg)
+{
+ pthread_barrier_t *barrier = arg;
+ int ret;
+
+ ret = pthread_barrier_wait (barrier);
+ printf ("%d ", pthread_self ());
+ return (void *) ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ pthread_barrierattr_t attr;
+ pthread_barrier_t barrier;
+
+ int i, j;
+ error_t err;
+ pthread_t tid[THREADS];
+
+ int havesyncs;
+
+ err = pthread_barrierattr_init (&attr);
+ if (err)
+ error (1, err, "pthread_barrierattr_init");
+
+ err = pthread_barrierattr_getpshared (&attr, &i);
+ if (err)
+ error (1, err, "pthread_barrierattr_getpshared");
+ assert (i == PTHREAD_PROCESS_PRIVATE || i == PTHREAD_PROCESS_SHARED);
+
+ err = pthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_PRIVATE);
+ if (err)
+ error (1, err, "pthread_barrierattr_setpshared");
+
+ err = pthread_barrier_init (&barrier, &attr, THREADS + 1);
+ if (err)
+ error (1, err, "pthread_barrier_init");
+
+ for (j = 0; j < WAITS; j ++)
+ {
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, dowait, &barrier);
+ if (err)
+ error (1, err, "pthread_create (%d)", i);
+ }
+
+ printf ("Manager will now call pthread_barrier_wait.\n");
+
+ havesyncs
+ = pthread_barrier_wait (&barrier) == PTHREAD_BARRIER_SERIAL_THREAD
+ ? 1 : 0;
+
+ for (i = THREADS - 1; i >= 0; i --)
+ {
+ void *ret;
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ switch ((int) ret)
+ {
+ case 0:
+ break;
+
+ case PTHREAD_BARRIER_SERIAL_THREAD:
+ havesyncs ++;
+ break;
+
+ default:
+ assert (! "Unknown value returned from pthread_barrier_wait.");
+ break;
+ }
+ }
+
+ printf ("\n");
+
+ assert (havesyncs == 1);
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-7.c b/libpthread/tests/test-7.c
new file mode 100644
index 00000000..22fb1caa
--- /dev/null
+++ b/libpthread/tests/test-7.c
@@ -0,0 +1,70 @@
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+#include <error.h>
+#include <errno.h>
+
+#define THREADS 10
+#define KEYS 400
+
+pthread_key_t key[KEYS];
+
+void *
+thr (void *arg)
+{
+ error_t err;
+ int i;
+
+ for (i = 0; i < KEYS; i ++)
+ {
+ printf ("pthread_getspecific(%d).\n", key[i]);
+ assert (pthread_getspecific (key[i]) == NULL);
+ printf ("pthread_setspecific(%d, %d).\n", key[i], pthread_self ());
+ err = pthread_setspecific (key[i], (void *) pthread_self ());
+ printf ("pthread_setspecific(%d, %d) => %d.\n", key[i], pthread_self (), err);
+ assert_perror (err);
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int i;
+ pthread_t tid[THREADS];
+
+ void des (void *val)
+ {
+ assert ((pthread_t) val == pthread_self ());
+ }
+
+ assert (pthread_getspecific ((pthread_key_t) 0) == NULL);
+ assert (pthread_setspecific ((pthread_key_t) 0, (void *) 0x1) == EINVAL);
+
+ for (i = 0; i < KEYS; i ++)
+ err = pthread_key_create (&key[i], des);
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, thr, 0);
+ if (err)
+ error (1, err, "pthread_create (%d)", i);
+ }
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ void *ret;
+
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ assert (ret == 0);
+ }
+
+ return 0;
+}
diff --git a/libpthread/tests/test-8.c b/libpthread/tests/test-8.c
new file mode 100644
index 00000000..85a7f8f6
--- /dev/null
+++ b/libpthread/tests/test-8.c
@@ -0,0 +1,60 @@
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+
+#define THREADS 10
+
+pthread_once_t inc_var_once = PTHREAD_ONCE_INIT;
+int var;
+
+void
+inc_var (void)
+{
+ var ++;
+}
+
+void *
+thr (void *arg)
+{
+ int i;
+
+ for (i = 0; i < 500; i ++)
+ pthread_once (&inc_var_once, inc_var);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int i;
+ pthread_t tid[THREADS];
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, thr, 0);
+ if (err)
+ error (1, err, "pthread_create (%d)", i);
+ }
+
+ assert (thr (0) == 0);
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ void *ret;
+
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ assert (ret == 0);
+ }
+
+ assert (var == 1);
+
+ return 0;
+}
diff --git a/libpthread/tests/test-9.c b/libpthread/tests/test-9.c
new file mode 100644
index 00000000..82051570
--- /dev/null
+++ b/libpthread/tests/test-9.c
@@ -0,0 +1,88 @@
+/* Test recursive mutexes. */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+
+#define THREADS 10
+
+int foo;
+
+void *
+thr (void *arg)
+{
+ int i;
+
+ pthread_mutex_lock (arg);
+
+ foo = pthread_self ();
+
+ for (i = 0; i < 500; i ++)
+ pthread_mutex_lock (arg);
+ for (i = 0; i < 500; i ++)
+ pthread_mutex_unlock (arg);
+
+ assert (foo == pthread_self ());
+
+ pthread_mutex_unlock (arg);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int i;
+ pthread_t tid[THREADS];
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+
+ err = pthread_mutexattr_init (&mattr);
+ if (err)
+ error (1, err, "pthread_mutexattr_init");
+
+ err = pthread_mutexattr_settype (&mattr, PTHREAD_MUTEX_RECURSIVE);
+ if (err)
+ error (1, err, "pthread_mutexattr_settype");
+
+ err = pthread_mutex_init (&mutex, &mattr);
+ if (err)
+ error (1, err, "pthread_mutex_init");
+
+ err = pthread_mutexattr_destroy (&mattr);
+ if (err)
+ error (1, err, "pthread_mutexattr_destroy");
+
+ pthread_mutex_lock (&mutex);
+ pthread_mutex_lock (&mutex);
+ pthread_mutex_unlock (&mutex);
+ pthread_mutex_unlock (&mutex);
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ err = pthread_create (&tid[i], 0, thr, &mutex);
+ if (err)
+ error (1, err, "pthread_create (%d)", i);
+ }
+
+ for (i = 0; i < THREADS; i ++)
+ {
+ void *ret;
+
+ err = pthread_join (tid[i], &ret);
+ if (err)
+ error (1, err, "pthread_join");
+
+ assert (ret == 0);
+ }
+
+ err = pthread_mutex_destroy (&mutex);
+ if (err)
+ error (1, err, "pthread_mutex_destroy");
+
+ return 0;
+}
diff --git a/procfs/Makefile b/procfs/Makefile
new file mode 100644
index 00000000..a397522f
--- /dev/null
+++ b/procfs/Makefile
@@ -0,0 +1,26 @@
+TARGET = procfs
+OBJS = procfs.o netfs.o procfs_dir.o \
+ process.o proclist.o rootdir.o dircat.o main.o
+LIBS = -lnetfs -lps
+
+CC = gcc
+CFLAGS = -Wall -g
+CPPFLAGS =
+LDFLAGS =
+
+ifdef PROFILE
+CFLAGS= -g -pg
+CPPFLAGS= -DPROFILE
+LDFLAGS= -static
+LIBS= -lnetfs -lfshelp -liohelp -lps -lports -lthreads -lihash -lshouldbeinlibc
+endif
+
+CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
diff --git a/procfs/TODO b/procfs/TODO
new file mode 100644
index 00000000..952d67bc
--- /dev/null
+++ b/procfs/TODO
@@ -0,0 +1,24 @@
+Known bugs to be fixed
+----------------------
+
+* The non-owned processes sometimes show up with INT_MAX as their owner,
+ instead of opt_anon_uid. This is likely to be a libps problem.
+
+Improvements and new features
+-----------------------------
+
+* There is a lot of dynamic memory allocation going on and it comes with a
+ cost in performance. We could try to limit such allocation, as long as it
+ keeps the inner interface simple and preserves the read/readdir semantics
+ (performance is probably not critical for a proc filesystem.)
+ One way would be to add an (optional) "needed_length" field to
+ procfs_node_ops, and arrange to pass a sufficent buffer in (*contents,
+ *contents_len) when get_contents is called. Then the user-provided buffer
+ might be used directly under some circumstances.
+
+* Add thread directories as [pid]/task/[n]. This shouldn't be too hard if we
+ use "process" nodes for threads, and provide an "exists" hook for the "task"
+ entry itself so that it's disabled in thread nodes. It might prove necessary
+ to have "optional" libps flags for some content generators, though, since
+ some of them might be missing for threads.
+
diff --git a/procfs/dircat.c b/procfs/dircat.c
new file mode 100644
index 00000000..5a60899a
--- /dev/null
+++ b/procfs/dircat.c
@@ -0,0 +1,128 @@
+/* Hurd /proc filesystem, concatenation of two directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "procfs.h"
+
+struct dircat_node
+{
+ int num_dirs;
+ struct node *dirs[0];
+};
+
+static error_t
+dircat_get_contents (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct dircat_node *dcn = hook;
+ int i, sz, pos;
+ error_t err;
+
+ pos = 0;
+ *contents = malloc (sz = 512);
+
+ for (i=0; i < dcn->num_dirs; i++)
+ {
+ char *subcon;
+ ssize_t sublen;
+
+ /* Make sure we're not getting some old stuff. */
+ procfs_refresh (dcn->dirs[i]);
+
+ err = procfs_get_contents (dcn->dirs[i], &subcon, &sublen);
+ if (err)
+ {
+ free (*contents);
+ *contents = NULL;
+ return err;
+ }
+
+ while (pos + sublen > sz)
+ *contents = realloc (*contents, sz *= 2);
+
+ memcpy (*contents + pos, subcon, sublen);
+ pos += sublen;
+ }
+
+ *contents_len = pos;
+ return 0;
+}
+
+static error_t
+dircat_lookup (void *hook, const char *name, struct node **np)
+{
+ struct dircat_node *dcn = hook;
+ error_t err;
+ int i;
+
+ err = ENOENT;
+ for (i=0; err && i < dcn->num_dirs; i++)
+ err = procfs_lookup (dcn->dirs[i], name, np);
+
+ return err;
+}
+
+static void
+dircat_release_dirs (struct node *const *dirs, int num_dirs)
+{
+ int i;
+
+ for (i=0; i < num_dirs; i++)
+ if (dirs[i])
+ netfs_nrele (dirs[i]);
+}
+
+static void
+dircat_cleanup (void *hook)
+{
+ struct dircat_node *dcn = hook;
+
+ dircat_release_dirs (dcn->dirs, dcn->num_dirs);
+ free (dcn);
+}
+
+struct node *
+dircat_make_node (struct node *const *dirs, int num_dirs)
+{
+ static struct procfs_node_ops ops = {
+ .get_contents = dircat_get_contents,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ .lookup = dircat_lookup,
+ .cleanup = dircat_cleanup,
+ };
+ struct dircat_node *dcn;
+ int i;
+
+ for (i=0; i < num_dirs; i++)
+ if (! dirs[i])
+ goto fail;
+
+ dcn = malloc (sizeof *dcn + num_dirs * sizeof dcn->dirs[0]);
+ if (! dcn)
+ goto fail;
+
+ dcn->num_dirs = num_dirs;
+ memcpy (dcn->dirs, dirs, num_dirs * sizeof dcn->dirs[0]);
+ return procfs_make_node (&ops, dcn);
+
+fail:
+ dircat_release_dirs (dirs, num_dirs);
+ return NULL;
+}
+
diff --git a/procfs/dircat.h b/procfs/dircat.h
new file mode 100644
index 00000000..4177b384
--- /dev/null
+++ b/procfs/dircat.h
@@ -0,0 +1,29 @@
+/* Hurd /proc filesystem, concatenation of two directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Append the contents of NUM_DIRS directories. DIRS is an array of
+ directory nodes. One reference is consumed for each of them. If a
+ memory allocation error occurs, or if one of the directories is a
+ NULL pointer, the references are dropped immediately and NULL is
+ returned. The given DIRS array is duplicated and can therefore be
+ allocated on the caller's stack. Strange things will happen if some
+ elements of DIRS have entries with the same name or if one of them is
+ not a directory. */
+struct node *
+dircat_make_node (struct node *const *dirs, int num_dirs);
diff --git a/procfs/main.c b/procfs/main.c
new file mode 100644
index 00000000..3a976ccc
--- /dev/null
+++ b/procfs/main.c
@@ -0,0 +1,190 @@
+/* Hurd /proc filesystem, main program.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <hurd.h>
+#include <unistd.h>
+#include <error.h>
+#include <argp.h>
+#include <hurd/netfs.h>
+#include <ps.h>
+#include "procfs.h"
+#include "proclist.h"
+#include "rootdir.h"
+#include "dircat.h"
+#include "main.h"
+
+/* Command-line options */
+int opt_clk_tck;
+mode_t opt_stat_mode;
+pid_t opt_fake_self;
+pid_t opt_kernel_pid;
+uid_t opt_anon_owner;
+
+static error_t
+argp_parser (int key, char *arg, struct argp_state *state)
+{
+ struct passwd *pw;
+ char *endp;
+
+ switch (key)
+ {
+ case 'h':
+ opt_clk_tck = strtol (arg, &endp, 0);
+ if (*endp || ! *arg || opt_clk_tck <= 0)
+ error (1, 0, "--clk-tck: HZ should be a positive integer");
+ break;
+
+ case 's':
+ opt_stat_mode = strtol (arg, &endp, 8);
+ if (*endp || ! *arg || opt_stat_mode & ~07777)
+ error (1, 0, "--stat-mode: MODE should be an octal mode");
+ break;
+
+ case 'S':
+ if (arg)
+ {
+ opt_fake_self = strtol (arg, &endp, 0);
+ if (*endp || ! *arg)
+ error (1, 0, "--fake-self: PID must be an integer");
+ }
+ else
+ opt_fake_self = 1;
+ break;
+
+ case 'k':
+ opt_kernel_pid = strtol (arg, &endp, 0);
+ if (*endp || ! *arg || (signed) opt_kernel_pid < 0)
+ error (1, 0, "--kernel-process: PID must be a positive integer");
+ break;
+
+ case 'c':
+ opt_clk_tck = 100;
+ opt_stat_mode = 0444;
+ opt_fake_self = 1;
+ break;
+
+ case 'a':
+ pw = getpwnam (arg);
+ if (pw)
+ {
+ opt_anon_owner = pw->pw_uid;
+ break;
+ }
+
+ opt_anon_owner = strtol (arg, &endp, 0);
+ if (*endp || ! *arg || (signed) opt_anon_owner < 0)
+ error(1, 0, "--anonymous-owner: USER should be the a user name "
+ "or a numeric UID.");
+ break;
+ }
+
+ return 0;
+}
+
+struct argp argp = {
+ .options = (struct argp_option []) {
+ { "clk-tck", 'h', "HZ", 0,
+ "Unit used for the values expressed in system clock ticks "
+ "(default: sysconf(_SC_CLK_TCK))" },
+ { "stat-mode", 's', "MODE", 0,
+ "The [pid]/stat file publishes information which on Hurd is only "
+ "available to the process owner. "
+ "You can use this option to override its mode to be more permissive "
+ "for compatibility purposes. "
+ "(default: 0400)" },
+ { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL,
+ "Provide a fake \"self\" symlink to the given PID, for compatibility "
+ "purposes. If PID is omitted, \"self\" will point to init. "
+ "(default: no self link)" },
+ { "kernel-process", 'k', "PID", 0,
+ "Process identifier for the kernel, used to retreive its command "
+ "line, as well as the global up and idle times. "
+ "(default: 2)" },
+ { "compatible", 'c', NULL, 0,
+ "Try to be compatible with the Linux procps utilities. "
+ "Currently equivalent to -h 100 -s 0444 -S 1." },
+ { "anonymous-owner", 'a', "USER", 0,
+ "Make USER the owner of files related to processes without one. "
+ "Be aware that USER will be granted access to the environment and "
+ "other sensitive information about the processes in question. "
+ "(default: use uid 0)" },
+ {}
+ },
+ .parser = argp_parser,
+ .doc = "A virtual filesystem emulating the Linux procfs.",
+ .children = (struct argp_child []) {
+ { &netfs_std_startup_argp, },
+ {}
+ },
+};
+
+error_t
+root_make_node (struct ps_context *pc, struct node **np)
+{
+ struct node *root_dirs[] = {
+ proclist_make_node (pc),
+ rootdir_make_node (pc),
+ };
+
+ *np = dircat_make_node (root_dirs, sizeof root_dirs / sizeof root_dirs[0]);
+ if (! *np)
+ return ENOMEM;
+
+ /* Since this one is not created through proc_lookup(), we have to affect an
+ inode number to it. */
+ (*np)->nn_stat.st_ino = * (uint32_t *) "PROC";
+
+ return 0;
+}
+
+int main (int argc, char **argv)
+{
+ struct ps_context *pc;
+ mach_port_t bootstrap;
+ error_t err;
+
+ opt_clk_tck = sysconf(_SC_CLK_TCK);
+ opt_stat_mode = 0400;
+ opt_fake_self = -1;
+ opt_kernel_pid = 2;
+ opt_anon_owner = 0;
+ err = argp_parse (&argp, argc, argv, 0, 0, 0);
+ if (err)
+ error (1, err, "Could not parse command line");
+
+ err = ps_context_create (getproc (), &pc);
+ if (err)
+ error (1, err, "Could not create libps context");
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ netfs_init ();
+ err = root_make_node (pc, &netfs_root_node);
+ if (err)
+ error (1, err, "Could not create the root node");
+
+ netfs_startup (bootstrap, 0);
+ netfs_server_loop ();
+
+ assert (0 /* netfs_server_loop returned after all */);
+}
+
diff --git a/procfs/main.h b/procfs/main.h
new file mode 100644
index 00000000..4e28b7eb
--- /dev/null
+++ b/procfs/main.h
@@ -0,0 +1,25 @@
+/* Hurd /proc filesystem, command-line options set by main.c.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Startup options */
+extern int opt_clk_tck;
+extern mode_t opt_stat_mode;
+extern pid_t opt_fake_self;
+extern pid_t opt_kernel_pid;
+extern uid_t opt_anon_owner;
diff --git a/procfs/netfs.c b/procfs/netfs.c
new file mode 100644
index 00000000..24a6603f
--- /dev/null
+++ b/procfs/netfs.c
@@ -0,0 +1,445 @@
+/* Hurd /proc filesystem, interface with libnetfs.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/netfs.h>
+#include <hurd/fshelp.h>
+#include <sys/mman.h>
+#include <mach/vm_param.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include "procfs.h"
+
+#define PROCFS_SERVER_NAME "procfs"
+#define PROCFS_SERVER_VERSION "0.1.0"
+#define PROCFS_MAXSYMLINKS 16
+
+
+/* Interesting libnetfs callback functions. */
+
+/* The user must define this variable. Set this to the name of the
+ filesystem server. */
+char *netfs_server_name = PROCFS_SERVER_NAME;
+
+/* The user must define this variables. Set this to be the server
+ version number. */
+char *netfs_server_version = PROCFS_SERVER_VERSION;
+
+/* Maximum number of symlinks to follow before returning ELOOP. */
+int netfs_maxsymlinks = PROCFS_MAXSYMLINKS;
+
+/* The user must define this function. Make sure that NP->nn_stat is
+ filled with the most current information. CRED identifies the user
+ responsible for the operation. NP is locked. */
+error_t netfs_validate_stat (struct node *np, struct iouser *cred)
+{
+ char *contents;
+ ssize_t contents_len;
+ error_t err;
+
+ /* Only symlinks need to have their size filled, before a read is
+ attempted. */
+ if (! S_ISLNK (np->nn_stat.st_mode))
+ return 0;
+
+ err = procfs_get_contents (np, &contents, &contents_len);
+ if (err)
+ return err;
+
+ np->nn_stat.st_size = contents_len;
+ return 0;
+}
+
+/* The user must define this function. Read from the locked file NP
+ for user CRED starting at OFFSET and continuing for up to *LEN
+ bytes. Put the data at DATA. Set *LEN to the amount successfully
+ read upon return. */
+error_t netfs_attempt_read (struct iouser *cred, struct node *np,
+ loff_t offset, size_t *len, void *data)
+{
+ char *contents;
+ ssize_t contents_len;
+ error_t err;
+
+ if (offset == 0)
+ procfs_refresh (np);
+
+ err = procfs_get_contents (np, &contents, &contents_len);
+ if (err)
+ return err;
+
+ contents += offset;
+ contents_len -= offset;
+
+ if (*len > contents_len)
+ *len = contents_len;
+ if (*len < 0)
+ *len = 0;
+
+ memcpy (data, contents, *len);
+ return 0;
+}
+
+/* The user must define this function. Read the contents of locked
+ node NP (a symlink), for USER, into BUF. */
+error_t netfs_attempt_readlink (struct iouser *user, struct node *np,
+ char *buf)
+{
+ char *contents;
+ ssize_t contents_len;
+ error_t err;
+
+ err = procfs_get_contents (np, &contents, &contents_len);
+ if (err)
+ return err;
+
+ assert (contents_len == np->nn_stat.st_size);
+ memcpy (buf, contents, contents_len);
+ return 0;
+}
+
+/* Helper function for netfs_get_dirents() below. CONTENTS is an argz
+ vector of directory entry names, as returned by procfs_get_contents().
+ Convert at most NENTRIES of them to dirent structures, put them in
+ DATA (if not NULL), write the number of entries processed in *AMT and
+ return the required/used space in DATACNT. */
+static int putentries (char *contents, size_t contents_len, int nentries,
+ char *data, mach_msg_type_number_t *datacnt)
+{
+ int i;
+
+ *datacnt = 0;
+ for (i = 0; contents_len && (nentries < 0 || i < nentries); i++)
+ {
+ int namlen = strlen (contents);
+ int reclen = sizeof (struct dirent) + namlen;
+
+ if (data)
+ {
+ struct dirent *d = (struct dirent *) (data + *datacnt);
+ d->d_fileno = 42; /* XXX */
+ d->d_namlen = namlen;
+ d->d_reclen = reclen;
+ d->d_type = DT_UNKNOWN;
+ strcpy (d->d_name, contents);
+ }
+
+ *datacnt += reclen;
+ contents += namlen + 1;
+ contents_len -= namlen + 1;
+ }
+
+ return i;
+}
+
+/* The user must define this function. Fill the array *DATA of size
+ BUFSIZE with up to NENTRIES dirents from DIR (which is locked)
+ starting with entry ENTRY for user CRED. The number of entries in
+ the array is stored in *AMT and the number of bytes in *DATACNT.
+ If the supplied buffer is not large enough to hold the data, it
+ should be grown. */
+error_t netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int entry, int nentries, char **data,
+ mach_msg_type_number_t *datacnt,
+ vm_size_t bufsize, int *amt)
+{
+ char *contents;
+ ssize_t contents_len;
+ error_t err;
+
+ if (entry == 0)
+ procfs_refresh (dir);
+
+ err = procfs_get_contents (dir, &contents, &contents_len);
+ if (err)
+ return err;
+
+ /* We depend on the fact that CONTENTS is terminated. */
+ assert (contents_len == 0 || contents[contents_len - 1] == '\0');
+
+ /* Skip to the first requested entry. */
+ while (contents_len && entry--)
+ {
+ int ofs = strlen (contents) + 1;
+ contents += ofs;
+ contents_len -= ofs;
+ }
+
+ /* Allocate a buffer if necessary. */
+ putentries (contents, contents_len, nentries, NULL, datacnt);
+ if (bufsize < *datacnt)
+ {
+ char *n = mmap (0, *datacnt, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, 0, 0);
+ if (n == MAP_FAILED)
+ return ENOMEM;
+
+ *data = n;
+ }
+
+ /* Do the actual conversion. */
+ *amt = putentries (contents, contents_len, nentries, *data, datacnt);
+
+ return 0;
+}
+
+/* The user must define this function. Lookup NAME in DIR (which is
+ locked) for USER; set *NP to the found name upon return. If the
+ name was not found, then return ENOENT. On any error, clear *NP.
+ (*NP, if found, should be locked and a reference to it generated.
+ This call should unlock DIR no matter what.) */
+error_t netfs_attempt_lookup (struct iouser *user, struct node *dir,
+ char *name, struct node **np)
+{
+ error_t err;
+
+ err = procfs_lookup (dir, name, np);
+ mutex_unlock (&dir->lock);
+
+ if (! err)
+ mutex_lock (&(*np)->lock);
+
+ return err;
+}
+
+/* The user must define this function. Node NP has no more references;
+ free all its associated storage. */
+void netfs_node_norefs (struct node *np)
+{
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ procfs_cleanup (np);
+ free (np);
+
+ spin_lock (&netfs_node_refcnt_lock);
+}
+
+
+/* Libnetfs callbacks managed with libfshelp. */
+
+/* The user must define this function. Locked node NP is being opened
+ by USER, with FLAGS. NEWNODE is nonzero if we just created this
+ node. Return an error if we should not permit the open to complete
+ because of a permission restriction. */
+error_t netfs_check_open_permissions (struct iouser *user, struct node *np,
+ int flags, int newnode)
+{
+ error_t err = 0;
+ if (!err && (flags & O_READ))
+ err = fshelp_access (&np->nn_stat, S_IREAD, user);
+ if (!err && (flags & O_WRITE))
+ err = fshelp_access (&np->nn_stat, S_IWRITE, user);
+ if (!err && (flags & O_EXEC))
+ err = fshelp_access (&np->nn_stat, S_IEXEC, user);
+ return err;
+}
+
+/* The user must define this function. Return the valid access
+ types (bitwise OR of O_READ, O_WRITE, and O_EXEC) in *TYPES for
+ locked file NP and user CRED. */
+error_t netfs_report_access (struct iouser *cred, struct node *np,
+ int *types)
+{
+ *types = 0;
+ if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0)
+ *types |= O_READ;
+ if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0)
+ *types |= O_WRITE;
+ if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
+ *types |= O_EXEC;
+ return 0;
+}
+
+
+/* Trivial or unsupported libnetfs callbacks. */
+
+/* The user must define this function. This should attempt a chmod
+ call for the user specified by CRED on locked node NP, to change
+ the owner to UID and the group to GID. */
+error_t netfs_attempt_chown (struct iouser *cred, struct node *np,
+ uid_t uid, uid_t gid)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt a chauthor
+ call for the user specified by CRED on locked node NP, thereby
+ changing the author to AUTHOR. */
+error_t netfs_attempt_chauthor (struct iouser *cred, struct node *np,
+ uid_t author)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt a chmod
+ call for the user specified by CRED on locked node NODE, to change
+ the mode to MODE. Unlike the normal Unix and Hurd meaning of
+ chmod, this function is also used to attempt to change files into
+ other types. If such a transition is attempted which is
+ impossible, then return EOPNOTSUPP. */
+error_t netfs_attempt_chmod (struct iouser *cred, struct node *np,
+ mode_t mode)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to turn locked node NP
+ (user CRED) into a symlink with target NAME. */
+error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *np,
+ char *name)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to turn NODE (user
+ CRED) into a device. TYPE is either S_IFBLK or S_IFCHR. NP is
+ locked. */
+error_t netfs_attempt_mkdev (struct iouser *cred, struct node *np,
+ mode_t type, dev_t indexes)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt a chflags
+ call for the user specified by CRED on locked node NP, to change
+ the flags to FLAGS. */
+error_t netfs_attempt_chflags (struct iouser *cred, struct node *np,
+ int flags)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt a utimes
+ call for the user specified by CRED on locked node NP, to change
+ the atime to ATIME and the mtime to MTIME. If ATIME or MTIME is
+ null, then set to the current time. */
+error_t netfs_attempt_utimes (struct iouser *cred, struct node *np,
+ struct timespec *atime, struct timespec *mtime)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt to set the
+ size of the locked file NP (for user CRED) to SIZE bytes long. */
+error_t netfs_attempt_set_size (struct iouser *cred, struct node *np,
+ loff_t size)
+{
+ return EROFS;
+}
+
+/* The user must define this function. This should attempt to fetch
+ filesystem status information for the remote filesystem, for the
+ user CRED. NP is locked. */
+error_t netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ fsys_statfsbuf_t *st)
+{
+ return ENOSYS;
+}
+
+/* The user must define this function. This should sync the locked
+ file NP completely to disk, for the user CRED. If WAIT is set,
+ return only after the sync is completely finished. */
+error_t netfs_attempt_sync (struct iouser *cred, struct node *np,
+ int wait)
+{
+ return 0;
+}
+
+/* The user must define this function. This should sync the entire
+ remote filesystem. If WAIT is set, return only after the sync is
+ completely finished. */
+error_t netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+ return 0;
+}
+
+/* The user must define this function. Delete NAME in DIR (which is
+ locked) for USER. */
+error_t netfs_attempt_unlink (struct iouser *user, struct node *dir,
+ char *name)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to rename the
+ directory FROMDIR to TODIR. Note that neither of the specific nodes
+ are locked. */
+error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+ char *fromname, struct node *todir,
+ char *toname, int excl)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to create a new
+ directory named NAME in DIR (which is locked) for USER with mode
+ MODE. */
+error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+ char *name, mode_t mode)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to remove directory
+ named NAME in DIR (which is locked) for USER. */
+error_t netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return EROFS;
+}
+
+
+/* The user must define this function. Create a link in DIR with name
+ NAME to FILE for USER. Note that neither DIR nor FILE are
+ locked. If EXCL is set, do not delete the target. Return EEXIST if
+ NAME is already found in DIR. */
+error_t netfs_attempt_link (struct iouser *user, struct node *dir,
+ struct node *file, char *name, int excl)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to create an anonymous
+ file related to DIR (which is locked) for USER with MODE. Set *NP
+ to the returned file upon success. No matter what, unlock DIR. */
+error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir,
+ mode_t mode, struct node **np)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Attempt to create a file named
+ NAME in DIR (which is locked) for USER with MODE. Set *NP to the
+ new node upon return. On any error, clear *NP. *NP should be
+ locked on success; no matter what, unlock DIR before returning. */
+error_t netfs_attempt_create_file (struct iouser *user, struct node *dir,
+ char *name, mode_t mode, struct node **np)
+{
+ return EROFS;
+}
+
+/* The user must define this function. Write to the locked file NP
+ for user CRED starting at OFSET and continuing for up to *LEN bytes
+ from DATA. Set *LEN to the amount successfully written upon
+ return. */
+error_t netfs_attempt_write (struct iouser *cred, struct node *np,
+ loff_t offset, size_t *len, void *data)
+{
+ return EROFS;
+}
+
+
diff --git a/procfs/process.c b/procfs/process.c
new file mode 100644
index 00000000..6652a4e9
--- /dev/null
+++ b/procfs/process.c
@@ -0,0 +1,387 @@
+/* Hurd /proc filesystem, implementation of process directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <hurd/process.h>
+#include <hurd/resource.h>
+#include <mach/vm_param.h>
+#include <ps.h>
+#include "procfs.h"
+#include "procfs_dir.h"
+#include "process.h"
+#include "main.h"
+
+/* This module implements the process directories and the files they
+ contain. A libps proc_stat structure is created for each process
+ node, and is used by the individual file content generators as a
+ source of information. Each possible file (cmdline, environ, ...) is
+ decribed in a process_file_desc structure, which specifies which bits
+ of information (ie. libps flags) it needs, and what function should
+ be used to generate the file's contents.
+
+ The content generators are defined first, followed by glue logic and
+ entry table. */
+
+
+/* Helper functions */
+
+static char state_char (struct proc_stat *ps)
+{
+ int i;
+
+ for (i = 0; (1 << i) & (PSTAT_STATE_P_STATES | PSTAT_STATE_T_STATES); i++)
+ if (proc_stat_state (ps) & (1 << i))
+ return proc_stat_state_tags[i];
+
+ return '?';
+}
+
+static const char *state_string (struct proc_stat *ps)
+{
+ static const char *const state_strings[] = {
+ "T (stopped)",
+ "Z (zombie)",
+ "R (running)",
+ "H (halted)",
+ "D (disk sleep)",
+ "S (sleeping)",
+ "I (idle)",
+ NULL
+ };
+ int i;
+
+ for (i = 0; state_strings[i]; i++)
+ if (proc_stat_state (ps) & (1 << i))
+ return state_strings[i];
+
+ return "? (unknown)";
+}
+
+static long long int timeval_jiffies (time_value_t tv)
+{
+ double secs = tv.seconds * 1000000. + tv.microseconds;
+ return secs * opt_clk_tck / 1000000.;
+}
+
+/* Actual content generators */
+
+static ssize_t
+process_file_gc_cmdline (struct proc_stat *ps, char **contents)
+{
+ *contents = proc_stat_args(ps);
+ return proc_stat_args_len(ps);
+}
+
+static ssize_t
+process_file_gc_environ (struct proc_stat *ps, char **contents)
+{
+ *contents = proc_stat_env(ps);
+ return proc_stat_env_len(ps);
+}
+
+static ssize_t
+process_file_gc_stat (struct proc_stat *ps, char **contents)
+{
+ struct procinfo *pi = proc_stat_proc_info (ps);
+ task_basic_info_t tbi = proc_stat_task_basic_info (ps);
+ thread_basic_info_t thbi = proc_stat_thread_basic_info (ps);
+
+ /* See proc(5) for more information about the contents of each field for the
+ Linux procfs. */
+ return asprintf (contents,
+ "%d (%s) %c " /* pid, command, state */
+ "%d %d %d " /* ppid, pgid, session */
+ "%d %d " /* controling tty stuff */
+ "%u " /* flags, as defined by <linux/sched.h> */
+ "%lu %lu %lu %lu " /* page fault counts */
+ "%lu %lu %ld %ld " /* user/sys times, in sysconf(_SC_CLK_TCK) */
+ "%d %d " /* scheduler params (priority, nice) */
+ "%d %ld " /* number of threads, [obsolete] */
+ "%llu " /* start time since boot (jiffies) */
+ "%lu %ld %lu " /* virtual size (bytes), rss (pages), rss lim */
+ "%lu %lu %lu %lu %lu " /* some vm addresses (code, stack, sp, pc) */
+ "%lu %lu %lu %lu " /* pending, blocked, ignored and caught sigs */
+ "%lu " /* wait channel */
+ "%lu %lu " /* swap usage (not maintained in Linux) */
+ "%d " /* exit signal, to be sent to the parent */
+ "%d " /* last processor used */
+ "%u %u " /* RT priority and policy */
+ "%llu " /* aggregated block I/O delay */
+ "\n",
+ proc_stat_pid (ps), proc_stat_args (ps), state_char (ps),
+ pi->ppid, pi->pgrp, pi->session,
+ 0, 0, /* no such thing as a major:minor for ctty */
+ 0, /* no such thing as CLONE_* flags on Hurd */
+ 0L, 0L, 0L, 0L, /* TASK_EVENTS_INFO is unavailable on GNU Mach */
+ (long unsigned) timeval_jiffies (thbi->user_time),
+ (long unsigned) timeval_jiffies (thbi->system_time),
+ 0L, 0L, /* cumulative time for children */
+ MACH_PRIORITY_TO_NICE(thbi->base_priority) + 20,
+ MACH_PRIORITY_TO_NICE(thbi->base_priority),
+ pi->nthreads, 0L,
+ timeval_jiffies (thbi->creation_time), /* FIXME: ... since boot */
+ (long unsigned) tbi->virtual_size,
+ (long unsigned) tbi->resident_size / PAGE_SIZE, 0L,
+ 0L, 0L, 0L, 0L, 0L,
+ 0L, 0L, 0L, 0L,
+ (long unsigned) proc_stat_thread_rpc (ps), /* close enough */
+ 0L, 0L,
+ 0,
+ 0,
+ 0, 0,
+ 0LL);
+}
+
+static ssize_t
+process_file_gc_statm (struct proc_stat *ps, char **contents)
+{
+ task_basic_info_t tbi = proc_stat_task_basic_info (ps);
+
+ return asprintf (contents,
+ "%lu %lu 0 0 0 0 0\n",
+ tbi->virtual_size / sysconf(_SC_PAGE_SIZE),
+ tbi->resident_size / sysconf(_SC_PAGE_SIZE));
+}
+
+static ssize_t
+process_file_gc_status (struct proc_stat *ps, char **contents)
+{
+ task_basic_info_t tbi = proc_stat_task_basic_info (ps);
+
+ return asprintf (contents,
+ "Name:\t%s\n"
+ "State:\t%s\n"
+ "Tgid:\t%u\n"
+ "Pid:\t%u\n"
+ "PPid:\t%u\n"
+ "Uid:\t%u\t%u\t%u\t%u\n"
+ "VmSize:\t%8u kB\n"
+ "VmPeak:\t%8u kB\n"
+ "VmRSS:\t%8u kB\n"
+ "VmHWM:\t%8u kB\n" /* ie. resident peak */
+ "Threads:\t%u\n",
+ proc_stat_args (ps),
+ state_string (ps),
+ proc_stat_pid (ps), /* XXX will need more work for threads */
+ proc_stat_pid (ps),
+ proc_stat_proc_info (ps)->ppid,
+ proc_stat_owner_uid (ps),
+ proc_stat_owner_uid (ps),
+ proc_stat_owner_uid (ps),
+ proc_stat_owner_uid (ps),
+ tbi->virtual_size / 1024,
+ tbi->virtual_size / 1024,
+ tbi->resident_size / 1024,
+ tbi->resident_size / 1024,
+ proc_stat_num_threads (ps));
+}
+
+
+/* Implementation of the file nodes. */
+
+/* Describes a file in the process directories. This structure is
+ filled in as an "entry hook" in our procfs_dir entry table and is
+ passed to the process_file_make_node function defined below. */
+struct process_file_desc
+{
+ /* The proc_stat information required to get the contents of this file. */
+ ps_flags_t needs;
+
+ /* Content generator to use for this file. Once we have acquired the
+ necessary information, there can be only memory allocation errors,
+ hence this simplified signature. */
+ ssize_t (*get_contents) (struct proc_stat *ps, char **contents);
+
+ /* The cmdline and environ contents don't need any cleaning since they
+ point directly into the proc_stat structure. */
+ int no_cleanup;
+
+ /* If specified, the file mode to be set with procfs_node_chmod(). */
+ mode_t mode;
+};
+
+struct process_file_node
+{
+ const struct process_file_desc *desc;
+ struct proc_stat *ps;
+};
+
+/* FIXME: lock the parent! */
+static error_t
+process_file_get_contents (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct process_file_node *file = hook;
+ error_t err;
+
+ /* Fetch the required information. */
+ err = proc_stat_set_flags (file->ps, file->desc->needs);
+ if (err)
+ return EIO;
+ if ((proc_stat_flags (file->ps) & file->desc->needs) != file->desc->needs)
+ return EIO;
+
+ /* Call the actual content generator (see the definitions below). */
+ *contents_len = file->desc->get_contents (file->ps, contents);
+ return 0;
+}
+
+static void
+process_file_cleanup_contents (void *hook, char *contents, ssize_t len)
+{
+ struct process_file_node *file = hook;
+
+ if (! file->desc->no_cleanup)
+ free (contents);
+}
+
+static struct node *
+process_file_make_node (void *dir_hook, const void *entry_hook)
+{
+ static const struct procfs_node_ops ops = {
+ .get_contents = process_file_get_contents,
+ .cleanup_contents = process_file_cleanup_contents,
+ .cleanup = free,
+ };
+ struct process_file_node *f;
+ struct node *np;
+
+ f = malloc (sizeof *f);
+ if (! f)
+ return NULL;
+
+ f->desc = entry_hook;
+ f->ps = dir_hook;
+
+ np = procfs_make_node (&ops, f);
+ if (! np)
+ return NULL;
+
+ procfs_node_chown (np, proc_stat_owner_uid (f->ps));
+ if (f->desc->mode)
+ procfs_node_chmod (np, f->desc->mode);
+
+ return np;
+}
+
+/* Stat needs its own constructor in oreder to set its mode according to
+ the --stat-mode command-line option. */
+static struct node *
+process_stat_make_node (void *dir_hook, const void *entry_hook)
+{
+ struct node *np = process_file_make_node (dir_hook, entry_hook);
+ if (np) procfs_node_chmod (np, opt_stat_mode);
+ return np;
+}
+
+
+/* Implementation of the process directory per se. */
+
+static struct procfs_dir_entry entries[] = {
+ {
+ .name = "cmdline",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_cmdline,
+ .needs = PSTAT_ARGS,
+ .no_cleanup = 1,
+ },
+ },
+ {
+ .name = "environ",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_environ,
+ .needs = PSTAT_ENV,
+ .no_cleanup = 1,
+ .mode = 0400,
+ },
+ },
+ {
+ .name = "stat",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_stat,
+ .needs = PSTAT_PID | PSTAT_ARGS | PSTAT_STATE | PSTAT_PROC_INFO
+ | PSTAT_TASK | PSTAT_TASK_BASIC | PSTAT_THREAD_BASIC
+ | PSTAT_THREAD_WAIT,
+ },
+ .ops = {
+ .make_node = process_stat_make_node,
+ }
+ },
+ {
+ .name = "statm",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_statm,
+ .needs = PSTAT_TASK_BASIC,
+ },
+ },
+ {
+ .name = "status",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_status,
+ .needs = PSTAT_PID | PSTAT_ARGS | PSTAT_STATE | PSTAT_PROC_INFO
+ | PSTAT_TASK_BASIC | PSTAT_OWNER_UID | PSTAT_NUM_THREADS,
+ },
+ },
+ {}
+};
+
+error_t
+process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np)
+{
+ static const struct procfs_dir_ops dir_ops = {
+ .entries = entries,
+ .cleanup = (void (*)(void *)) _proc_stat_free,
+ .entry_ops = {
+ .make_node = process_file_make_node,
+ },
+ };
+ struct proc_stat *ps;
+ int owner;
+ error_t err;
+
+ err = _proc_stat_create (pid, pc, &ps);
+ if (err == ESRCH)
+ return ENOENT;
+ if (err)
+ return EIO;
+
+ err = proc_stat_set_flags (ps, PSTAT_OWNER_UID);
+ if (err || ! (proc_stat_flags (ps) & PSTAT_OWNER_UID))
+ {
+ _proc_stat_free (ps);
+ return EIO;
+ }
+
+ /* FIXME: have a separate proc_desc structure for each file, so this can be
+ accessed in a more robust and straightforward way. */
+ ((struct process_file_desc *) entries[2].hook)->mode = opt_stat_mode;
+
+ /* FIXME: have a separate proc_desc structure for each file, so this can be
+ accessed in a more robust and straightforward way. */
+ ((struct process_file_desc *) entries[2].hook)->mode = opt_stat_mode;
+
+ *np = procfs_dir_make_node (&dir_ops, ps);
+ if (! *np)
+ return ENOMEM;
+
+ owner = proc_stat_owner_uid (ps);
+ procfs_node_chown (*np, owner >= 0 ? owner : opt_anon_owner);
+ return 0;
+}
diff --git a/procfs/process.h b/procfs/process.h
new file mode 100644
index 00000000..b230a281
--- /dev/null
+++ b/procfs/process.h
@@ -0,0 +1,27 @@
+/* Hurd /proc filesystem, implementation of process directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ps.h>
+
+/* Create a node for a directory representing the given PID, as published by
+ the proc server refrenced by the libps context PC. On success, returns the
+ newly created node in *NP. */
+error_t
+process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np);
+
diff --git a/procfs/procfs.c b/procfs/procfs.c
new file mode 100644
index 00000000..ae5a6769
--- /dev/null
+++ b/procfs/procfs.c
@@ -0,0 +1,203 @@
+/* Hurd /proc filesystem, basic infrastructure.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <mach.h>
+#include <hurd/netfs.h>
+#include <hurd/fshelp.h>
+#include "procfs.h"
+
+struct netnode
+{
+ const struct procfs_node_ops *ops;
+ void *hook;
+
+ /* (cached) contents of the node */
+ char *contents;
+ ssize_t contents_len;
+
+ /* parent directory, if applicable */
+ struct node *parent;
+};
+
+void
+procfs_cleanup_contents_with_free (void *hook, char *cont, ssize_t len)
+{
+ free (cont);
+}
+
+void
+procfs_cleanup_contents_with_vm_deallocate (void *hook, char *cont, ssize_t len)
+{
+ vm_deallocate (mach_task_self (), (vm_address_t) cont, (vm_size_t) len);
+}
+
+struct node *procfs_make_node (const struct procfs_node_ops *ops, void *hook)
+{
+ struct netnode *nn;
+ struct node *np;
+
+ nn = malloc (sizeof *nn);
+ if (! nn)
+ goto fail;
+
+ memset (nn, 0, sizeof *nn);
+ nn->ops = ops;
+ nn->hook = hook;
+
+ np = netfs_make_node (nn);
+ if (! np)
+ goto fail;
+
+ np->nn = nn;
+ memset (&np->nn_stat, 0, sizeof np->nn_stat);
+ np->nn_translated = 0;
+
+ if (np->nn->ops->lookup)
+ np->nn_stat.st_mode = S_IFDIR | 0555;
+ else
+ np->nn_stat.st_mode = S_IFREG | 0444;
+
+ return np;
+
+fail:
+ if (ops->cleanup)
+ ops->cleanup (hook);
+
+ free (nn);
+ return NULL;
+}
+
+void procfs_node_chown (struct node *np, uid_t owner)
+{
+ np->nn_stat.st_uid = owner;
+}
+
+void procfs_node_chmod (struct node *np, mode_t mode)
+{
+ np->nn_stat.st_mode = (np->nn_stat.st_mode & S_IFMT) | mode;
+ np->nn_translated = np->nn_stat.st_mode;
+}
+
+void procfs_node_chtype (struct node *np, mode_t type)
+{
+ np->nn_stat.st_mode = (np->nn_stat.st_mode & ~S_IFMT) | type;
+ np->nn_translated = np->nn_stat.st_mode;
+ if (type == S_IFLNK)
+ procfs_node_chmod (np, 0777);
+}
+
+/* FIXME: possibly not the fastest hash function... */
+ino64_t
+procfs_make_ino (struct node *np, const char *filename)
+{
+ unsigned short x[3];
+
+ if (! strcmp (filename, "."))
+ return np->nn_stat.st_ino;
+ if (! strcmp (filename, ".."))
+ return np->nn->parent ? np->nn->parent->nn_stat.st_ino : /* FIXME: */ 2;
+
+ assert (sizeof np->nn_stat.st_ino > sizeof x);
+ memcpy (x, &np->nn_stat.st_ino, sizeof x);
+
+ while (*filename)
+ {
+ x[0] ^= *(filename++);
+ jrand48 (x);
+ }
+
+ return (unsigned long) jrand48 (x);
+}
+
+error_t procfs_get_contents (struct node *np, char **data, ssize_t *data_len)
+{
+ if (! np->nn->contents && np->nn->ops->get_contents)
+ {
+ char *contents;
+ ssize_t contents_len;
+ error_t err;
+
+ contents_len = -1;
+ err = np->nn->ops->get_contents (np->nn->hook, &contents, &contents_len);
+ if (err)
+ return err;
+ if (contents_len < 0)
+ return ENOMEM;
+
+ np->nn->contents = contents;
+ np->nn->contents_len = contents_len;
+ }
+
+ *data = np->nn->contents;
+ *data_len = np->nn->contents_len;
+ return 0;
+}
+
+void procfs_refresh (struct node *np)
+{
+ if (np->nn->contents && np->nn->ops->cleanup_contents)
+ np->nn->ops->cleanup_contents (np->nn->hook, np->nn->contents, np->nn->contents_len);
+
+ np->nn->contents = NULL;
+}
+
+error_t procfs_lookup (struct node *np, const char *name, struct node **npp)
+{
+ error_t err = ENOENT;
+
+ if (err && ! strcmp (name, "."))
+ {
+ netfs_nref(*npp = np);
+ err = 0;
+ }
+
+ if (err && np->nn->parent && ! strcmp (name, ".."))
+ {
+ netfs_nref(*npp = np->nn->parent);
+ err = 0;
+ }
+
+ if (err && np->nn->ops->lookup)
+ {
+ err = np->nn->ops->lookup (np->nn->hook, name, npp);
+ if (! err)
+ {
+ (*npp)->nn_stat.st_ino = procfs_make_ino (np, name);
+ netfs_nref ((*npp)->nn->parent = np);
+ }
+ }
+
+ return err;
+}
+
+void procfs_cleanup (struct node *np)
+{
+ procfs_refresh (np);
+
+ if (np->nn->ops->cleanup)
+ np->nn->ops->cleanup (np->nn->hook);
+
+ if (np->nn->parent)
+ netfs_nrele (np->nn->parent);
+
+ free (np->nn);
+}
diff --git a/procfs/procfs.h b/procfs/procfs.h
new file mode 100644
index 00000000..64782ec4
--- /dev/null
+++ b/procfs/procfs.h
@@ -0,0 +1,93 @@
+/* Hurd /proc filesystem, basic infrastructure.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/hurd_types.h>
+#include <hurd/netfs.h>
+
+
+/* Interface for the procfs side. */
+
+/* Any of these callback functions can be omitted, in which case
+ reasonable defaults will be used. The initial file mode and type
+ depend on whether a lookup function is provided, but can be
+ overridden in update_stat(). */
+struct procfs_node_ops
+{
+ /* Fetch the contents of a node. A pointer to the contents should be
+ returned in *CONTENTS and their length in *CONTENTS_LEN. The exact
+ nature of these data depends on whether the node is a regular file,
+ symlink or directory, as determined by the file mode in
+ netnode->nn_stat. For regular files and symlinks, they are what
+ you would expect; for directories, they are an argz vector of the
+ names of the entries. If upon return, *CONTENTS_LEN is negative or
+ unchanged, the call is considered to have failed because of a memory
+ allocation error. */
+ error_t (*get_contents) (void *hook, char **contents, ssize_t *contents_len);
+ void (*cleanup_contents) (void *hook, char *contents, ssize_t contents_len);
+
+ /* Lookup NAME in this directory, and store the result in *np. The
+ returned node should be created by lookup() using procfs_make_node()
+ or a derived function. Note that the parent will be kept alive as
+ long as the child exists, so you can safely reference the parent's
+ data from the child. You may want to consider locking if there's
+ any mutation going on, though. */
+ error_t (*lookup) (void *hook, const char *name, struct node **np);
+
+ /* Destroy this node. */
+ void (*cleanup) (void *hook);
+};
+
+/* These helper functions can be used as procfs_node_ops.cleanup_contents. */
+void procfs_cleanup_contents_with_free (void *, char *, ssize_t);
+void procfs_cleanup_contents_with_vm_deallocate (void *, char *, ssize_t);
+
+/* Create a new node and return it. Returns NULL if it fails to allocate
+ enough memory. In this case, ops->cleanup will be invoked. */
+struct node *procfs_make_node (const struct procfs_node_ops *ops, void *hook);
+
+/* Set the owner of the node NP. Must be called right after the node
+ has been created. */
+void procfs_node_chown (struct node *np, uid_t owner);
+
+/* Set the permission bits of the node NP. Must be called right after
+ the node has been created. */
+void procfs_node_chmod (struct node *np, mode_t mode);
+
+/* Set the type of the node NP. If type is S_IFLNK, appropriate
+ permission bits will be set as well. Must be called right after the
+ node has been created. */
+void procfs_node_chtype (struct node *np, mode_t type);
+
+
+/* Interface for the libnetfs side. */
+
+/* Get the inode number which will be given to a child of NP named FILENAME.
+ This allows us to retreive them for readdir() without creating the
+ corresponding child nodes. */
+ino64_t procfs_make_ino (struct node *np, const char *filename);
+
+/* Forget the current cached contents for the node. This is done before reads
+ from offset 0, to ensure that the data are recent even for utilities such as
+ top which keep some nodes open. */
+void procfs_refresh (struct node *np);
+
+error_t procfs_get_contents (struct node *np, char **data, ssize_t *data_len);
+error_t procfs_lookup (struct node *np, const char *name, struct node **npp);
+void procfs_cleanup (struct node *np);
+
diff --git a/procfs/procfs_dir.c b/procfs/procfs_dir.c
new file mode 100644
index 00000000..c250aa48
--- /dev/null
+++ b/procfs/procfs_dir.c
@@ -0,0 +1,134 @@
+/* Hurd /proc filesystem, infrastructure for directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "procfs.h"
+#include "procfs_dir.h"
+
+struct procfs_dir_node
+{
+ const struct procfs_dir_ops *ops;
+ void *hook;
+};
+
+static int
+entry_exists (struct procfs_dir_node *dir, const struct procfs_dir_entry *ent)
+{
+ if (ent->ops.exists)
+ return ent->ops.exists (dir->hook, ent->hook);
+ if (dir->ops->entry_ops.exists)
+ return dir->ops->entry_ops.exists (dir->hook, ent->hook);
+
+ return 1;
+}
+
+static error_t
+procfs_dir_get_contents (void *hook, char **contents, ssize_t *contents_len)
+{
+ static const char dot_dotdot[] = ".\0..";
+ struct procfs_dir_node *dir = hook;
+ const struct procfs_dir_entry *ent;
+ int pos;
+
+ /* Evaluate how much space is needed. Note that we include the hidden
+ entries, just in case their status changes between now and then. */
+ pos = sizeof dot_dotdot;
+ for (ent = dir->ops->entries; ent->name; ent++)
+ pos += strlen (ent->name) + 1;
+
+ *contents = malloc (pos);
+ if (! *contents)
+ return ENOMEM;
+
+ memcpy (*contents, dot_dotdot, sizeof dot_dotdot);
+ pos = sizeof dot_dotdot;
+ for (ent = dir->ops->entries; ent->name; ent++)
+ {
+ if (! entry_exists (dir, ent))
+ continue;
+
+ strcpy (*contents + pos, ent->name);
+ pos += strlen (ent->name) + 1;
+ }
+
+ *contents_len = pos;
+ return 0;
+}
+
+static error_t
+procfs_dir_lookup (void *hook, const char *name, struct node **np)
+{
+ struct procfs_dir_node *dir = hook;
+ const struct procfs_dir_entry *ent;
+
+ for (ent = dir->ops->entries; ent->name && strcmp (name, ent->name); ent++);
+ if (! ent->name)
+ return ENOENT;
+
+ if (ent->ops.make_node)
+ *np = ent->ops.make_node (dir->hook, ent->hook);
+ else if (dir->ops->entry_ops.make_node)
+ *np = dir->ops->entry_ops.make_node (dir->hook, ent->hook);
+ else
+ return EGRATUITOUS;
+
+ if (! *np)
+ return ENOMEM;
+
+ return 0;
+}
+
+static void
+procfs_dir_cleanup (void *hook)
+{
+ struct procfs_dir_node *dir = hook;
+
+ if (dir->ops->cleanup)
+ dir->ops->cleanup (dir->hook);
+
+ free (dir);
+}
+
+struct node *
+procfs_dir_make_node (const struct procfs_dir_ops *dir_ops, void *dir_hook)
+{
+ static const struct procfs_node_ops ops = {
+ .get_contents = procfs_dir_get_contents,
+ .lookup = procfs_dir_lookup,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ .cleanup = procfs_dir_cleanup,
+ };
+ struct procfs_dir_node *dir;
+
+ dir = malloc (sizeof *dir);
+ if (! dir)
+ {
+ if (dir_ops->cleanup)
+ dir_ops->cleanup (dir_hook);
+
+ return NULL;
+ }
+
+ dir->ops = dir_ops;
+ dir->hook = dir_hook;
+
+ return procfs_make_node (&ops, dir);
+}
+
diff --git a/procfs/procfs_dir.h b/procfs/procfs_dir.h
new file mode 100644
index 00000000..94c5b019
--- /dev/null
+++ b/procfs/procfs_dir.h
@@ -0,0 +1,63 @@
+/* Hurd /proc filesystem, infrastructure for directories.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides an abstraction layer for implementing simple
+ directories with (mostly) static contents. The user defines the
+ contents of the directory by providing a table of entries and various
+ optional callback functions. */
+
+/* These operations define how a given entry will behave. Either can be
+ omitted, both from the entry-specific operations and from the
+ directory-wide defaults. */
+struct procfs_dir_entry_ops
+{
+ /* Called when this entry is looked up to create a corresponding node. */
+ struct node *(*make_node)(void *dir_hook, const void *entry_hook);
+ /* If this is provided and returns 0, this entry will be hidden. */
+ int (*exists)(void *dir_hook, const void *entry_hook);
+};
+
+/* Describes an individual directory entry, associating a NAME with
+ * arbitrary HOOK data and node-specific OPS. */
+struct procfs_dir_entry
+{
+ const char *name;
+ const void *hook;
+ struct procfs_dir_entry_ops ops;
+};
+
+/* Describes a complete directory. ENTRIES is a table terminated by a
+ null NAME field. ENTRY_OPS provides default operations for the
+ entries which don't specify them. The optional CLEANUP function
+ should release all the resources associated with the directory hook. */
+struct procfs_dir_ops
+{
+ const struct procfs_dir_entry *entries;
+ void (*cleanup)(void *dir_hook);
+ struct procfs_dir_entry_ops entry_ops;
+};
+
+/* Create and return a new node for the directory described in OPS.
+ The DIR_HOOK is passed the MAKE_NODE callback function of looked up
+ entries, as well as to the CLEANUP callback when the node is
+ destroyed. If not enough memory can be allocated, OPS->CLEANUP is
+ invoked immediately and NULL is returned. */
+struct node *
+procfs_dir_make_node (const struct procfs_dir_ops *ops, void *dir_hook);
+
diff --git a/procfs/proclist.c b/procfs/proclist.c
new file mode 100644
index 00000000..58b942dc
--- /dev/null
+++ b/procfs/proclist.c
@@ -0,0 +1,94 @@
+/* Hurd /proc filesystem, list of processes as a directory.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mach.h>
+#include <hurd/process.h>
+#include <ps.h>
+#include "procfs.h"
+#include "process.h"
+
+#define PID_STR_SIZE (3 * sizeof (pid_t) + 1)
+
+static error_t
+proclist_get_contents (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct ps_context *pc = hook;
+ pidarray_t pids;
+ mach_msg_type_number_t num_pids;
+ error_t err;
+ int i;
+
+ num_pids = 0;
+ err = proc_getallpids (pc->server, &pids, &num_pids);
+ if (err)
+ return EIO;
+
+ *contents = malloc (num_pids * PID_STR_SIZE);
+ if (*contents)
+ {
+ *contents_len = 0;
+ for (i=0; i < num_pids; i++)
+ {
+ int n = sprintf (*contents + *contents_len, "%d", pids[i]);
+ assert (n >= 0);
+ *contents_len += (n + 1);
+ }
+ }
+ else
+ err = ENOMEM;
+
+ vm_deallocate (mach_task_self (), (vm_address_t) pids, num_pids * sizeof pids[0]);
+ return err;
+}
+
+static error_t
+proclist_lookup (void *hook, const char *name, struct node **np)
+{
+ struct ps_context *pc = hook;
+ char *endp;
+ pid_t pid;
+
+ /* Self-lookups should not end up here. */
+ assert (name[0]);
+
+ /* No leading zeros allowed */
+ if (name[0] == '0' && name[1])
+ return ENOENT;
+
+ pid = strtol (name, &endp, 10);
+ if (*endp)
+ return ENOENT;
+
+ return process_lookup_pid (pc, pid, np);
+}
+
+struct node *
+proclist_make_node (struct ps_context *pc)
+{
+ static const struct procfs_node_ops ops = {
+ .get_contents = proclist_get_contents,
+ .lookup = proclist_lookup,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ };
+ return procfs_make_node (&ops, pc);
+}
+
diff --git a/procfs/proclist.h b/procfs/proclist.h
new file mode 100644
index 00000000..bfe95b3d
--- /dev/null
+++ b/procfs/proclist.h
@@ -0,0 +1,23 @@
+/* Hurd /proc filesystem, list of processes as a directory.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ps.h>
+
+struct node *
+proclist_make_node (struct ps_context *pc);
diff --git a/procfs/rootdir.c b/procfs/rootdir.c
new file mode 100644
index 00000000..1fa71b03
--- /dev/null
+++ b/procfs/rootdir.c
@@ -0,0 +1,506 @@
+/* Hurd /proc filesystem, permanent files of the root directory.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach/vm_param.h>
+#include <mach/vm_statistics.h>
+#include <mach/default_pager.h>
+#include <hurd/paths.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <argz.h>
+#include <ps.h>
+#include "procfs.h"
+#include "procfs_dir.h"
+#include "main.h"
+
+/* This implements a directory node with the static files in /proc.
+ NB: the libps functions for host information return static storage;
+ using them would require locking and as a consequence it would be
+ more complicated, not simpler. */
+
+
+/* Helper functions */
+
+/* We get the boot time by using that of the kernel process. */
+static error_t
+get_boottime (struct ps_context *pc, struct timeval *tv)
+{
+ struct proc_stat *ps;
+ error_t err;
+
+ err = _proc_stat_create (opt_kernel_pid, pc, &ps);
+ if (err)
+ return err;
+
+ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC);
+ if (err || !(proc_stat_flags (ps) & PSTAT_TASK_BASIC))
+ err = EIO;
+
+ if (! err)
+ {
+ task_basic_info_t tbi = proc_stat_task_basic_info (ps);
+ tv->tv_sec = tbi->creation_time.seconds;
+ tv->tv_usec = tbi->creation_time.microseconds;
+ }
+
+ _proc_stat_free (ps);
+ return err;
+}
+
+/* We get the idle time by querying the kernel's idle thread. */
+static error_t
+get_idletime (struct ps_context *pc, struct timeval *tv)
+{
+ struct proc_stat *ps, *pst;
+ thread_basic_info_t tbi;
+ error_t err;
+ int i;
+
+ err = _proc_stat_create (opt_kernel_pid, pc, &ps);
+ if (err)
+ return err;
+
+ pst = NULL, tbi = NULL;
+
+ err = proc_stat_set_flags (ps, PSTAT_NUM_THREADS);
+ if (err || !(proc_stat_flags (ps) & PSTAT_NUM_THREADS))
+ {
+ err = EIO;
+ goto out;
+ }
+
+ /* Look for the idle thread */
+ for (i=0; !tbi || !(tbi->flags & TH_FLAGS_IDLE); i++)
+ {
+ if (pst)
+ _proc_stat_free (pst);
+
+ pst = NULL, tbi = NULL;
+ if (i >= proc_stat_num_threads (ps))
+ {
+ err = ESRCH;
+ goto out;
+ }
+
+ err = proc_stat_thread_create (ps, i, &pst);
+ if (err)
+ continue;
+
+ err = proc_stat_set_flags (pst, PSTAT_THREAD_BASIC);
+ if (err || ! (proc_stat_flags (pst) & PSTAT_THREAD_BASIC))
+ continue;
+
+ tbi = proc_stat_thread_basic_info (pst);
+ }
+
+ /* We found it! */
+ tv->tv_sec = tbi->system_time.seconds;
+ tv->tv_usec = tbi->system_time.microseconds;
+ err = 0;
+
+out:
+ if (pst) _proc_stat_free (pst);
+ _proc_stat_free (ps);
+ return err;
+}
+
+static error_t
+get_swapinfo (default_pager_info_t *info)
+{
+ mach_port_t defpager;
+ error_t err;
+
+ defpager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0);
+ if (defpager == MACH_PORT_NULL)
+ return errno;
+
+ err = default_pager_info (defpager, info);
+ mach_port_deallocate (mach_task_self (), defpager);
+
+ return err;
+}
+
+
+/* Content generators */
+
+static error_t
+rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct utsname uts;
+ int r;
+
+ r = uname (&uts);
+ if (r < 0)
+ return errno;
+
+ *contents_len = asprintf (contents,
+ "Linux version 2.6.1 (%s %s %s %s)\n",
+ uts.sysname, uts.release, uts.version, uts.machine);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct timeval time, boottime, idletime;
+ double up_secs, idle_secs;
+ error_t err;
+
+ err = gettimeofday (&time, NULL);
+ if (err < 0)
+ return errno;
+
+ err = get_boottime (hook, &boottime);
+ if (err)
+ return err;
+
+ err = get_idletime (hook, &idletime);
+ if (err)
+ return err;
+
+ timersub (&time, &boottime, &time);
+ up_secs = (time.tv_sec * 1000000. + time.tv_usec) / 1000000.;
+ idle_secs = (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.;
+
+ /* The second field is the total idle time. As far as I know we don't
+ keep track of it. However, procps uses it to compute "USER_HZ", and
+ proc(5) specifies that it should be equal to USER_HZ times the idle value
+ in ticks from /proc/stat. So we assume a completely idle system both here
+ and there to make that work. */
+ *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, idle_secs);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct timeval boottime, time, idletime;
+ struct vm_statistics vmstats;
+ unsigned long up_ticks, idle_ticks;
+ error_t err;
+
+ err = gettimeofday (&time, NULL);
+ if (err < 0)
+ return errno;
+
+ err = get_boottime (hook, &boottime);
+ if (err)
+ return err;
+
+ err = get_idletime (hook, &idletime);
+ if (err)
+ return err;
+
+ err = vm_statistics (mach_task_self (), &vmstats);
+ if (err)
+ return EIO;
+
+ timersub (&time, &boottime, &time);
+ up_ticks = opt_clk_tck * (time.tv_sec * 1000000. + time.tv_usec) / 1000000.;
+ idle_ticks = opt_clk_tck * (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.;
+
+ *contents_len = asprintf (contents,
+ "cpu %lu 0 0 %lu 0 0 0 0 0\n"
+ "cpu0 %lu 0 0 %lu 0 0 0 0 0\n"
+ "intr 0\n"
+ "page %d %d\n"
+ "btime %lu\n",
+ up_ticks - idle_ticks, idle_ticks,
+ up_ticks - idle_ticks, idle_ticks,
+ vmstats.pageins, vmstats.pageouts,
+ boottime.tv_sec);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_loadavg (void *hook, char **contents, ssize_t *contents_len)
+{
+ host_load_info_data_t hli;
+ mach_msg_type_number_t cnt;
+ error_t err;
+
+ cnt = HOST_LOAD_INFO_COUNT;
+ err = host_info (mach_host_self (), HOST_LOAD_INFO, (host_info_t) &hli, &cnt);
+ if (err)
+ return err;
+
+ assert (cnt == HOST_LOAD_INFO_COUNT);
+ *contents_len = asprintf (contents,
+ "%.2f %.2f %.2f 1/0 0\n",
+ hli.avenrun[0] / (double) LOAD_SCALE,
+ hli.avenrun[1] / (double) LOAD_SCALE,
+ hli.avenrun[2] / (double) LOAD_SCALE);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len)
+{
+ host_basic_info_data_t hbi;
+ mach_msg_type_number_t cnt;
+ struct vm_statistics vmstats;
+ default_pager_info_t swap;
+ error_t err;
+
+ err = vm_statistics (mach_task_self (), &vmstats);
+ if (err)
+ return EIO;
+
+ cnt = HOST_BASIC_INFO_COUNT;
+ err = host_info (mach_host_self (), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt);
+ if (err)
+ return err;
+
+ err = get_swapinfo (&swap);
+ if (err)
+ return err;
+
+ assert (cnt == HOST_BASIC_INFO_COUNT);
+ *contents_len = asprintf (contents,
+ "MemTotal: %14lu kB\n"
+ "MemFree: %14lu kB\n"
+ "Buffers: %14lu kB\n"
+ "Cached: %14lu kB\n"
+ "Active: %14lu kB\n"
+ "Inactive: %14lu kB\n"
+ "Mlocked: %14lu kB\n"
+ "SwapTotal:%14lu kB\n"
+ "SwapFree: %14lu kB\n"
+ ,
+ (long unsigned) hbi.memory_size / 1024,
+ (long unsigned) vmstats.free_count * PAGE_SIZE / 1024,
+ 0,
+ 0,
+ (long unsigned) vmstats.active_count * PAGE_SIZE / 1024,
+ (long unsigned) vmstats.inactive_count * PAGE_SIZE / 1024,
+ (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024,
+ (long unsigned) swap.dpi_total_space / 1024,
+ (long unsigned) swap.dpi_free_space / 1024);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_vmstat (void *hook, char **contents, ssize_t *contents_len)
+{
+ host_basic_info_data_t hbi;
+ mach_msg_type_number_t cnt;
+ struct vm_statistics vmstats;
+ error_t err;
+
+ err = vm_statistics (mach_task_self (), &vmstats);
+ if (err)
+ return EIO;
+
+ cnt = HOST_BASIC_INFO_COUNT;
+ err = host_info (mach_host_self (), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt);
+ if (err)
+ return err;
+
+ assert (cnt == HOST_BASIC_INFO_COUNT);
+ *contents_len = asprintf (contents,
+ "nr_free_pages %lu\n"
+ "nr_inactive_anon %lu\n"
+ "nr_active_anon %lu\n"
+ "nr_inactive_file %lu\n"
+ "nr_active_file %lu\n"
+ "nr_unevictable %lu\n"
+ "nr_mlock %lu\n"
+ "pgpgin %lu\n"
+ "pgpgout %lu\n"
+ "pgfault %lu\n",
+ (long unsigned) vmstats.free_count,
+ /* FIXME: how can we distinguish the anon/file pages? Maybe we can
+ ask the default pager how many it manages? */
+ (long unsigned) vmstats.inactive_count,
+ (long unsigned) vmstats.active_count,
+ (long unsigned) 0,
+ (long unsigned) 0,
+ (long unsigned) vmstats.wire_count,
+ (long unsigned) vmstats.wire_count,
+ (long unsigned) vmstats.pageins,
+ (long unsigned) vmstats.pageouts,
+ (long unsigned) vmstats.faults);
+
+ return 0;
+}
+
+static error_t
+rootdir_gc_cmdline (void *hook, char **contents, ssize_t *contents_len)
+{
+ struct ps_context *pc = hook;
+ struct proc_stat *ps;
+ error_t err;
+
+ err = _proc_stat_create (opt_kernel_pid, pc, &ps);
+ if (err)
+ return EIO;
+
+ err = proc_stat_set_flags (ps, PSTAT_ARGS);
+ if (err || ! (proc_stat_flags (ps) & PSTAT_ARGS))
+ {
+ err = EIO;
+ goto out;
+ }
+
+ *contents_len = proc_stat_args_len (ps);
+ *contents = malloc (*contents_len);
+ if (! *contents)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
+ memcpy (*contents, proc_stat_args (ps), *contents_len);
+ argz_stringify (*contents, *contents_len, ' ');
+ (*contents)[*contents_len - 1] = '\n';
+
+out:
+ _proc_stat_free (ps);
+ return err;
+}
+
+static int
+rootdir_fakeself_exists ()
+{
+ return opt_fake_self >= 0;
+}
+
+static error_t
+rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len)
+{
+ *contents_len = asprintf (contents, "%d", opt_fake_self);
+ return 0;
+}
+
+
+/* Glue logic and entries table */
+
+static struct node *
+rootdir_file_make_node (void *dir_hook, const void *entry_hook)
+{
+ /* The entry hook we use is actually a procfs_node_ops for the file to be
+ created. The hook associated to these newly created files (and passed
+ to the generators above as a consequence) is always the same global
+ ps_context, which we get from rootdir_make_node as the directory hook. */
+ return procfs_make_node (entry_hook, dir_hook);
+}
+
+static struct node *
+rootdir_symlink_make_node (void *dir_hook, const void *entry_hook)
+{
+ struct node *np = procfs_make_node (entry_hook, dir_hook);
+ if (np)
+ procfs_node_chtype (np, S_IFLNK);
+ return np;
+}
+
+static const struct procfs_dir_entry rootdir_entries[] = {
+ {
+ .name = "self",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_fakeself,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ .ops = {
+ .make_node = rootdir_symlink_make_node,
+ .exists = rootdir_fakeself_exists,
+ }
+ },
+ {
+ .name = "version",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_version,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "uptime",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_uptime,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "stat",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_stat,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "loadavg",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_loadavg,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "meminfo",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_meminfo,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "vmstat",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_vmstat,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+ {
+ .name = "cmdline",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_cmdline,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
+#ifdef PROFILE
+ /* In order to get a usable gmon.out file, we must apparently use exit(). */
+ {
+ .name = "exit",
+ .ops = {
+ .make_node = exit,
+ },
+ },
+#endif
+ {}
+};
+
+struct node
+*rootdir_make_node (struct ps_context *pc)
+{
+ static const struct procfs_dir_ops ops = {
+ .entries = rootdir_entries,
+ .entry_ops = {
+ .make_node = rootdir_file_make_node,
+ },
+ };
+ return procfs_dir_make_node (&ops, pc);
+}
+
diff --git a/procfs/rootdir.h b/procfs/rootdir.h
new file mode 100644
index 00000000..6980da8f
--- /dev/null
+++ b/procfs/rootdir.h
@@ -0,0 +1,23 @@
+/* Hurd /proc filesystem, permanent files of the root directory.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ 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 General Public License as
+ published by the Free Software Foundation; either version 2, 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ps.h>
+
+struct node *
+rootdir_make_node (struct ps_context *pc);
diff --git a/random/Makefile b/random/Makefile
new file mode 100644
index 00000000..9b3a95dd
--- /dev/null
+++ b/random/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 1994,95,96,97,99,2000,2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := random
+makemode := server
+
+CFLAGS += -D__HURD__
+
+target = random
+SRCS = random.c gnupg-random.c gnupg-rmd160.c
+OBJS = $(SRCS:.c=.o) startup_notifyServer.o
+LCLHDRS = gnupg-random.h gnupg-rmd.h gnupg-bithelp.h random.h
+HURDLIBS = trivfs threads ports fshelp ihash shouldbeinlibc
+
+include ../Makeconf
diff --git a/random/TODO b/random/TODO
new file mode 100644
index 00000000..9cc57ab9
--- /dev/null
+++ b/random/TODO
@@ -0,0 +1,11 @@
+* read_poll uses random_poll until the pool is filled. This is ian
+ issue at first initialization, as this requries POOLSIZE good random (level 1 from
+ gather_random) even in level 0 and 1.
+ For now, the code is only applied to level 2. Eventually, readable_pool
+ should be fixed to return 0 if initialization is not done yet and not enough bytes
+ are available. Otherwise it enters an infinite loop.
+
+* Permissions?
+
+* Off by one error in gather_random/io_write? I can only get GATHERBUFSIZE - 1
+ bytes from it.
diff --git a/random/gnupg-bithelp.h b/random/gnupg-bithelp.h
new file mode 100644
index 00000000..188db168
--- /dev/null
+++ b/random/gnupg-bithelp.h
@@ -0,0 +1,41 @@
+/* bithelp.h - Some bit manipulation helpers
+ * Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_BITHELP_H
+#define G10_BITHELP_H
+
+
+/****************
+ * Rotate a 32 bit integer by n bytes
+ */
+#if defined(__GNUC__) && defined(__i386__)
+static inline u32
+rol( u32 x, int n)
+{
+ __asm__("roll %%cl,%0"
+ :"=r" (x)
+ :"0" (x),"c" (n));
+ return x;
+}
+#else
+ #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+
+#endif /*G10_BITHELP_H*/
diff --git a/random/gnupg-glue.h b/random/gnupg-glue.h
new file mode 100644
index 00000000..cbf0a103
--- /dev/null
+++ b/random/gnupg-glue.h
@@ -0,0 +1,40 @@
+#ifndef __GNUPG_GLUE_H__
+#define __GNUPG_GLUE_H__
+
+#include <sys/types.h>
+#include <random.h>
+
+#define SIZEOF_UNSIGNED_LONG 4
+typedef unsigned int u32;
+typedef unsigned char byte;
+
+/* GnuPG's config.h */
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_GETRUSAGE 1
+#define HAVE_RAND 1
+
+/* GnuPG's memory.h */
+#define m_alloc malloc
+#define m_alloc_secure malloc
+#define m_alloc_clear(x) calloc(x, 1)
+#define m_alloc_secure_clear(x) calloc(x, 1)
+#define m_free free
+#define m_strdup strdup
+
+/* GnuPG's dynaload.h */
+#define dynload_getfnc_fast_random_poll() (0)
+#define dynload_getfnc_gather_random() &gather_random
+int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level );
+
+/* GnuPG's miscellaneous stuff. */
+#define BUG() assert(0)
+#define _(x) x
+#define make_timestamp() time(0)
+#define tty_printf printf
+#define log_info(format, args...) printf(format , ## args)
+#define log_fatal(format, args...) { printf(format , ## args) ; exit(2); }
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+
+#endif /* __GNUPG_GLUE_H__ */
diff --git a/random/gnupg-random.c b/random/gnupg-random.c
new file mode 100644
index 00000000..8f308621
--- /dev/null
+++ b/random/gnupg-random.c
@@ -0,0 +1,810 @@
+/* random.c - random number generator
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/****************
+ * This random number generator is modelled after the one described
+ * in Peter Gutmann's Paper: "Software Generation of Practically
+ * Strong Random Numbers".
+ */
+
+#ifndef __HURD__
+#include <config.h>
+#else
+#include "gnupg-glue.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef HAVE_GETHRTIME
+ #include <sys/times.h>
+#endif
+#ifdef HAVE_GETTIMEOFDAY
+ #include <sys/times.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+ #include <sys/resource.h>
+#endif
+#ifdef __MINGW32__
+ #include <process.h>
+#endif
+#ifndef __HURD__
+#include "util.h"
+#endif
+#ifndef __HURD__
+#include "rmd.h"
+#include "ttyio.h"
+#include "i18n.h"
+#include "random.h"
+#include "rand-internal.h"
+#include "dynload.h"
+#else
+#include "gnupg-rmd.h"
+#include "gnupg-random.h"
+#endif
+
+#ifndef RAND_MAX /* for SunOS */
+ #define RAND_MAX 32767
+#endif
+
+
+#if SIZEOF_UNSIGNED_LONG == 8
+ #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
+#elif SIZEOF_UNSIGNED_LONG == 4
+ #define ADD_VALUE 0xa5a5a5a5
+#else
+ #error weird size for an unsigned long
+#endif
+
+#define BLOCKLEN 64 /* hash this amount of bytes */
+#define DIGESTLEN 20 /* into a digest of this length (rmd160) */
+/* poolblocks is the number of digests which make up the pool
+ * and poolsize must be a multiple of the digest length
+ * to make the AND operations faster, the size should also be
+ * a multiple of ulong
+ */
+#define POOLBLOCKS 30
+#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
+#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
+ #error Please make sure that poolsize is a multiple of ulong
+#endif
+#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
+
+
+static int is_initialized;
+#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
+static char *rndpool; /* allocated size is POOLSIZE+BLOCKLEN */
+static char *keypool; /* allocated size is POOLSIZE+BLOCKLEN */
+static size_t pool_readpos;
+static size_t pool_writepos;
+static int pool_filled;
+static int pool_balance;
+static int just_mixed;
+static int did_initial_extra_seeding;
+static char *seed_file_name;
+static int allow_seed_file_update;
+
+static int secure_alloc;
+static int quick_test;
+static int faked_rng;
+
+
+#ifndef __HURD__
+static void read_pool( byte *buffer, size_t length, int level );
+#else
+int read_pool( byte *buffer, size_t length, int level );
+#endif
+static void add_randomness( const void *buffer, size_t length, int source );
+static void random_poll(void);
+#ifndef __HURD__
+static void read_random_source( int requester, size_t length, int level);
+#else
+static int read_random_source( int requester, size_t length, int level);
+#endif
+static int gather_faked( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level );
+
+static struct {
+ ulong mixrnd;
+ ulong mixkey;
+ ulong slowpolls;
+ ulong fastpolls;
+ ulong getbytes1;
+ ulong ngetbytes1;
+ ulong getbytes2;
+ ulong ngetbytes2;
+ ulong addbytes;
+ ulong naddbytes;
+} rndstats;
+
+static void
+initialize(void)
+{
+ /* The data buffer is allocated somewhat larger, so that
+ * we can use this extra space (which is allocated in secure memory)
+ * as a temporary hash buffer */
+ rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+ : m_alloc_clear(POOLSIZE+BLOCKLEN);
+ keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+ : m_alloc_clear(POOLSIZE+BLOCKLEN);
+ is_initialized = 1;
+#ifndef __HURD__
+ cipher_modules_constructor();
+#endif
+}
+
+static void
+burn_stack (int bytes)
+{
+ char buf[128];
+
+ memset (buf, 0, sizeof buf);
+ bytes -= sizeof buf;
+ if (bytes > 0)
+ burn_stack (bytes);
+}
+
+void
+random_dump_stats()
+{
+ fprintf(stderr,
+ "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
+ " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
+ POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
+ rndstats.naddbytes, rndstats.addbytes,
+ rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
+ rndstats.ngetbytes2, rndstats.getbytes2 );
+}
+
+void
+secure_random_alloc()
+{
+ secure_alloc = 1;
+}
+
+
+int
+quick_random_gen( int onoff )
+{
+ int last;
+
+ read_random_source(0,0,0); /* init */
+ last = quick_test;
+ if( onoff != -1 )
+ quick_test = onoff;
+ return faked_rng? 1 : last;
+}
+
+
+/****************
+ * Fill the buffer with LENGTH bytes of cryptographically strong
+ * random bytes. level 0 is not very strong, 1 is strong enough
+ * for most usage, 2 is good for key generation stuff but may be very slow.
+ */
+void
+randomize_buffer( byte *buffer, size_t length, int level )
+{
+ char *p = get_random_bits( length*8, level, 1 );
+ memcpy( buffer, p, length );
+ m_free(p);
+}
+
+
+int
+random_is_faked()
+{
+ if( !is_initialized )
+ initialize();
+ return faked_rng || quick_test;
+}
+
+/****************
+ * Return a pointer to a randomized buffer of level 0 and LENGTH bits
+ * caller must free the buffer.
+ * Note: The returned value is rounded up to bytes.
+ */
+byte *
+get_random_bits( size_t nbits, int level, int secure )
+{
+ byte *buf, *p;
+ size_t nbytes = (nbits+7)/8;
+
+ if( quick_test && level > 1 )
+ level = 1;
+ MASK_LEVEL(level);
+ if( level == 1 ) {
+ rndstats.getbytes1 += nbytes;
+ rndstats.ngetbytes1++;
+ }
+ else if( level >= 2 ) {
+ rndstats.getbytes2 += nbytes;
+ rndstats.ngetbytes2++;
+ }
+
+ buf = secure && secure_alloc ? m_alloc_secure( nbytes ) : m_alloc( nbytes );
+ for( p = buf; nbytes > 0; ) {
+ size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
+#ifdef __HURD__
+ n =
+#endif
+ read_pool( p, n, level );
+ nbytes -= n;
+ p += n;
+
+ }
+ return buf;
+}
+
+
+/****************
+ * Mix the pool
+ */
+static void
+mix_pool(byte *pool)
+{
+ char *hashbuf = pool + POOLSIZE;
+ char *p, *pend;
+ int i, n;
+ RMD160_CONTEXT md;
+
+ rmd160_init( &md );
+ #if DIGESTLEN != 20
+ #error must have a digest length of 20 for ripe-md-160
+ #endif
+ /* loop over the pool */
+ pend = pool + POOLSIZE;
+ memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
+ memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+ rmd160_mixblock( &md, hashbuf);
+ memcpy(pool, hashbuf, 20 );
+
+ p = pool;
+ for( n=1; n < POOLBLOCKS; n++ ) {
+ memcpy(hashbuf, p, DIGESTLEN );
+
+ p += DIGESTLEN;
+ if( p+DIGESTLEN+BLOCKLEN < pend )
+ memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+ else {
+ char *pp = p+DIGESTLEN;
+ for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
+ if( pp >= pend )
+ pp = pool;
+ hashbuf[i] = *pp++;
+ }
+ }
+
+ rmd160_mixblock( &md, hashbuf);
+ memcpy(p, hashbuf, 20 );
+ }
+ burn_stack (200); /* for the rmd160_mixblock() */
+}
+
+
+void
+set_random_seed_file( const char *name )
+{
+ if( seed_file_name )
+ BUG();
+ seed_file_name = m_strdup( name );
+}
+
+/****************
+ * Read in a seed form the random_seed file
+ * and return true if this was successful
+ */
+static int
+read_seed_file()
+{
+ int fd;
+ struct stat sb;
+ unsigned char buffer[POOLSIZE];
+ int n;
+
+ if( !seed_file_name )
+ return 0;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_RDONLY | O_BINARY );
+ #else
+ fd = open( seed_file_name, O_RDONLY );
+ #endif
+ if( fd == -1 && errno == ENOENT) {
+ allow_seed_file_update = 1;
+ return 0;
+ }
+
+ if( fd == -1 ) {
+ log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+ return 0;
+ }
+ if( fstat( fd, &sb ) ) {
+ log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+ close(fd);
+ return 0;
+ }
+ if( !S_ISREG(sb.st_mode) ) {
+ log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+ close(fd);
+ return 0;
+ }
+ if( !sb.st_size ) {
+ log_info(_("note: random_seed file is empty\n") );
+ close(fd);
+ allow_seed_file_update = 1;
+ return 0;
+ }
+ if( sb.st_size != POOLSIZE ) {
+ log_info(_("warning: invalid size of random_seed file - not used\n") );
+ close(fd);
+ return 0;
+ }
+ do {
+ n = read( fd, buffer, POOLSIZE );
+ } while( n == -1 && errno == EINTR );
+ if( n != POOLSIZE ) {
+ log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ add_randomness( buffer, POOLSIZE, 0 );
+ /* add some minor entropy to the pool now (this will also force a mixing) */
+ { pid_t x = getpid();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ /* And read a few bytes from our entropy source. By using
+ * a level of 0 this will not block and might not return anything
+ * with some entropy drivers, however the rndlinux driver will use
+ * /dev/urandom and return some stuff - Do not read to much as we
+ * want to be friendly to the scare system entropy resource. */
+ read_random_source( 0, 16, 0 );
+
+ allow_seed_file_update = 1;
+ return 1;
+}
+
+void
+update_random_seed_file()
+{
+ ulong *sp, *dp;
+ int fd, i;
+
+ if( !seed_file_name || !is_initialized || !pool_filled )
+ return;
+ if( !allow_seed_file_update ) {
+ log_info(_("note: random_seed file not updated\n"));
+ return;
+ }
+
+
+ /* copy the entropy pool to a scratch pool and mix both of them */
+ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ ) {
+ *dp = *sp + ADD_VALUE;
+ }
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+ S_IRUSR|S_IWUSR );
+ #else
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+ #endif
+ if( fd == -1 ) {
+ log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+ return;
+ }
+ do {
+ i = write( fd, keypool, POOLSIZE );
+ } while( i == -1 && errno == EINTR );
+ if( i != POOLSIZE ) {
+ log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+ }
+ if( close(fd) )
+ log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+}
+
+#ifdef __HURD__
+int readable_pool( size_t length, int level )
+{
+ size_t needed = 0;
+ size_t my_balance = pool_balance;
+ size_t available = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
+
+ if (length > POOLSIZE)
+ length = POOLSIZE;
+
+ if (level < 2)
+ return length;
+
+ if( !pool_filled ) {
+ if( read_seed_file() )
+ pool_filled = 1;
+ }
+
+ if (!did_initial_extra_seeding)
+ {
+ /* Take account for initial extra seeding. */
+ needed = length;
+ if (needed < POOLSIZE/2)
+ needed = POOLSIZE/2;
+ my_balance = needed;
+
+ if (!pool_filled && pool_writepos + needed < POOLSIZE)
+ {
+ /* If the pool is not filled yet, we couldn't read the seed
+ file. Too bad. We will now have to take account for so many
+ random_poll()s as fit into the remaining pool. */
+
+ needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / (POOLSIZE/5);
+ }
+ }
+ else
+ {
+ if (!pool_filled)
+ needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / (POOLSIZE/5);
+ }
+
+ /* NEEDED contains the bytes needed for initialization, MY_BALANCE the resulting
+ available bytes. */
+ if (available < needed)
+ return 0;
+ return available + my_balance - needed;
+}
+#endif
+
+#ifndef __HURD__
+static void
+#else
+int
+#endif
+read_pool( byte *buffer, size_t length, int level )
+{
+ int i;
+ ulong *sp, *dp;
+
+ if( length > POOLSIZE ) {
+#ifndef __HURD__
+ log_fatal(_("too many random bits requested; the limit is %d\n"),
+ POOLSIZE*8-1 );
+#else
+ length = POOLSIZE;
+#endif
+ }
+
+ if( !pool_filled ) {
+ if( read_seed_file() )
+ pool_filled = 1;
+ }
+
+ /* For level 2 quality (key generation) we alwas make
+ * sure that the pool has been seeded enough initially */
+ if( level == 2 && !did_initial_extra_seeding ) {
+ size_t needed;
+
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if( needed < POOLSIZE/2 )
+ needed = POOLSIZE/2;
+ else if( needed > POOLSIZE )
+ BUG();
+#ifdef __HURD__
+ needed =
+#endif
+ read_random_source( 3, needed, 2 );
+#ifdef __HURD__
+ if (! needed)
+ return 0;
+ /* XXX This will succeed with needed < POOLSIZE/2 even. But
+ erroring out will waste the random we already got. */
+#endif
+ pool_balance += needed;
+ did_initial_extra_seeding=1;
+ }
+
+ /* for level 2 make sure that there is enough random in the pool */
+ if( level == 2 && pool_balance < length ) {
+ size_t needed;
+
+ if( pool_balance < 0 )
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if( needed > POOLSIZE )
+ BUG();
+#ifdef __HURD__
+ needed =
+#endif
+ read_random_source( 3, needed, 2 );
+ pool_balance += needed;
+ }
+
+#ifdef __HURD__
+ /* XXX This makes level 0 and 1 worse than needed at first start up. */
+ if (level == 2)
+#endif
+ /* make sure the pool is filled */
+ while( !pool_filled )
+ random_poll();
+
+ /* do always a fast random poll */
+ fast_random_poll();
+
+ if( !level ) { /* no need for cryptographic strong random */
+ /* create a new pool */
+ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ )
+ *dp = *sp + ADD_VALUE;
+ /* must mix both pools */
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+ memcpy( buffer, keypool, length );
+ return length;
+ }
+ else {
+#ifdef __HURD__
+ int amount;
+#endif
+ /* mix the pool (if add_randomness() didn't it) */
+ if( !just_mixed ) {
+ mix_pool(rndpool);
+ rndstats.mixrnd++;
+ }
+ /* create a new pool */
+ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ )
+ *dp = *sp + ADD_VALUE;
+ /* and mix both pools */
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+ /* read the required data
+ * we use a readpoiter to read from a different postion each
+ * time */
+#ifdef __HURD__
+ if (level == 2 && length > pool_balance)
+ length = pool_balance;
+ amount = length;
+#endif
+ while( length-- ) {
+ *buffer++ = keypool[pool_readpos++];
+ if( pool_readpos >= POOLSIZE )
+ pool_readpos = 0;
+ pool_balance--;
+ }
+ if( pool_balance < 0 )
+ pool_balance = 0;
+ /* and clear the keypool */
+ memset( keypool, 0, POOLSIZE );
+#ifdef __HURD__
+ return amount;
+#endif
+ }
+}
+
+
+/****************
+ * Add LENGTH bytes of randomness from buffer to the pool.
+ * source may be used to specify the randomness source.
+ * Source is:
+ * 0 - used ony for initialization
+ * 1 - fast random poll function
+ * 2 - normal poll function
+ * 3 - used when level 2 random quality has been requested
+ * to do an extra pool seed.
+ */
+static void
+add_randomness( const void *buffer, size_t length, int source )
+{
+ const byte *p = buffer;
+
+ if( !is_initialized )
+ initialize();
+ rndstats.addbytes += length;
+ rndstats.naddbytes++;
+ while( length-- ) {
+ rndpool[pool_writepos++] = *p++;
+ if( pool_writepos >= POOLSIZE ) {
+ if( source > 1 )
+ pool_filled = 1;
+ pool_writepos = 0;
+ mix_pool(rndpool); rndstats.mixrnd++;
+ just_mixed = !length;
+ }
+ }
+}
+
+
+
+static void
+random_poll()
+{
+ rndstats.slowpolls++;
+ read_random_source( 2, POOLSIZE/5, 1 );
+}
+
+
+void
+fast_random_poll()
+{
+ static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
+ static int initialized = 0;
+
+ rndstats.fastpolls++;
+ if( !initialized ) {
+ if( !is_initialized )
+ initialize();
+ initialized = 1;
+ fnc = dynload_getfnc_fast_random_poll();
+ }
+ if( fnc ) {
+ (*fnc)( add_randomness, 1 );
+ return;
+ }
+
+ /* fall back to the generic function */
+ #if HAVE_GETHRTIME
+ { hrtime_t tv;
+ tv = gethrtime();
+ add_randomness( &tv, sizeof(tv), 1 );
+ }
+ #elif HAVE_GETTIMEOFDAY
+ { struct timeval tv;
+ if( gettimeofday( &tv, NULL ) )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+ add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
+ }
+ #elif HAVE_CLOCK_GETTIME
+ { struct timespec tv;
+ if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+ add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+ }
+ #else /* use times */
+ #ifndef HAVE_DOSISH_SYSTEM
+ { struct tms buf;
+ times( &buf );
+ add_randomness( &buf, sizeof buf, 1 );
+ }
+ #endif
+ #endif
+ #ifdef HAVE_GETRUSAGE
+ #ifndef RUSAGE_SELF
+ #ifdef __GCC__
+ #warning There is no RUSAGE_SELF on this system
+ #endif
+ #else
+ { struct rusage buf;
+ /* QNX/Neutrino does return ENOSYS - so we just ignore it and
+ * add whatever is in buf. In a chroot environment it might not
+ * work at all (i.e. because /proc/ is not accessible), so we better
+ * ognore all error codes and hope for the best
+ */
+ getrusage( RUSAGE_SELF, &buf );
+
+ add_randomness( &buf, sizeof buf, 1 );
+ memset( &buf, 0, sizeof buf );
+ }
+ #endif
+ #endif
+ /* time and clock are availabe on all systems - so
+ * we better do it just in case one of the above functions
+ * didn't work */
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 1 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 1 );
+ }
+}
+
+
+#ifndef __HURD__
+static void
+#else
+static int
+#endif
+read_random_source( int requester, size_t length, int level )
+{
+ static int (*fnc)(void (*)(const void*, size_t, int), int,
+ size_t, int) = NULL;
+#ifdef __HURD__
+ int got;
+#endif
+ if( !fnc ) {
+ if( !is_initialized )
+ initialize();
+ fnc = dynload_getfnc_gather_random();
+ if( !fnc ) {
+ faked_rng = 1;
+ fnc = gather_faked;
+ }
+ if( !requester && !length && !level )
+#ifndef __HURD__
+ return; /* init only */
+#else
+ return 0;
+#endif
+ }
+#ifndef __HURD__
+ if( (*fnc)( add_randomness, requester, length, level ) < 0 )
+ log_fatal("No way to gather entropy for the RNG\n");
+#else
+ got = (*fnc)( add_randomness, requester, length, level );
+ if (got < 0)
+ log_fatal("No way to gather entropy for the RNG\n");
+ return got;
+#endif
+}
+
+
+static int
+gather_faked( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level )
+{
+ static int initialized=0;
+ size_t n;
+ char *buffer, *p;
+
+ if( !initialized ) {
+ log_info(_("WARNING: using insecure random number generator!!\n"));
+ tty_printf(_("The random number generator is only a kludge to let\n"
+ "it run - it is in no way a strong RNG!\n\n"
+ "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
+ initialized=1;
+ #ifdef HAVE_RAND
+ srand(make_timestamp()*getpid());
+ #else
+ srandom(make_timestamp()*getpid());
+ #endif
+ }
+ printf("WAITING FOR %i bytes.\n", length);
+ p = buffer = m_alloc( length );
+ n = length;
+ #ifdef HAVE_RAND
+ while( n-- )
+ *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
+ #else
+ while( n-- )
+ *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
+ #endif
+ add_randomness( buffer, length, requester );
+ m_free(buffer);
+ return 0; /* okay */
+}
+
diff --git a/random/gnupg-random.h b/random/gnupg-random.h
new file mode 100644
index 00000000..ee18febc
--- /dev/null
+++ b/random/gnupg-random.h
@@ -0,0 +1,47 @@
+/* random.h - random functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_RANDOM_H
+#define G10_RANDOM_H
+
+#ifndef __HURD__
+#include "types.h"
+#else
+#include "gnupg-glue.h"
+int read_pool (byte *, size_t, int);
+int readable_pool (size_t, int);
+#endif
+
+/*-- random.c --*/
+void random_dump_stats(void);
+void secure_random_alloc(void);
+void set_random_seed_file(const char *);
+void update_random_seed_file(void);
+int quick_random_gen( int onoff );
+int random_is_faked(void);
+void randomize_buffer( byte *buffer, size_t length, int level );
+byte *get_random_bits( size_t nbits, int level, int secure );
+void fast_random_poll( void );
+
+/*-- rndw32.c --*/
+#ifdef USE_STATIC_RNDW32
+void rndw32_set_dll_name( const char *name );
+#endif
+
+#endif /*G10_RANDOM_H*/
diff --git a/random/gnupg-rmd.h b/random/gnupg-rmd.h
new file mode 100644
index 00000000..2446fc7d
--- /dev/null
+++ b/random/gnupg-rmd.h
@@ -0,0 +1,38 @@
+/* rmd.h - RIPE-MD hash functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_RMD_H
+#define G10_RMD_H
+
+#ifdef __HURD__
+#include "gnupg-glue.h"
+#endif
+
+/* we need this here because random.c must have direct access */
+typedef struct {
+ u32 h0,h1,h2,h3,h4;
+ u32 nblocks;
+ byte buf[64];
+ int count;
+} RMD160_CONTEXT;
+
+void rmd160_init( RMD160_CONTEXT *hd );
+void rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer );
+
+#endif /*G10_RMD_H*/
diff --git a/random/gnupg-rmd160.c b/random/gnupg-rmd160.c
new file mode 100644
index 00000000..66107685
--- /dev/null
+++ b/random/gnupg-rmd160.c
@@ -0,0 +1,656 @@
+/* rmd160.c - RIPE-MD160
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef __HURD__
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#ifndef __HURD__
+#include "util.h"
+#include "memory.h"
+#include "rmd.h"
+#include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
+#include "dynload.h"
+
+#include "bithelp.h"
+#else
+#include "gnupg-rmd.h"
+#include "gnupg-bithelp.h"
+#endif
+
+
+/*********************************
+ * RIPEMD-160 is not patented, see (as of 25.10.97)
+ * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+ * Note that the code uses Little Endian byteorder, which is good for
+ * 386 etc, but we must add some conversion when used on a big endian box.
+ *
+ *
+ * Pseudo-code for RIPEMD-160
+ *
+ * RIPEMD-160 is an iterative hash function that operates on 32-bit words.
+ * The round function takes as input a 5-word chaining variable and a 16-word
+ * message block and maps this to a new chaining variable. All operations are
+ * defined on 32-bit words. Padding is identical to that of MD4.
+ *
+ *
+ * RIPEMD-160: definitions
+ *
+ *
+ * nonlinear functions at bit level: exor, mux, -, mux, -
+ *
+ * f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15)
+ * f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31)
+ * f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47)
+ * f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63)
+ * f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79)
+ *
+ *
+ * added constants (hexadecimal)
+ *
+ * K(j) = 0x00000000 (0 <= j <= 15)
+ * K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2))
+ * K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3))
+ * K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5))
+ * K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7))
+ * K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2))
+ * K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3))
+ * K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5))
+ * K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7))
+ * K'(j) = 0x00000000 (64 <= j <= 79)
+ *
+ *
+ * selection of message word
+ *
+ * r(j) = j (0 <= j <= 15)
+ * r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
+ * r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
+ * r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
+ * r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+ * r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
+ * r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
+ * r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
+ * r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
+ * r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+ *
+ *
+ * amount for rotate left (rol)
+ *
+ * s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
+ * s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
+ * s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
+ * s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
+ * s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+ * s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
+ * s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
+ * s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
+ * s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
+ * s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+ *
+ *
+ * initial value (hexadecimal)
+ *
+ * h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
+ * h4 = 0xC3D2E1F0;
+ *
+ *
+ * RIPEMD-160: pseudo-code
+ *
+ * It is assumed that the message after padding consists of t 16-word blocks
+ * that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
+ * The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
+ * shift (rotate) over s positions.
+ *
+ *
+ * for i := 0 to t-1 {
+ * A := h0; B := h1; C := h2; D = h3; E = h4;
+ * A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
+ * for j := 0 to 79 {
+ * T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
+ * A := E; E := D; D := rol_10(C); C := B; B := T;
+ * T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
+ [+] K'(j)) [+] E';
+ * A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
+ * }
+ * T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
+ * h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
+ * }
+ */
+
+/* Some examples:
+ * "" 9c1185a5c5e9fc54612808977ee8f548b2258d31
+ * "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
+ * "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
+ * "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36
+ * "a...z" f71c27109c692c1b56bbdceb5b9d2865b3708dbc
+ * "abcdbcde...nopq" 12a053384a9c0c88e405a06c27dcf49ada62eb2b
+ * "A...Za...z0...9" b0e20b6e3116640286ed3a87a5713079b21f5189
+ * 8 times "1234567890" 9b752e45573d4b39f4dbd3323cab82bf63326bfb
+ * 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528
+ */
+
+static void
+burn_stack (int bytes)
+{
+ char buf[150];
+
+ memset (buf, 0, sizeof buf);
+ bytes -= sizeof buf;
+ if (bytes > 0)
+ burn_stack (bytes);
+}
+
+
+
+void
+rmd160_init( RMD160_CONTEXT *hd )
+{
+ hd->h0 = 0x67452301;
+ hd->h1 = 0xEFCDAB89;
+ hd->h2 = 0x98BADCFE;
+ hd->h3 = 0x10325476;
+ hd->h4 = 0xC3D2E1F0;
+ hd->nblocks = 0;
+ hd->count = 0;
+}
+
+
+
+/****************
+ * Transform the message X which consists of 16 32-bit-words
+ */
+static void
+transform( RMD160_CONTEXT *hd, byte *data )
+{
+ u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
+ #ifdef BIG_ENDIAN_HOST
+ u32 x[16];
+ { int i;
+ byte *p2, *p1;
+ for(i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
+ p2[3] = *p1++;
+ p2[2] = *p1++;
+ p2[1] = *p1++;
+ p2[0] = *p1++;
+ }
+ }
+ #else
+ #if 0
+ u32 *x =(u32*)data;
+ #else
+ /* this version is better because it is always aligned;
+ * The performance penalty on a 586-100 is about 6% which
+ * is acceptable - because the data is more local it might
+ * also be possible that this is faster on some machines.
+ * This function (when compiled with -02 on gcc 2.7.2)
+ * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
+ * [measured with a 4MB data and "gpgm --print-md rmd160"] */
+ u32 x[16];
+ memcpy( x, data, 64 );
+ #endif
+ #endif
+
+
+#define K0 0x00000000
+#define K1 0x5A827999
+#define K2 0x6ED9EBA1
+#define K3 0x8F1BBCDC
+#define K4 0xA953FD4E
+#define KK0 0x50A28BE6
+#define KK1 0x5C4DD124
+#define KK2 0x6D703EF3
+#define KK3 0x7A6D76E9
+#define KK4 0x00000000
+#define F0(x,y,z) ( (x) ^ (y) ^ (z) )
+#define F1(x,y,z) ( ((x) & (y)) | (~(x) & (z)) )
+#define F2(x,y,z) ( ((x) | ~(y)) ^ (z) )
+#define F3(x,y,z) ( ((x) & (z)) | ((y) & ~(z)) )
+#define F4(x,y,z) ( (x) ^ ((y) | ~(z)) )
+#define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
+ a = rol(t,s) + e; \
+ c = rol(c,10); \
+ } while(0)
+
+ /* left lane */
+ a = hd->h0;
+ b = hd->h1;
+ c = hd->h2;
+ d = hd->h3;
+ e = hd->h4;
+ R( a, b, c, d, e, F0, K0, 0, 11 );
+ R( e, a, b, c, d, F0, K0, 1, 14 );
+ R( d, e, a, b, c, F0, K0, 2, 15 );
+ R( c, d, e, a, b, F0, K0, 3, 12 );
+ R( b, c, d, e, a, F0, K0, 4, 5 );
+ R( a, b, c, d, e, F0, K0, 5, 8 );
+ R( e, a, b, c, d, F0, K0, 6, 7 );
+ R( d, e, a, b, c, F0, K0, 7, 9 );
+ R( c, d, e, a, b, F0, K0, 8, 11 );
+ R( b, c, d, e, a, F0, K0, 9, 13 );
+ R( a, b, c, d, e, F0, K0, 10, 14 );
+ R( e, a, b, c, d, F0, K0, 11, 15 );
+ R( d, e, a, b, c, F0, K0, 12, 6 );
+ R( c, d, e, a, b, F0, K0, 13, 7 );
+ R( b, c, d, e, a, F0, K0, 14, 9 );
+ R( a, b, c, d, e, F0, K0, 15, 8 );
+ R( e, a, b, c, d, F1, K1, 7, 7 );
+ R( d, e, a, b, c, F1, K1, 4, 6 );
+ R( c, d, e, a, b, F1, K1, 13, 8 );
+ R( b, c, d, e, a, F1, K1, 1, 13 );
+ R( a, b, c, d, e, F1, K1, 10, 11 );
+ R( e, a, b, c, d, F1, K1, 6, 9 );
+ R( d, e, a, b, c, F1, K1, 15, 7 );
+ R( c, d, e, a, b, F1, K1, 3, 15 );
+ R( b, c, d, e, a, F1, K1, 12, 7 );
+ R( a, b, c, d, e, F1, K1, 0, 12 );
+ R( e, a, b, c, d, F1, K1, 9, 15 );
+ R( d, e, a, b, c, F1, K1, 5, 9 );
+ R( c, d, e, a, b, F1, K1, 2, 11 );
+ R( b, c, d, e, a, F1, K1, 14, 7 );
+ R( a, b, c, d, e, F1, K1, 11, 13 );
+ R( e, a, b, c, d, F1, K1, 8, 12 );
+ R( d, e, a, b, c, F2, K2, 3, 11 );
+ R( c, d, e, a, b, F2, K2, 10, 13 );
+ R( b, c, d, e, a, F2, K2, 14, 6 );
+ R( a, b, c, d, e, F2, K2, 4, 7 );
+ R( e, a, b, c, d, F2, K2, 9, 14 );
+ R( d, e, a, b, c, F2, K2, 15, 9 );
+ R( c, d, e, a, b, F2, K2, 8, 13 );
+ R( b, c, d, e, a, F2, K2, 1, 15 );
+ R( a, b, c, d, e, F2, K2, 2, 14 );
+ R( e, a, b, c, d, F2, K2, 7, 8 );
+ R( d, e, a, b, c, F2, K2, 0, 13 );
+ R( c, d, e, a, b, F2, K2, 6, 6 );
+ R( b, c, d, e, a, F2, K2, 13, 5 );
+ R( a, b, c, d, e, F2, K2, 11, 12 );
+ R( e, a, b, c, d, F2, K2, 5, 7 );
+ R( d, e, a, b, c, F2, K2, 12, 5 );
+ R( c, d, e, a, b, F3, K3, 1, 11 );
+ R( b, c, d, e, a, F3, K3, 9, 12 );
+ R( a, b, c, d, e, F3, K3, 11, 14 );
+ R( e, a, b, c, d, F3, K3, 10, 15 );
+ R( d, e, a, b, c, F3, K3, 0, 14 );
+ R( c, d, e, a, b, F3, K3, 8, 15 );
+ R( b, c, d, e, a, F3, K3, 12, 9 );
+ R( a, b, c, d, e, F3, K3, 4, 8 );
+ R( e, a, b, c, d, F3, K3, 13, 9 );
+ R( d, e, a, b, c, F3, K3, 3, 14 );
+ R( c, d, e, a, b, F3, K3, 7, 5 );
+ R( b, c, d, e, a, F3, K3, 15, 6 );
+ R( a, b, c, d, e, F3, K3, 14, 8 );
+ R( e, a, b, c, d, F3, K3, 5, 6 );
+ R( d, e, a, b, c, F3, K3, 6, 5 );
+ R( c, d, e, a, b, F3, K3, 2, 12 );
+ R( b, c, d, e, a, F4, K4, 4, 9 );
+ R( a, b, c, d, e, F4, K4, 0, 15 );
+ R( e, a, b, c, d, F4, K4, 5, 5 );
+ R( d, e, a, b, c, F4, K4, 9, 11 );
+ R( c, d, e, a, b, F4, K4, 7, 6 );
+ R( b, c, d, e, a, F4, K4, 12, 8 );
+ R( a, b, c, d, e, F4, K4, 2, 13 );
+ R( e, a, b, c, d, F4, K4, 10, 12 );
+ R( d, e, a, b, c, F4, K4, 14, 5 );
+ R( c, d, e, a, b, F4, K4, 1, 12 );
+ R( b, c, d, e, a, F4, K4, 3, 13 );
+ R( a, b, c, d, e, F4, K4, 8, 14 );
+ R( e, a, b, c, d, F4, K4, 11, 11 );
+ R( d, e, a, b, c, F4, K4, 6, 8 );
+ R( c, d, e, a, b, F4, K4, 15, 5 );
+ R( b, c, d, e, a, F4, K4, 13, 6 );
+
+ aa = a; bb = b; cc = c; dd = d; ee = e;
+
+ /* right lane */
+ a = hd->h0;
+ b = hd->h1;
+ c = hd->h2;
+ d = hd->h3;
+ e = hd->h4;
+ R( a, b, c, d, e, F4, KK0, 5, 8);
+ R( e, a, b, c, d, F4, KK0, 14, 9);
+ R( d, e, a, b, c, F4, KK0, 7, 9);
+ R( c, d, e, a, b, F4, KK0, 0, 11);
+ R( b, c, d, e, a, F4, KK0, 9, 13);
+ R( a, b, c, d, e, F4, KK0, 2, 15);
+ R( e, a, b, c, d, F4, KK0, 11, 15);
+ R( d, e, a, b, c, F4, KK0, 4, 5);
+ R( c, d, e, a, b, F4, KK0, 13, 7);
+ R( b, c, d, e, a, F4, KK0, 6, 7);
+ R( a, b, c, d, e, F4, KK0, 15, 8);
+ R( e, a, b, c, d, F4, KK0, 8, 11);
+ R( d, e, a, b, c, F4, KK0, 1, 14);
+ R( c, d, e, a, b, F4, KK0, 10, 14);
+ R( b, c, d, e, a, F4, KK0, 3, 12);
+ R( a, b, c, d, e, F4, KK0, 12, 6);
+ R( e, a, b, c, d, F3, KK1, 6, 9);
+ R( d, e, a, b, c, F3, KK1, 11, 13);
+ R( c, d, e, a, b, F3, KK1, 3, 15);
+ R( b, c, d, e, a, F3, KK1, 7, 7);
+ R( a, b, c, d, e, F3, KK1, 0, 12);
+ R( e, a, b, c, d, F3, KK1, 13, 8);
+ R( d, e, a, b, c, F3, KK1, 5, 9);
+ R( c, d, e, a, b, F3, KK1, 10, 11);
+ R( b, c, d, e, a, F3, KK1, 14, 7);
+ R( a, b, c, d, e, F3, KK1, 15, 7);
+ R( e, a, b, c, d, F3, KK1, 8, 12);
+ R( d, e, a, b, c, F3, KK1, 12, 7);
+ R( c, d, e, a, b, F3, KK1, 4, 6);
+ R( b, c, d, e, a, F3, KK1, 9, 15);
+ R( a, b, c, d, e, F3, KK1, 1, 13);
+ R( e, a, b, c, d, F3, KK1, 2, 11);
+ R( d, e, a, b, c, F2, KK2, 15, 9);
+ R( c, d, e, a, b, F2, KK2, 5, 7);
+ R( b, c, d, e, a, F2, KK2, 1, 15);
+ R( a, b, c, d, e, F2, KK2, 3, 11);
+ R( e, a, b, c, d, F2, KK2, 7, 8);
+ R( d, e, a, b, c, F2, KK2, 14, 6);
+ R( c, d, e, a, b, F2, KK2, 6, 6);
+ R( b, c, d, e, a, F2, KK2, 9, 14);
+ R( a, b, c, d, e, F2, KK2, 11, 12);
+ R( e, a, b, c, d, F2, KK2, 8, 13);
+ R( d, e, a, b, c, F2, KK2, 12, 5);
+ R( c, d, e, a, b, F2, KK2, 2, 14);
+ R( b, c, d, e, a, F2, KK2, 10, 13);
+ R( a, b, c, d, e, F2, KK2, 0, 13);
+ R( e, a, b, c, d, F2, KK2, 4, 7);
+ R( d, e, a, b, c, F2, KK2, 13, 5);
+ R( c, d, e, a, b, F1, KK3, 8, 15);
+ R( b, c, d, e, a, F1, KK3, 6, 5);
+ R( a, b, c, d, e, F1, KK3, 4, 8);
+ R( e, a, b, c, d, F1, KK3, 1, 11);
+ R( d, e, a, b, c, F1, KK3, 3, 14);
+ R( c, d, e, a, b, F1, KK3, 11, 14);
+ R( b, c, d, e, a, F1, KK3, 15, 6);
+ R( a, b, c, d, e, F1, KK3, 0, 14);
+ R( e, a, b, c, d, F1, KK3, 5, 6);
+ R( d, e, a, b, c, F1, KK3, 12, 9);
+ R( c, d, e, a, b, F1, KK3, 2, 12);
+ R( b, c, d, e, a, F1, KK3, 13, 9);
+ R( a, b, c, d, e, F1, KK3, 9, 12);
+ R( e, a, b, c, d, F1, KK3, 7, 5);
+ R( d, e, a, b, c, F1, KK3, 10, 15);
+ R( c, d, e, a, b, F1, KK3, 14, 8);
+ R( b, c, d, e, a, F0, KK4, 12, 8);
+ R( a, b, c, d, e, F0, KK4, 15, 5);
+ R( e, a, b, c, d, F0, KK4, 10, 12);
+ R( d, e, a, b, c, F0, KK4, 4, 9);
+ R( c, d, e, a, b, F0, KK4, 1, 12);
+ R( b, c, d, e, a, F0, KK4, 5, 5);
+ R( a, b, c, d, e, F0, KK4, 8, 14);
+ R( e, a, b, c, d, F0, KK4, 7, 6);
+ R( d, e, a, b, c, F0, KK4, 6, 8);
+ R( c, d, e, a, b, F0, KK4, 2, 13);
+ R( b, c, d, e, a, F0, KK4, 13, 6);
+ R( a, b, c, d, e, F0, KK4, 14, 5);
+ R( e, a, b, c, d, F0, KK4, 0, 15);
+ R( d, e, a, b, c, F0, KK4, 3, 13);
+ R( c, d, e, a, b, F0, KK4, 9, 11);
+ R( b, c, d, e, a, F0, KK4, 11, 11);
+
+
+ t = hd->h1 + d + cc;
+ hd->h1 = hd->h2 + e + dd;
+ hd->h2 = hd->h3 + a + ee;
+ hd->h3 = hd->h4 + b + aa;
+ hd->h4 = hd->h0 + c + bb;
+ hd->h0 = t;
+}
+
+
+/* Update the message digest with the contents
+ * of INBUF with length INLEN.
+ */
+static void
+rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
+{
+ if( hd->count == 64 ) { /* flush the buffer */
+ transform( hd, hd->buf );
+ burn_stack (108+5*sizeof(void*));
+ hd->count = 0;
+ hd->nblocks++;
+ }
+ if( !inbuf )
+ return;
+ if( hd->count ) {
+ for( ; inlen && hd->count < 64; inlen-- )
+ hd->buf[hd->count++] = *inbuf++;
+ rmd160_write( hd, NULL, 0 );
+ if( !inlen )
+ return;
+ }
+
+ while( inlen >= 64 ) {
+ transform( hd, inbuf );
+ hd->count = 0;
+ hd->nblocks++;
+ inlen -= 64;
+ inbuf += 64;
+ }
+ burn_stack (108+5*sizeof(void*));
+ for( ; inlen && hd->count < 64; inlen-- )
+ hd->buf[hd->count++] = *inbuf++;
+}
+
+/****************
+ * Apply the rmd160 transform function on the buffer which must have
+ * a length 64 bytes. Do not use this function together with the
+ * other functions, use rmd160_init to initialize internal variables.
+ * Returns: 16 bytes in buffer with the mixed contentes of buffer.
+ */
+void
+rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer )
+{
+ char *p = buffer;
+ transform( hd, buffer );
+ #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ #undef X
+}
+
+
+/* The routine terminates the computation
+ */
+
+static void
+rmd160_final( RMD160_CONTEXT *hd )
+{
+ u32 t, msb, lsb;
+ byte *p;
+
+ rmd160_write(hd, NULL, 0); /* flush */;
+
+ t = hd->nblocks;
+ /* multiply by 64 to make a byte count */
+ lsb = t << 6;
+ msb = t >> 26;
+ /* add the count */
+ t = lsb;
+ if( (lsb += hd->count) < t )
+ msb++;
+ /* multiply by 8 to make a bit count */
+ t = lsb;
+ lsb <<= 3;
+ msb <<= 3;
+ msb |= t >> 29;
+
+ if( hd->count < 56 ) { /* enough room */
+ hd->buf[hd->count++] = 0x80; /* pad */
+ while( hd->count < 56 )
+ hd->buf[hd->count++] = 0; /* pad */
+ }
+ else { /* need one extra block */
+ hd->buf[hd->count++] = 0x80; /* pad character */
+ while( hd->count < 64 )
+ hd->buf[hd->count++] = 0;
+ rmd160_write(hd, NULL, 0); /* flush */;
+ memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+ }
+ /* append the 64 bit count */
+ hd->buf[56] = lsb ;
+ hd->buf[57] = lsb >> 8;
+ hd->buf[58] = lsb >> 16;
+ hd->buf[59] = lsb >> 24;
+ hd->buf[60] = msb ;
+ hd->buf[61] = msb >> 8;
+ hd->buf[62] = msb >> 16;
+ hd->buf[63] = msb >> 24;
+ transform( hd, hd->buf );
+ burn_stack (108+5*sizeof(void*));
+
+ p = hd->buf;
+ #ifdef BIG_ENDIAN_HOST
+ #define X(a) do { *p++ = hd->h##a ; *p++ = hd->h##a >> 8; \
+ *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
+ #else /* little endian */
+ #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+ #endif
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ #undef X
+}
+
+static byte *
+rmd160_read( RMD160_CONTEXT *hd )
+{
+ return hd->buf;
+}
+
+
+
+/****************
+ * Shortcut functions which puts the hash value of the supplied buffer
+ * into outbuf which must have a size of 20 bytes.
+ */
+void
+rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
+{
+ RMD160_CONTEXT hd;
+
+ rmd160_init( &hd );
+ rmd160_write( &hd, (byte*)buffer, length );
+ rmd160_final( &hd );
+ memcpy( outbuf, hd.buf, 20 );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ */
+static const char *
+rmd160_get_info( int algo, size_t *contextsize,
+ byte **r_asnoid, int *r_asnlen, int *r_mdlen,
+ void (**r_init)( void *c ),
+ void (**r_write)( void *c, byte *buf, size_t nbytes ),
+ void (**r_final)( void *c ),
+ byte *(**r_read)( void *c )
+ )
+{
+ static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
+ { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
+ 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
+
+ if( algo != 3 )
+ return NULL;
+
+ *contextsize = sizeof(RMD160_CONTEXT);
+ *r_asnoid = asn;
+ *r_asnlen = DIM(asn);
+ *r_mdlen = 20;
+ *(void (**)(RMD160_CONTEXT *))r_init = rmd160_init;
+ *(void (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+ *(void (**)(RMD160_CONTEXT *))r_final = rmd160_final;
+ *(byte *(**)(RMD160_CONTEXT *))r_read = rmd160_read;
+
+ return "RIPEMD160";
+}
+
+
+#ifndef IS_MODULE
+static
+#endif
+const char * const gnupgext_version = "RMD160 ($Revision: 1.17.2.4 $)";
+
+static struct {
+ int class;
+ int version;
+ int value;
+ void (*func)(void);
+} func_table[] = {
+ { 10, 1, 0, (void(*)(void))rmd160_get_info },
+ { 11, 1, 3 },
+};
+
+
+#ifndef IS_MODULE
+static
+#endif
+void *
+gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
+{
+ void *ret;
+ int i = *sequence;
+
+ do {
+ if( i >= DIM(func_table) || i < 0 ) {
+ return NULL;
+ }
+ *class = func_table[i].class;
+ *vers = func_table[i].version;
+ switch( *class ) {
+ case 11:
+ case 21:
+ case 31:
+ ret = &func_table[i].value;
+ break;
+ default:
+ ret = func_table[i].func;
+ break;
+ }
+ i++;
+ } while( what && what != *class );
+
+ *sequence = i;
+ return ret;
+}
+
+
+
+#ifndef __HURD__
+#ifndef IS_MODULE
+void
+rmd160_constructor(void)
+{
+ register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
+}
+#endif
+#endif
diff --git a/random/random.c b/random/random.c
new file mode 100644
index 00000000..0ae31f5f
--- /dev/null
+++ b/random/random.c
@@ -0,0 +1,624 @@
+/* random.c - A single-file translator providing random data
+ Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <hurd/startup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <cthreads.h>
+#include <rwlock.h>
+
+#include <version.h>
+
+#include "random.h"
+#include "gnupg-random.h"
+
+/* Our control port. */
+struct trivfs_control *fsys;
+
+int read_blocked; /* For read and select. */
+struct condition wait; /* For read and select. */
+struct condition select_alert; /* For read and select. */
+
+
+/* The quality of randomness we provide.
+ 0: Very weak randomness based on time() and getrusage().
+ No external random data is used.
+ 1: Pseudo random numbers based on all available real random
+ numbers.
+ 2: Strong random numbers with a somewhat guaranteed entropy.
+*/
+#define DEFAULT_LEVEL 2
+static int level = DEFAULT_LEVEL;
+
+/* Name of file to use as seed. */
+static char *seed_file;
+
+/* The random bytes we collected. */
+char gatherbuf[GATHERBUFSIZE];
+
+/* The current positions in gatherbuf[]. */
+int gatherrpos;
+int gatherwpos;
+
+/* XXX Yuk Yuk. */
+#define POOLSIZE 600
+
+/* Take up to length bytes from gather_random if available. If
+ nothing is available, sleep until something becomes available.
+ Must be called with global_lock held. */
+int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level )
+{
+ int avail = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
+ int first = GATHERBUFSIZE - gatherrpos;
+ int second = length - first;
+
+ /* If level is zero, we should not block and not add anything
+ to the pool. */
+ if( !level )
+ return 0;
+
+ /* io_read() should guarantee that there is always data available. */
+ if (level == 2)
+ assert (avail);
+
+ if (length > avail)
+ length = avail;
+
+ if (first > length)
+ first = length;
+ (*add) (&gatherbuf[gatherrpos], first, requester);
+ gatherrpos = (gatherrpos + first) % GATHERBUFSIZE;
+ if (second > 0)
+ {
+ (*add) (&gatherbuf[gatherrpos], second, requester);
+ gatherrpos += second;
+ }
+ return length;
+}
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (random);
+
+/* This lock protects the GnuPG code. */
+static struct mutex global_lock;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= (S_IFCHR);
+ st->st_size = 0;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ update_random_seed_file ();
+ exit (0);
+}
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ data_t *data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+
+ if (amount > 0)
+ {
+ while (readable_pool (amount, level) == 0)
+ {
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+ read_blocked = 1;
+ if (hurd_condition_wait (&wait, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ /* See term/users.c for possible race? */
+ }
+
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+
+ amount = read_pool ((byte *) *data, amount, level);
+ }
+ *data_len = amount;
+
+ /* Set atime, see term/users.c */
+
+ mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they receive more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ data_t data,
+ mach_msg_type_number_t datalen,
+ loff_t offset,
+ mach_msg_type_number_t *amount)
+{
+ int i = 0;
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+
+ while (i < datalen)
+ {
+ gatherbuf[gatherwpos] = data[i++];
+ gatherwpos = (gatherwpos + 1) % GATHERBUFSIZE;
+ if (gatherrpos == gatherwpos)
+ /* Overrun. */
+ gatherrpos = (gatherrpos + 1) % GATHERBUFSIZE;
+ }
+ *amount = datalen;
+
+ if (datalen > 0 && read_blocked)
+ {
+ read_blocked = 0;
+ condition_broadcast (&wait);
+ }
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t *amount)
+{
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+
+ /* XXX: Before initialization, the amount depends on the amount we
+ want to read. Assume some medium value. */
+ *amount = readable_pool (POOLSIZE/2, level);
+
+ mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ /* We only deal with SELECT_READ and SELECT_WRITE here. */
+ if (*type & ~(SELECT_READ | SELECT_WRITE))
+ return EINVAL;
+
+ if (*type == 0)
+ return 0;
+
+ mutex_lock (&global_lock);
+
+ while (1)
+ {
+ /* XXX Before initialization, readable_pool depends on length. */
+ int avail = readable_pool (POOLSIZE/2, level);
+
+ if (avail != 0 || *type & SELECT_WRITE)
+ {
+ *type = (avail ? SELECT_READ : 0) | (*type & SELECT_WRITE);
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ ports_interrupt_self_on_port_death (cred, reply);
+ read_blocked = 1;
+
+ if (hurd_condition_wait (&select_alert, &global_lock))
+ {
+ *type = 0;
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ loff_t offs, int whence, loff_t *new_offs)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Not seekable. */
+ return ESPIPE;
+}
+
+/* Change the size of the file. If the size increases, new blocks are
+ zero-filled. After successful return, it is safe to reference mapped
+ areas of the file up to NEW_SIZE. */
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ loff_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map(struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ mach_port_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+
+int
+random_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (trivfs_demuxer (inp, outp)
+ || startup_notify_server (inp, outp));
+}
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"weak", 'w', 0, 0, "Output weak pseudo random data"},
+ {"fast", 'f', 0, 0, "Output cheap random data fast"},
+ {"secure", 's', 0, 0, "Output cryptographically secure random"},
+ {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'w':
+ {
+ level = 0;
+ break;
+ }
+ case 'f':
+ {
+ level = 1;
+ break;
+ }
+ case 's':
+ {
+ level = 2;
+ break;
+ }
+ case 'S':
+ {
+ seed_file = strdup (arg);
+ set_random_seed_file (arg);
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err = 0;
+ char *opt;
+
+ mutex_lock (&global_lock);
+ switch (level)
+ {
+ case 0:
+ {
+ opt = "--weak";
+ break;
+ }
+ case 1:
+ {
+ opt = "--fast";
+ break;
+ }
+ default:
+ {
+ opt = "--secure";
+ break;
+ }
+ }
+ if (level != DEFAULT_LEVEL)
+ err = argz_add (argz, argz_len, opt);
+
+ if (!err && seed_file)
+ {
+ if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
+ err = ENOMEM;
+ else
+ {
+ err = argz_add (argz, argz_len, opt);
+ free (opt);
+ }
+ }
+ mutex_unlock (&global_lock);
+
+ return err;
+}
+
+static struct argp random_argp =
+{ options, parse_opt, 0,
+ "A translator providing random output." };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &random_argp;
+
+struct port_class *shutdown_notify_class;
+
+/* The system is going down; destroy all the extant port rights. That
+ will cause net channels and such to close promptly. */
+error_t
+S_startup_dosync (mach_port_t handle)
+{
+ struct port_info *inpi = ports_lookup_port (fsys->pi.bucket, handle,
+ shutdown_notify_class);
+
+ if (!inpi)
+ return EOPNOTSUPP;
+
+ update_random_seed_file ();
+ return 0;
+}
+
+void
+sigterm_handler (int signo)
+{
+ update_random_seed_file ();
+ signal (SIGTERM, SIG_DFL);
+ raise (SIGTERM);
+}
+
+void
+arrange_shutdown_notification ()
+{
+ error_t err;
+ mach_port_t initport, notify;
+ process_t procserver;
+ struct port_info *pi;
+
+ shutdown_notify_class = ports_create_class (0, 0);
+
+ signal (SIGTERM, sigterm_handler);
+
+ /* Arrange to get notified when the system goes down,
+ but if we fail for some reason, just silently give up. No big deal. */
+
+ err = ports_create_port (shutdown_notify_class, fsys->pi.bucket,
+ sizeof (struct port_info), &pi);
+ if (err)
+ return;
+
+ procserver = getproc ();
+ if (!procserver)
+ return;
+
+ err = proc_getmsgport (procserver, 1, &initport);
+ mach_port_deallocate (mach_task_self (), procserver);
+ if (err)
+ return;
+
+ notify = ports_get_send_right (pi);
+ ports_port_deref (pi);
+ startup_request_notification (initport, notify,
+ MACH_MSG_TYPE_MAKE_SEND,
+ program_invocation_short_name);
+ mach_port_deallocate (mach_task_self (), notify);
+ mach_port_deallocate (mach_task_self (), initport);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+
+ /* Initialize the lock that will protect everything.
+ We must do this before argp_parse, because parse_opt (above) will
+ use the lock. */
+ mutex_init (&global_lock);
+
+ /* The conditions are used to implement proper read/select
+ behaviour. */
+ condition_init (&wait);
+ condition_init (&select_alert);
+ condition_implies (&wait, &select_alert);
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&random_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ arrange_shutdown_notification ();
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,
+ 10 * 1000, /* idle thread */
+ 10 * 60 * 1000, /* idle server */
+ 0);
+ return 0;
+}
diff --git a/random/random.h b/random/random.h
new file mode 100644
index 00000000..a38a4177
--- /dev/null
+++ b/random/random.h
@@ -0,0 +1,32 @@
+/* random.c - A single-file translator providing random data
+ Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef __RANDOM_H__
+#define __RANDOM_H__
+
+/* How many random bytes to gather at most.
+ XXX: Should be at least POOLSIZE. */
+#define GATHERBUFSIZE 32768
+
+/* The random bytes we collected. */
+extern char gatherbuf[GATHERBUFSIZE];
+
+/* The current positions in gatherbuf[]. */
+extern int gatherrpos;
+extern int gatherwpos;
+
+#endif
diff --git a/tests/test-17.c b/tests/test-17.c
new file mode 100644
index 00000000..a8bd1503
--- /dev/null
+++ b/tests/test-17.c
@@ -0,0 +1,57 @@
+/* Test that the key reuse inside libpthread does not cause thread
+ specific values to persist. */
+
+#define _GNU_SOURCE 1
+
+#include <pthread.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+void
+work (int iter)
+{
+ error_t err;
+ pthread_key_t key1;
+ pthread_key_t key2;
+ void *value1;
+ void *value2;
+
+ printf ("work/%d: start\n", iter);
+ err = pthread_key_create (&key1, NULL);
+ assert (err == 0);
+ err = pthread_key_create (&key2, NULL);
+ assert (err == 0);
+
+ value1 = pthread_getspecific (key1);
+ value2 = pthread_getspecific (key2);
+ printf ("work/%d: pre-setspecific: %p,%p\n", iter, value1, value2);
+ assert (value1 == NULL);
+ assert (value2 == NULL);
+ err = pthread_setspecific (key1, (void *)(0x100 + iter));
+ assert (err == 0);
+ err = pthread_setspecific (key2, (void *)(0x200 + iter));
+ assert (err == 0);
+
+ value1 = pthread_getspecific (key1);
+ value2 = pthread_getspecific (key2);
+ printf ("work/%d: post-setspecific: %p,%p\n", iter, value1, value2);
+ assert (value1 == (void *)(0x100 + iter));
+ assert (value2 == (void *)(0x200 + iter));
+
+ err = pthread_key_delete (key1);
+ assert (err == 0);
+ err = pthread_key_delete (key2);
+ assert (err == 0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ work (i + 1);
+
+ return 0;
+}
diff --git a/tests/test-__pthread_destroy_specific-skip.c b/tests/test-__pthread_destroy_specific-skip.c
new file mode 100644
index 00000000..b2c4c0bd
--- /dev/null
+++ b/tests/test-__pthread_destroy_specific-skip.c
@@ -0,0 +1,83 @@
+/* Check that __pthread_destroy_specific works correctly if it has to skip
+ unused slots. */
+
+#define _GNU_SOURCE
+
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+#define N_k 42
+
+static volatile int v;
+
+static void
+d (void *x)
+{
+ int *i = (int *) x;
+
+ if (v != *i)
+ error (1, 0, "FAILED %d %d", v, *i);
+ v += 2;
+
+ printf ("%s %d\n", __FUNCTION__, *i);
+ fflush (stdout);
+}
+
+static void *
+test (void *x)
+{
+ pthread_key_t k[N_k];
+ static int k_v[N_k];
+
+ int err, i;
+
+ for (i = 0; i < N_k; i += 1)
+ {
+ err = pthread_key_create (&k[i], &d);
+ if (err != 0)
+ error (1, err, "pthread_key_create %d", i);
+ }
+
+ for (i = 0; i < N_k; i += 1)
+ {
+ k_v[i] = i;
+ err = pthread_setspecific (k[i], &k_v[i]);
+ if (err != 0)
+ error (1, err, "pthread_setspecific %d", i);
+ }
+
+ /* Delete every even key. */
+ for (i = 0; i < N_k; i += 2)
+ {
+ err = pthread_key_delete (k[i]);
+ if (err != 0)
+ error (1, err, "pthread_key_delete %d", i);
+ }
+
+ v = 1;
+ pthread_exit (NULL);
+
+ return NULL;
+}
+
+
+int main(void)
+{
+ pthread_t tid;
+ int err;
+
+ err = pthread_create (&tid, 0, test, NULL);
+ if (err != 0)
+ error (1, err, "pthread_create");
+
+ err = pthread_join(tid, NULL);
+ if (err)
+ error (1, err, "pthread_join");
+
+ if (v != N_k + 1)
+ error (1, 0, "FAILED END %d %d", v, N_k + 1);
+
+ return 0;
+}