summaryrefslogtreecommitdiff
path: root/libpthread/pthread
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/pthread')
-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
19 files changed, 1600 insertions, 0 deletions
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);
+}