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/Android.mk b/libc/Android.mk
index 708624d..5a1356a 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -280,7 +280,16 @@
     bionic/__memmove_chk.cpp \
     bionic/__memset_chk.cpp \
     bionic/pthread_attr.cpp \
+    bionic/pthread_detach.cpp \
+    bionic/pthread_equal.cpp \
+    bionic/pthread_getcpuclockid.cpp \
+    bionic/pthread_getschedparam.cpp \
+    bionic/pthread_internals.cpp \
+    bionic/pthread_join.cpp \
+    bionic/pthread_kill.cpp \
+    bionic/pthread_self.cpp \
     bionic/pthread_setname_np.cpp \
+    bionic/pthread_setschedparam.cpp \
     bionic/pthread_sigmask.cpp \
     bionic/raise.cpp \
     bionic/sbrk.cpp \
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;
+}
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index ef6b80e..dbdee70 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -151,7 +151,7 @@
 
 int pthread_getschedparam(pthread_t thid, int * policy,
                           struct sched_param * param);
-int pthread_setschedparam(pthread_t thid, int poilcy,
+int pthread_setschedparam(pthread_t thid, int policy,
                           struct sched_param const * param);
 
 int pthread_mutexattr_init(pthread_mutexattr_t *attr);