diff options
Diffstat (limited to 'pthread')
-rw-r--r-- | pthread/cthreads-compat.c | 8 | ||||
-rw-r--r-- | pthread/pt-alloc.c | 56 | ||||
-rw-r--r-- | pthread/pt-create.c | 4 | ||||
-rw-r--r-- | pthread/pt-dealloc.c | 33 | ||||
-rw-r--r-- | pthread/pt-detach.c | 10 | ||||
-rw-r--r-- | pthread/pt-exit.c | 12 | ||||
-rw-r--r-- | pthread/pt-getattr.c | 49 | ||||
-rw-r--r-- | pthread/pt-internal.h | 49 | ||||
-rw-r--r-- | pthread/pt-join.c | 15 | ||||
-rw-r--r-- | pthread/pt-self.c | 7 | ||||
-rw-r--r-- | pthread/pt-setcancelstate.c | 3 | ||||
-rw-r--r-- | pthread/pt-setcanceltype.c | 3 | ||||
-rw-r--r-- | pthread/pt-yield.c | 26 |
13 files changed, 197 insertions, 78 deletions
diff --git a/pthread/cthreads-compat.c b/pthread/cthreads-compat.c index ccea03c..e0536ef 100644 --- a/pthread/cthreads-compat.c +++ b/pthread/cthreads-compat.c @@ -1,5 +1,5 @@ /* Compatibility routines for cthreads. - Copyright (C) 2000, 2002 Free Software Foundation, Inc. + 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 @@ -20,7 +20,11 @@ #include <assert.h> #include <pthread.h> -#include <cthreads.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) diff --git a/pthread/pt-alloc.c b/pthread/pt-alloc.c index 30dcede..6af2da9 100644 --- a/pthread/pt-alloc.c +++ b/pthread/pt-alloc.c @@ -1,5 +1,5 @@ /* Allocate a new thread structure. - Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc. + 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 @@ -25,8 +25,6 @@ #include <pt-internal.h> -#include <bits/atomic.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." */ @@ -44,9 +42,9 @@ 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. */ -__atomicptr_t __pthread_free_threads; +struct __pthread *__pthread_free_threads; +pthread_mutex_t __pthread_free_threads_lock; static inline error_t initialize_pthread (struct __pthread *new, int recycling) @@ -94,33 +92,35 @@ __pthread_alloc (struct __pthread **pthread) int max_threads; int new_max_threads; - /* Try to re-use a thread structure before creating a new one. */ - while ((new = (struct __pthread *)__pthread_free_threads)) + pthread_mutex_lock (&__pthread_free_threads_lock); + for (new = __pthread_free_threads; new; new = new->next) { - if (__atomicptr_compare_and_swap (&__pthread_free_threads, - 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) { - /* Yes, we managed to get one. The thread number in the - thread structure still refers to the correct slot. */ - err = initialize_pthread (new, 1); - if (err) - /* An error occured, however, we cannot just free NEW as - there may be resources attached to it. We must return - it to the free list. */ - while (1) - { - new->next = (struct __pthread *)__pthread_free_threads; - if (__atomicptr_compare_and_swap (&__pthread_free_threads, - new->next, new)) - break; - } - - if (! err) - *pthread = new; - - return err; + __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)); diff --git a/pthread/pt-create.c b/pthread/pt-create.c index 0d66d6c..346c697 100644 --- a/pthread/pt-create.c +++ b/pthread/pt-create.c @@ -45,6 +45,8 @@ entry_point (void *(*start_routine)(void *), void *arg) uselocale (LC_GLOBAL_LOCALE); #endif + __pthread_startup (); + pthread_exit (start_routine (arg)); } @@ -204,7 +206,7 @@ __pthread_create_internal (struct __pthread **thread, failed_thread_tls_alloc: #endif /* ENABLE_TLS */ __pthread_thread_dealloc (pthread); - __pthread_thread_halt (pthread, 0); + __pthread_thread_halt (pthread); failed_thread_alloc: __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize); pthread->stack = 0; diff --git a/pthread/pt-dealloc.c b/pthread/pt-dealloc.c index 1fc7a7b..92fe1fd 100644 --- a/pthread/pt-dealloc.c +++ b/pthread/pt-dealloc.c @@ -1,5 +1,5 @@ /* Deallocate a thread structure. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -23,13 +23,12 @@ #include <pt-internal.h> -#include <bits/atomic.h> - /* List of thread structures corresponding to free thread IDs. */ -extern __atomicptr_t __pthread_free_threads; +extern struct __pthread *__pthread_free_threads; +extern pthread_mutex_t __pthread_free_threads_lock; + -/* Deallocate the thread structure for PTHREAD and the resources - associated with it. */ +/* Deallocate the thread structure for PTHREAD. */ void __pthread_dealloc (struct __pthread *pthread) { @@ -44,20 +43,22 @@ __pthread_dealloc (struct __pthread *pthread) pthread_join is completely bogus, but unfortunately allowed by the standards. */ __pthread_mutex_lock (&pthread->state_lock); - pthread->state = PTHREAD_TERMINATED; 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. */ - while (1) - { - pthread->next = (struct __pthread *)__pthread_free_threads; - if (__atomicptr_compare_and_swap (&__pthread_free_threads, - pthread->next, pthread)) - return; - } - - /* NOTREACHED */ + 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/pthread/pt-detach.c b/pthread/pt-detach.c index 42a8408..1e42c45 100644 --- a/pthread/pt-detach.c +++ b/pthread/pt-detach.c @@ -58,10 +58,20 @@ pthread_detach (pthread_t thread) __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; diff --git a/pthread/pt-exit.c b/pthread/pt-exit.c index 941526a..c01efda 100644 --- a/pthread/pt-exit.c +++ b/pthread/pt-exit.c @@ -1,5 +1,5 @@ /* Thread termination. - Copyright (C) 2000, 2002, 2005, 2007 Free Software Foundation, Inc. + 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 @@ -28,14 +28,13 @@ /* Terminate the current thread and make STATUS available to any - thread that might join us. */ + thread that might join it. */ void pthread_exit (void *status) { struct __pthread *self = _pthread_self (); struct __pthread_cancelation_handler **handlers; int oldstate; - int need_dealloc; /* Run any cancelation handlers. According to POSIX, the cancellation cleanup handlers should be called with cancellation @@ -74,7 +73,6 @@ pthread_exit (void *status) if (self->tcb) _dl_deallocate_tls (self->tcb, 1); #endif /* ENABLE_TLS */ - __pthread_thread_dealloc (self); switch (self->state) { @@ -90,7 +88,8 @@ pthread_exit (void *status) deallocate our own stack. However, it will eventually be reused when this thread structure is recycled. */ __pthread_mutex_unlock (&self->state_lock); - need_dealloc = 1; + + __pthread_dealloc (self); break; @@ -107,7 +106,6 @@ pthread_exit (void *status) waiting to join us. */ pthread_cond_broadcast (&self->state_cond); __pthread_mutex_unlock (&self->state_lock); - need_dealloc = 0; break; } @@ -117,7 +115,7 @@ pthread_exit (void *status) This means that before freeing any resources, such a thread should make sure that this thread is really halted. */ - __pthread_thread_halt (self, need_dealloc); + __pthread_thread_halt (self); /* NOTREACHED */ abort (); diff --git a/pthread/pt-getattr.c b/pthread/pt-getattr.c new file mode 100644 index 0000000..24599c6 --- /dev/null +++ b/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/pthread/pt-internal.h b/pthread/pt-internal.h index 159f1cb..3f69d2d 100644 --- a/pthread/pt-internal.h +++ b/pthread/pt-internal.h @@ -1,5 +1,5 @@ /* Internal defenitions for pthreads library. - Copyright (C) 2000, 2005, 2007 Free Software Foundation, Inc. + 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 @@ -36,9 +36,13 @@ /* 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 }; @@ -128,15 +132,22 @@ __pthread_dequeue (struct __pthread *thread) } /* Iterate over QUEUE storing each element in ELEMENT. */ -#define __pthread_queue_iterate(queue, element) \ - for (element = queue; element; element = element->next) +#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 (element = queue; \ - element && ((element->prevp = 0), 1); \ - element = element->next) +#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; @@ -214,23 +225,27 @@ extern int __pthread_setup (struct __pthread *__restrict thread, 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 except don't - halt the thread itself. On return, the thread will be marked as - dead and __pthread_halt will be called. */ +/* 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. If NEED_DEALLOC is - true, the function must call __pthread_dealloc on 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); - NB: The thread executing this function may be the thread which is - being halted, thus the last action should be halting the thread - itself. */ -extern void __pthread_thread_halt (struct __pthread *thread, - int need_dealloc); +/* 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); diff --git a/pthread/pt-join.c b/pthread/pt-join.c index 698b6c9..153058b 100644 --- a/pthread/pt-join.c +++ b/pthread/pt-join.c @@ -37,7 +37,8 @@ pthread_join (pthread_t thread, void **status) return ESRCH; __pthread_mutex_lock (&pthread->state_lock); - pthread_cleanup_push (__pthread_mutex_unlock, &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); @@ -53,12 +54,20 @@ pthread_join (pthread_t thread, void **status) if (status) *status = pthread->status; - /* Make sure nobody can reference it anymore, and mark it as - terminated. */ + /* 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; diff --git a/pthread/pt-self.c b/pthread/pt-self.c index e14fe1e..4976864 100644 --- a/pthread/pt-self.c +++ b/pthread/pt-self.c @@ -1,5 +1,5 @@ /* Get calling thread's ID. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -25,5 +25,8 @@ pthread_t pthread_self (void) { - return _pthread_self()->thread; + struct __pthread *self = _pthread_self (); + assert (self); + + return self->thread; } diff --git a/pthread/pt-setcancelstate.c b/pthread/pt-setcancelstate.c index ded5892..e2d8183 100644 --- a/pthread/pt-setcancelstate.c +++ b/pthread/pt-setcancelstate.c @@ -35,7 +35,8 @@ pthread_setcancelstate (int state, int *oldstate) break; } - *oldstate = p->cancel_state; + if (oldstate) + *oldstate = p->cancel_state; p->cancel_state = state; return 0; diff --git a/pthread/pt-setcanceltype.c b/pthread/pt-setcanceltype.c index 9511c99..3ce4259 100644 --- a/pthread/pt-setcanceltype.c +++ b/pthread/pt-setcanceltype.c @@ -35,7 +35,8 @@ pthread_setcanceltype (int type, int *oldtype) break; } - *oldtype = p->cancel_type; + if (oldtype) + *oldtype = p->cancel_type; p->cancel_type = type; return 0; diff --git a/pthread/pt-yield.c b/pthread/pt-yield.c new file mode 100644 index 0000000..27848bb --- /dev/null +++ b/pthread/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 (); +} |