diff --git a/libc/Android.mk b/libc/Android.mk index 708624dcd..5a1356a62 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -280,7 +280,16 @@ libc_bionic_src_files := \ 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 584821580..e30fa9de9 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -59,55 +59,6 @@ int __futex_wait_ex(volatile void *ftx, int pshared, int val, const struct time #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 @@ void pthread_exit(void * retval) // 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 @@ void pthread_exit(void * retval) } else { thread->join_count = -1; /* zombie thread */ } - pthread_mutex_unlock(&gThreadListLock); } + pthread_mutex_unlock(&gThreadListLock); sigfillset(&mask); sigdelset(&mask, SIGSEGV); @@ -212,133 +162,6 @@ void pthread_exit(void * retval) _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 @@ int pthread_cond_timeout_np(pthread_cond_t *cond, } -// man says this should be in , 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 000000000..eb8c35090 --- /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 + +#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(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 000000000..63f5809d8 --- /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 + +#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 000000000..493b2c25c --- /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 + +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 000000000..10046bab5 --- /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 + +#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 000000000..03fa5f2d4 --- /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 + +#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 9122a748b..0eb0e0a93 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -57,16 +57,17 @@ typedef struct pthread_internal_t 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 000000000..66bc5b75d --- /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(const_cast(__get_tls())); + return reinterpret_cast(tls[TLS_SLOT_THREAD_ID]); +} diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp new file mode 100644 index 000000000..e6acc34ce --- /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 + +#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 000000000..2d37ae9fb --- /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 +#include + +#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 000000000..0a83f0780 --- /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(__get_thread()); +} diff --git a/libc/bionic/pthread_setschedparam.cpp b/libc/bionic/pthread_setschedparam.cpp new file mode 100644 index 000000000..c383cca18 --- /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 + +#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 ef6b80e75..dbdee7044 100644 --- a/libc/include/pthread.h +++ b/libc/include/pthread.h @@ -151,7 +151,7 @@ int pthread_equal(pthread_t one, pthread_t two); 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); diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index aebf47770..239092ca2 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -79,6 +79,12 @@ static void AssertDetached(pthread_t t, bool is_detached) { ASSERT_EQ(is_detached, (detach_state == PTHREAD_CREATE_DETACHED)); } +static void MakeDeadThread(pthread_t& t) { + ASSERT_EQ(0, pthread_create(&t, NULL, IdFn, NULL)); + void* result; + ASSERT_EQ(0, pthread_join(t, &result)); +} + TEST(pthread, pthread_create) { void* expected_result = reinterpret_cast(123); // Can we create a thread? @@ -229,12 +235,67 @@ TEST(pthread, pthread_setname_np__other) { #if __BIONIC__ // Not all build servers have a new enough glibc? TODO: remove when they're on gprecise. TEST(pthread, pthread_setname_np__no_such_thread) { - pthread_t t1; - ASSERT_EQ(0, pthread_create(&t1, NULL, IdFn, NULL)); - void* result; - ASSERT_EQ(0, pthread_join(t1, &result)); + pthread_t dead_thread; + MakeDeadThread(dead_thread); // Call pthread_setname_np after thread has already exited. - ASSERT_EQ(ENOENT, pthread_setname_np(t1, "short 3")); + ASSERT_EQ(ENOENT, pthread_setname_np(dead_thread, "short 3")); } #endif + +TEST(pthread, pthread_kill__0) { + // Signal 0 just tests that the thread exists, so it's safe to call on ourselves. + ASSERT_EQ(0, pthread_kill(pthread_self(), 0)); +} + +TEST(pthread, pthread_kill__invalid_signal) { + ASSERT_EQ(EINVAL, pthread_kill(pthread_self(), -1)); +} + +TEST(pthread, pthread_detach__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + ASSERT_EQ(ESRCH, pthread_detach(dead_thread)); +} + +TEST(pthread, pthread_getcpuclockid__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + clockid_t c; + ASSERT_EQ(ESRCH, pthread_getcpuclockid(dead_thread, &c)); +} + +TEST(pthread, pthread_getschedparam__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + int policy; + sched_param param; + ASSERT_EQ(ESRCH, pthread_getschedparam(dead_thread, &policy, ¶m)); +} + +TEST(pthread, pthread_setschedparam__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + int policy = 0; + sched_param param; + ASSERT_EQ(ESRCH, pthread_setschedparam(dead_thread, policy, ¶m)); +} + +TEST(pthread, pthread_join__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + void* result; + ASSERT_EQ(ESRCH, pthread_join(dead_thread, &result)); +} + +TEST(pthread, pthread_kill__no_such_thread) { + pthread_t dead_thread; + MakeDeadThread(dead_thread); + + ASSERT_EQ(ESRCH, pthread_kill(dead_thread, 0)); +}