Fix pthreads functions that should return ESRCH.
imgtec pointed out that pthread_kill(3) was broken, but most of the
other functions that ought to return ESRCH for invalid/exited threads
were equally broken.
Change-Id: I96347f6195549aee0c72dc39063e6c5d06d2e01f
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index 5848215..e30fa9d 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -59,55 +59,6 @@
#define __likely(cond) __builtin_expect(!!(cond), 1)
#define __unlikely(cond) __builtin_expect(!!(cond), 0)
-__LIBC_HIDDEN__ pthread_internal_t* gThreadList = NULL;
-__LIBC_HIDDEN__ pthread_mutex_t gThreadListLock = PTHREAD_MUTEX_INITIALIZER;
-
-static void _pthread_internal_remove_locked(pthread_internal_t* thread) {
- if (thread->next != NULL) {
- thread->next->prev = thread->prev;
- }
- if (thread->prev != NULL) {
- thread->prev->next = thread->next;
- } else {
- gThreadList = thread->next;
- }
-
- // The main thread is not heap-allocated. See __libc_init_tls for the declaration,
- // and __libc_init_common for the point where it's added to the thread list.
- if (thread->allocated_on_heap) {
- free(thread);
- }
-}
-
-static void _pthread_internal_remove(pthread_internal_t* thread) {
- pthread_mutex_lock(&gThreadListLock);
- _pthread_internal_remove_locked(thread);
- pthread_mutex_unlock(&gThreadListLock);
-}
-
-__LIBC_ABI_PRIVATE__ void _pthread_internal_add(pthread_internal_t* thread) {
- pthread_mutex_lock(&gThreadListLock);
-
- // We insert at the head.
- thread->next = gThreadList;
- thread->prev = NULL;
- if (thread->next != NULL) {
- thread->next->prev = thread;
- }
- gThreadList = thread;
-
- pthread_mutex_unlock(&gThreadListLock);
-}
-
-__LIBC_ABI_PRIVATE__ pthread_internal_t*
-__get_thread(void)
-{
- void** tls = (void**)__get_tls();
-
- return (pthread_internal_t*) tls[TLS_SLOT_THREAD_ID];
-}
-
-
void*
__get_stack_base(int *p_stack_size)
{
@@ -166,11 +117,10 @@
// if the thread is detached, destroy the pthread_internal_t
// otherwise, keep it in memory and signal any joiners.
+ pthread_mutex_lock(&gThreadListLock);
if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
- _pthread_internal_remove(thread);
+ _pthread_internal_remove_locked(thread);
} else {
- pthread_mutex_lock(&gThreadListLock);
-
/* make sure that the thread struct doesn't have stale pointers to a stack that
* will be unmapped after the exit call below.
*/
@@ -198,8 +148,8 @@
} else {
thread->join_count = -1; /* zombie thread */
}
- pthread_mutex_unlock(&gThreadListLock);
}
+ pthread_mutex_unlock(&gThreadListLock);
sigfillset(&mask);
sigdelset(&mask, SIGSEGV);
@@ -212,133 +162,6 @@
_exit_with_stack_teardown(stack_base, stack_size, (int)retval);
}
-int pthread_join(pthread_t thid, void ** ret_val)
-{
- pthread_internal_t* thread = (pthread_internal_t*)thid;
- if (thid == pthread_self()) {
- return EDEADLK;
- }
-
- // check that the thread still exists and is not detached
- pthread_mutex_lock(&gThreadListLock);
-
- for (thread = gThreadList; thread != NULL; thread = thread->next) {
- if (thread == (pthread_internal_t*)thid) {
- goto FoundIt;
- }
- }
-
- pthread_mutex_unlock(&gThreadListLock);
- return ESRCH;
-
-FoundIt:
- if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
- pthread_mutex_unlock(&gThreadListLock);
- return EINVAL;
- }
-
- /* wait for thread death when needed
- *
- * if the 'join_count' is negative, this is a 'zombie' thread that
- * is already dead and without stack/TLS
- *
- * otherwise, we need to increment 'join-count' and wait to be signaled
- */
- int count = thread->join_count;
- if (count >= 0) {
- thread->join_count += 1;
- pthread_cond_wait( &thread->join_cond, &gThreadListLock );
- count = --thread->join_count;
- }
- if (ret_val) {
- *ret_val = thread->return_value;
- }
-
- /* remove thread descriptor when we're the last joiner or when the
- * thread was already a zombie.
- */
- if (count <= 0) {
- _pthread_internal_remove_locked(thread);
- }
- pthread_mutex_unlock(&gThreadListLock);
- return 0;
-}
-
-int pthread_detach( pthread_t thid )
-{
- pthread_internal_t* thread;
- int result = 0;
-
- pthread_mutex_lock(&gThreadListLock);
- for (thread = gThreadList; thread != NULL; thread = thread->next) {
- if (thread == (pthread_internal_t*)thid) {
- goto FoundIt;
- }
- }
-
- result = ESRCH;
- goto Exit;
-
-FoundIt:
- if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
- result = EINVAL; // Already detached.
- goto Exit;
- }
-
- if (thread->join_count > 0) {
- result = 0; // Already being joined; silently do nothing, like glibc.
- goto Exit;
- }
-
- thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED;
-
-Exit:
- pthread_mutex_unlock(&gThreadListLock);
- return result;
-}
-
-pthread_t pthread_self(void)
-{
- return (pthread_t)__get_thread();
-}
-
-int pthread_equal(pthread_t one, pthread_t two)
-{
- return (one == two ? 1 : 0);
-}
-
-int pthread_getschedparam(pthread_t thid, int * policy,
- struct sched_param * param)
-{
- int old_errno = errno;
-
- pthread_internal_t * thread = (pthread_internal_t *)thid;
- int err = sched_getparam(thread->tid, param);
- if (!err) {
- *policy = sched_getscheduler(thread->tid);
- } else {
- err = errno;
- errno = old_errno;
- }
- return err;
-}
-
-int pthread_setschedparam(pthread_t thid, int policy,
- struct sched_param const * param)
-{
- pthread_internal_t * thread = (pthread_internal_t *)thid;
- int old_errno = errno;
- int ret;
-
- ret = sched_setscheduler(thread->tid, policy, param);
- if (ret < 0) {
- ret = errno;
- errno = old_errno;
- }
- return ret;
-}
-
-
/* a mutex is implemented as a 32-bit integer holding the following fields
*
* bits: name description
@@ -1370,42 +1193,10 @@
}
-// man says this should be in <linux/unistd.h>, but it isn't
-extern int tgkill(int tgid, int tid, int sig);
-
-int pthread_kill(pthread_t tid, int sig)
-{
- int ret;
- int old_errno = errno;
- pthread_internal_t * thread = (pthread_internal_t *)tid;
-
- ret = tgkill(getpid(), thread->tid, sig);
- if (ret < 0) {
- ret = errno;
- errno = old_errno;
- }
-
- return ret;
-}
-
-
-int pthread_getcpuclockid(pthread_t tid, clockid_t *clockid)
-{
- const int CLOCK_IDTYPE_BITS = 3;
- pthread_internal_t* thread = (pthread_internal_t*)tid;
-
- if (!thread)
- return ESRCH;
-
- *clockid = CLOCK_THREAD_CPUTIME_ID | (thread->tid << CLOCK_IDTYPE_BITS);
- return 0;
-}
-
-
/* NOTE: this implementation doesn't support a init function that throws a C++ exception
* or calls fork()
*/
-int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) )
+int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) )
{
volatile pthread_once_t* ocptr = once_control;