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;
diff --git a/libc/bionic/pthread_accessor.h b/libc/bionic/pthread_accessor.h
new file mode 100644
index 0000000..eb8c350
--- /dev/null
+++ b/libc/bionic/pthread_accessor.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PTHREAD_ACCESSOR_H
+#define PTHREAD_ACCESSOR_H
+
+#include <pthread.h>
+
+#include "pthread_internal.h"
+
+class pthread_accessor {
+ public:
+ explicit pthread_accessor(pthread_t desired_thread) {
+ Lock();
+ for (thread_ = gThreadList; thread_ != NULL; thread_ = thread_->next) {
+ if (thread_ == reinterpret_cast<pthread_internal_t*>(desired_thread)) {
+ break;
+ }
+ }
+ }
+
+ ~pthread_accessor() {
+ Unlock();
+ }
+
+ pthread_internal_t& operator*() const { return *thread_; }
+ pthread_internal_t* operator->() const { return thread_; }
+ pthread_internal_t* get() const { return thread_; }
+
+ private:
+ pthread_internal_t* thread_;
+ bool is_locked_;
+
+ void Lock() {
+ pthread_mutex_lock(&gThreadListLock);
+ is_locked_ = true;
+ }
+
+ void Unlock() {
+ if (is_locked_) {
+ is_locked_ = false;
+ thread_ = NULL;
+ pthread_mutex_unlock(&gThreadListLock);
+ }
+ }
+
+ // Disallow copy and assignment.
+ pthread_accessor(const pthread_accessor&);
+ void operator=(const pthread_accessor&);
+};
+
+#endif // PTHREAD_ACCESSOR_H
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
new file mode 100644
index 0000000..63f5809
--- /dev/null
+++ b/libc/bionic/pthread_detach.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include "pthread_accessor.h"
+
+int pthread_detach(pthread_t t) {
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
+ return EINVAL; // Already detached.
+ }
+
+ if (thread->join_count > 0) {
+ return 0; // Already being joined; silently do nothing, like glibc.
+ }
+
+ thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED;
+ return 0;
+}
diff --git a/libc/bionic/pthread_equal.cpp b/libc/bionic/pthread_equal.cpp
new file mode 100644
index 0000000..493b2c2
--- /dev/null
+++ b/libc/bionic/pthread_equal.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+
+int pthread_equal(pthread_t lhs, pthread_t rhs) {
+ return (lhs == rhs ? 1 : 0);
+}
diff --git a/libc/bionic/pthread_getcpuclockid.cpp b/libc/bionic/pthread_getcpuclockid.cpp
new file mode 100644
index 0000000..10046ba
--- /dev/null
+++ b/libc/bionic/pthread_getcpuclockid.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include "pthread_accessor.h"
+
+int pthread_getcpuclockid(pthread_t t, clockid_t* clockid) {
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ enum { CLOCK_IDTYPE_BITS = 3 };
+ *clockid = CLOCK_THREAD_CPUTIME_ID | (thread->tid << CLOCK_IDTYPE_BITS);
+ return 0;
+}
diff --git a/libc/bionic/pthread_getschedparam.cpp b/libc/bionic/pthread_getschedparam.cpp
new file mode 100644
index 0000000..03fa5f2
--- /dev/null
+++ b/libc/bionic/pthread_getschedparam.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include "ErrnoRestorer.h"
+#include "pthread_accessor.h"
+
+int pthread_getschedparam(pthread_t t, int* policy, sched_param* param) {
+ ErrnoRestorer errno_restorer;
+
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ int rc = sched_getparam(thread->tid, param);
+ if (rc == -1) {
+ return errno;
+ }
+ *policy = sched_getscheduler(thread->tid);
+ return 0;
+}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 9122a74..0eb0e0a 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -57,16 +57,17 @@
int _init_thread(pthread_internal_t* thread, bool add_to_thread_list);
void __init_tls(pthread_internal_t* thread);
-void _pthread_internal_add( pthread_internal_t* thread );
+void _pthread_internal_add(pthread_internal_t* thread);
pthread_internal_t* __get_thread(void);
__LIBC_HIDDEN__ void pthread_key_clean_all(void);
+__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread);
#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002
-extern pthread_internal_t* gThreadList;
-extern pthread_mutex_t gThreadListLock;
+__LIBC_HIDDEN__ extern pthread_internal_t* gThreadList;
+__LIBC_HIDDEN__ extern pthread_mutex_t gThreadListLock;
/* needed by posix-timers.c */
diff --git a/libc/bionic/pthread_internals.cpp b/libc/bionic/pthread_internals.cpp
new file mode 100644
index 0000000..66bc5b7
--- /dev/null
+++ b/libc/bionic/pthread_internals.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "pthread_internal.h"
+
+#include "bionic_tls.h"
+#include "ScopedPthreadMutexLocker.h"
+
+__LIBC_HIDDEN__ pthread_internal_t* gThreadList = NULL;
+__LIBC_HIDDEN__ pthread_mutex_t gThreadListLock = PTHREAD_MUTEX_INITIALIZER;
+
+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);
+ }
+}
+
+__LIBC_ABI_PRIVATE__ void _pthread_internal_add(pthread_internal_t* thread) {
+ ScopedPthreadMutexLocker locker(&gThreadListLock);
+
+ // We insert at the head.
+ thread->next = gThreadList;
+ thread->prev = NULL;
+ if (thread->next != NULL) {
+ thread->next->prev = thread;
+ }
+ gThreadList = thread;
+}
+
+__LIBC_ABI_PRIVATE__ pthread_internal_t* __get_thread(void) {
+ void** tls = reinterpret_cast<void**>(const_cast<void*>(__get_tls()));
+ return reinterpret_cast<pthread_internal_t*>(tls[TLS_SLOT_THREAD_ID]);
+}
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
new file mode 100644
index 0000000..e6acc34
--- /dev/null
+++ b/libc/bionic/pthread_join.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include "pthread_accessor.h"
+
+int pthread_join(pthread_t t, void ** ret_val) {
+ if (t == pthread_self()) {
+ return EDEADLK;
+ }
+
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
+ 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 from thread list when we're the last joiner or when the
+ // thread was already a zombie.
+ if (count <= 0) {
+ _pthread_internal_remove_locked(thread.get());
+ }
+ return 0;
+}
diff --git a/libc/bionic/pthread_kill.cpp b/libc/bionic/pthread_kill.cpp
new file mode 100644
index 0000000..2d37ae9
--- /dev/null
+++ b/libc/bionic/pthread_kill.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "ErrnoRestorer.h"
+#include "pthread_accessor.h"
+
+extern "C" int tgkill(int tgid, int tid, int sig);
+
+int pthread_kill(pthread_t t, int sig) {
+ ErrnoRestorer errno_restorer;
+
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ int rc = tgkill(getpid(), thread->tid, sig);
+ if (rc == -1) {
+ return errno;
+ }
+
+ return 0;
+}
diff --git a/libc/bionic/pthread_self.cpp b/libc/bionic/pthread_self.cpp
new file mode 100644
index 0000000..0a83f07
--- /dev/null
+++ b/libc/bionic/pthread_self.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "pthread_internal.h"
+
+pthread_t pthread_self() {
+ return reinterpret_cast<pthread_t>(__get_thread());
+}
diff --git a/libc/bionic/pthread_setschedparam.cpp b/libc/bionic/pthread_setschedparam.cpp
new file mode 100644
index 0000000..c383cca
--- /dev/null
+++ b/libc/bionic/pthread_setschedparam.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include "ErrnoRestorer.h"
+#include "pthread_accessor.h"
+
+int pthread_setschedparam(pthread_t t, int policy, struct sched_param const* param) {
+ ErrnoRestorer errno_restorer;
+
+ pthread_accessor thread(t);
+ if (thread.get() == NULL) {
+ return ESRCH;
+ }
+
+ int rc = sched_setscheduler(thread->tid, policy, param);
+ if (rc == -1) {
+ return errno;
+ }
+ return 0;
+}