pthread_mutex.cpp revision a12c54454f3a6132988b68873903f6e9eed7f384
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved. 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met: 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions of source code must retain the above copyright 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer. 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions in binary form must reproduce the above copyright 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer in 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the documentation and/or other materials provided with the 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distribution. 141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE. 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 28d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer 29d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <assert.h> 30d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <errno.h> 31d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <fcntl.h> 32d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <limits.h> 33d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <malloc.h> 34d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <memory.h> 35d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <pthread.h> 361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <signal.h> 371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdint.h> 381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h> 391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h> 401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/atomics.h> 411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/mman.h> 42d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <sys/prctl.h> 43d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <sys/stat.h> 44d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <sys/types.h> 451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <time.h> 46d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include <unistd.h> 47d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer 48d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include "bionic_atomic_inline.h" 49d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include "bionic_futex.h" 50d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include "bionic_pthread.h" 51ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughes#include "bionic_ssp.h" 52d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer#include "bionic_tls.h" 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "pthread_internal.h" 541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "thread_private.h" 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 567c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianextern void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex); 577c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianextern void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex); 587c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern int __pthread_clone(int (*fn)(void*), void *child_stack, int flags, void *arg); 601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void _exit_with_stack_teardown(void * stackBase, int stackSize, int retCode); 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void _exit_thread(int retCode); 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 636304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turnerint __futex_wake_ex(volatile void *ftx, int pshared, int val) 646304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner{ 656304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner return __futex_syscall3(ftx, pshared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, val); 666304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner} 676304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner 686304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turnerint __futex_wait_ex(volatile void *ftx, int pshared, int val, const struct timespec *timeout) 696304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner{ 706304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner return __futex_syscall4(ftx, pshared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, val, timeout); 716304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner} 726304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner 7388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner#define __likely(cond) __builtin_expect(!!(cond), 1) 7488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner#define __unlikely(cond) __builtin_expect(!!(cond), 0) 7588f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 768e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare#ifdef __i386__ 778e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare#define ATTRIBUTES __attribute__((noinline)) __attribute__((fastcall)) 788e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare#else 798e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare#define ATTRIBUTES __attribute__((noinline)) 808e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare#endif 818e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Beare 828e551a6319e45dd5c8d03864f3330b45cf8551b7Bruce Bearevoid ATTRIBUTES _thread_created_hook(pid_t thread_id); 831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 84d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peifferstatic const int kPthreadInitFailed = 1; 85d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer 861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002 881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define DEFAULT_STACKSIZE (1024 * 1024) 901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic pthread_mutex_t mmap_lock = PTHREAD_MUTEX_INITIALIZER; 921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const pthread_attr_t gDefaultPthreadAttr = { 951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .flags = 0, 961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .stack_base = NULL, 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .stack_size = DEFAULT_STACKSIZE, 981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .guard_size = PAGE_SIZE, 991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .sched_policy = SCHED_NORMAL, 1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project .sched_priority = 0 1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}; 1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 103d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peifferstatic pthread_internal_t* gThreadList = NULL; 1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic pthread_mutex_t gThreadListLock = PTHREAD_MUTEX_INITIALIZER; 1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic pthread_mutex_t gDebuggerNotificationLock = PTHREAD_MUTEX_INITIALIZER; 1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1074f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughesstatic void _pthread_internal_remove_locked(pthread_internal_t* thread) { 1084f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes if (thread->next != NULL) { 109bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes thread->next->prev = thread->prev; 1104f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes } 1114f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes if (thread->prev != NULL) { 1124f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes thread->prev->next = thread->next; 1134f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes } else { 1144f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes gThreadList = thread->next; 1154f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes } 1164f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes 1174f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes // The main thread is not heap-allocated. See __libc_init_tls for the declaration, 1184f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes // and __libc_init_common for the point where it's added to the thread list. 1194f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes if (thread->allocated_on_heap) { 1204f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes free(thread); 1214f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes } 1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1244f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughesstatic void _pthread_internal_remove(pthread_internal_t* thread) { 1254f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes pthread_mutex_lock(&gThreadListLock); 1264f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes _pthread_internal_remove_locked(thread); 1274f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes pthread_mutex_unlock(&gThreadListLock); 1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1304f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes__LIBC_ABI_PRIVATE__ void _pthread_internal_add(pthread_internal_t* thread) { 1314f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes pthread_mutex_lock(&gThreadListLock); 132bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes 1334f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes // We insert at the head. 1344f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes thread->next = gThreadList; 1354f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes thread->prev = NULL; 1364f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes if (thread->next != NULL) { 1374f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes thread->next->prev = thread; 1384f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes } 1394f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes gThreadList = thread; 140bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes 1414f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes pthread_mutex_unlock(&gThreadListLock); 1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1441a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov__LIBC_ABI_PRIVATE__ pthread_internal_t* 1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project__get_thread(void) 1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void** tls = (void**)__get_tls(); 1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (pthread_internal_t*) tls[TLS_SLOT_THREAD_ID]; 1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid* 1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project__get_stack_base(int *p_stack_size) 1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = __get_thread(); 1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *p_stack_size = thread->attr.stack_size; 1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return thread->attr.stack_base; 1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1635419b9474753d25dff947c7740532f86d130c0beElliott Hughesvoid __init_tls(void** tls, void* thread) { 1645419b9474753d25dff947c7740532f86d130c0beElliott Hughes ((pthread_internal_t*) thread)->tls = tls; 1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1665419b9474753d25dff947c7740532f86d130c0beElliott Hughes // Zero-initialize all the slots. 1675419b9474753d25dff947c7740532f86d130c0beElliott Hughes for (size_t i = 0; i < BIONIC_TLS_SLOTS; ++i) { 1685419b9474753d25dff947c7740532f86d130c0beElliott Hughes tls[i] = NULL; 1695419b9474753d25dff947c7740532f86d130c0beElliott Hughes } 1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 171ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughes // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0. 1725419b9474753d25dff947c7740532f86d130c0beElliott Hughes tls[TLS_SLOT_SELF] = (void*) tls; 1735419b9474753d25dff947c7740532f86d130c0beElliott Hughes tls[TLS_SLOT_THREAD_ID] = thread; 1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 175ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughes // Stack guard generation may make system calls, and those system calls may fail. 176ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughes // If they do, they'll try to set errno, so we can only do this after calling __set_tls. 1775419b9474753d25dff947c7740532f86d130c0beElliott Hughes __set_tls((void*) tls); 178ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughes tls[TLS_SLOT_STACK_GUARD] = __generate_stack_chk_guard(); 1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 183d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer * This trampoline is called from the assembly _pthread_clone() function. 1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid __thread_entry(int (*func)(void*), void *arg, void **tls) 1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Wait for our creating thread to release us. This lets it have time to 188d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // notify gdb about this thread before we start doing anything. 189e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // 190e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // This also provides the memory barrier needed to ensure that all memory 191e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // accesses previously made by the creating thread are visible to us. 192d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF]; 1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(start_mutex); 1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_destroy(start_mutex); 1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 196d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_internal_t* thread = (pthread_internal_t*) tls[TLS_SLOT_THREAD_ID]; 197d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer __init_tls(tls, thread); 1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 199d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if ((thread->internal_flags & kPthreadInitFailed) != 0) { 200d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_exit(NULL); 201d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 203d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int result = func(arg); 204d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_exit((void*) result); 2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20788f1ea8f82e1fcef0d472577f00cd889b796e944Dave Burke#include <private/logd.h> 20888f1ea8f82e1fcef0d472577f00cd889b796e944Dave Burke 2091a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov__LIBC_ABI_PRIVATE__ 210ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wangint _init_thread(pthread_internal_t* thread, pid_t kernel_id, const pthread_attr_t* attr, 211bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes void* stack_base, bool add_to_thread_list) 2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 213d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int error = 0; 214d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer 215ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wang thread->attr = *attr; 2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->attr.stack_base = stack_base; 217ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wang thread->kernel_id = kernel_id; 2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 219d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // Make a note of whether the user supplied this stack (so we know whether or not to free it). 220d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (attr->stack_base == stack_base) { 221d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK; 222d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 223d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer 224d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // Set the scheduling policy/priority of the thread. 2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (thread->attr.sched_policy != SCHED_NORMAL) { 2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct sched_param param; 2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project param.sched_priority = thread->attr.sched_priority; 228d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (sched_setscheduler(kernel_id, thread->attr.sched_policy, ¶m) == -1) { 229ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wang // For backwards compatibility reasons, we just warn about failures here. 230ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wang // error = errno; 23188f1ea8f82e1fcef0d472577f00cd889b796e944Dave Burke const char* msg = "pthread_create sched_setscheduler call failed: %s\n"; 23288f1ea8f82e1fcef0d472577f00cd889b796e944Dave Burke __libc_android_log_print(ANDROID_LOG_WARN, "libc", msg, strerror(errno)); 233d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_init(&thread->join_cond, NULL); 2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->join_count = 0; 2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->cleanup_stack = NULL; 2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 240bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes if (add_to_thread_list) { 241bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes _pthread_internal_add(thread); 242bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes } 243bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes 244d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer return error; 2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void *mkstack(size_t size, size_t guard_size) 2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&mmap_lock); 2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 251d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int prot = PROT_READ | PROT_WRITE; 252d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; 2539c3eca7bcee694e6a477a7d50065f11cf1e805bbElliott Hughes void* stack = mmap(NULL, size, prot, flags, -1, 0); 254d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (stack == MAP_FAILED) { 2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project stack = NULL; 2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto done; 2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 259d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (mprotect(stack, guard_size, PROT_NONE) == -1) { 2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project munmap(stack, size); 2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project stack = NULL; 2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto done; 2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdone: 2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&mmap_lock); 2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return stack; 2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 271e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * Create a new thread. The thread's stack is laid out like so: 2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * +---------------------------+ 2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | pthread_internal_t | 2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * +---------------------------+ 2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | | 2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | TLS area | 2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | | 2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * +---------------------------+ 2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | | 2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * . . 2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * . stack area . 2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * . . 2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | | 2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * +---------------------------+ 2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * | guard page | 2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * +---------------------------+ 2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * note that TLS[0] must be a pointer to itself, this is required 2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * by the thread-local storage implementation of the x86 Linux 2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * kernel, where the TLS pointer is read by reading fs:[0] 2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_create(pthread_t *thread_out, pthread_attr_t const * attr, 2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void *(*start_routine)(void *), void * arg) 2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 296d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int old_errno = errno; 2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* this will inform the rest of the C library that at least one thread 2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * was created. this will enforce certain functions to acquire/release 3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * locks (e.g. atexit()) to protect shared global structures. 3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * this works because pthread_create() is not called by the C library 3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * initialization routine that sets up the main thread's data structures. 3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project __isthreaded = 1; 3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 307d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_internal_t* thread = calloc(sizeof(*thread), 1); 308d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (thread == NULL) { 3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ENOMEM; 310d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 3114f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes thread->allocated_on_heap = true; 3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (attr == NULL) { 3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr = &gDefaultPthreadAttr; 3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // make sure the stack is PAGE_SIZE aligned 318d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer size_t stack_size = (attr->stack_size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); 319d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer uint8_t* stack = attr->stack_base; 320d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (stack == NULL) { 321d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer stack = mkstack(stack_size, attr->guard_size); 322d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (stack == NULL) { 3234f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes free(thread); 3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ENOMEM; 3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Make room for TLS 329d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer void** tls = (void**)(stack + stack_size - BIONIC_TLS_SLOTS*sizeof(void*)); 3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Create a mutex for the thread in TLS_SLOT_SELF to wait on once it starts so we can keep 3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // it from doing anything until after we notify the debugger about it 333e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // 334e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // This also provides the memory barrier we need to ensure that all 335e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // memory accesses previously performed by this thread are visible to 336e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden // the new thread. 337d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF]; 3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_init(start_mutex, NULL); 3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(start_mutex); 3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tls[TLS_SLOT_THREAD_ID] = thread; 3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 343d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | 344d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED; 345d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int tid = __pthread_clone((int(*)(void*))start_routine, tls, flags, arg); 3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 347d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (tid < 0) { 348d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer int clone_errno = errno; 349d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_mutex_unlock(start_mutex); 350d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (stack != attr->stack_base) { 351d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer munmap(stack, stack_size); 352d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 3534f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes free(thread); 3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = old_errno; 355d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer return clone_errno; 3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 358ae8eb74675722b57ab66a51f1d6f4f250137bb23Xi Wang int init_errno = _init_thread(thread, tid, attr, stack, true); 359d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer if (init_errno != 0) { 360d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // Mark the thread detached and let its __thread_entry run to 361d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // completion. (It'll just exit immediately, cleaning up its resources.) 362d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer thread->internal_flags |= kPthreadInitFailed; 363d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED; 364d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer pthread_mutex_unlock(start_mutex); 365d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer errno = old_errno; 366d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer return init_errno; 367d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer } 3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 369d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer // Notify any debuggers about the new thread. 3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&gDebuggerNotificationLock); 3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project _thread_created_hook(tid); 3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gDebuggerNotificationLock); 3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3742932f048327965731c7e1ab9f2968a2ddb1854f5Jurijs Oniscuks // Publish the pthread_t and let the thread run. 3752932f048327965731c7e1ab9f2968a2ddb1854f5Jurijs Oniscuks *thread_out = (pthread_t) thread; 3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(start_mutex); 3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_init(pthread_attr_t * attr) 3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *attr = gDefaultPthreadAttr; 3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_destroy(pthread_attr_t * attr) 3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project memset(attr, 0x42, sizeof(pthread_attr_t)); 3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setdetachstate(pthread_attr_t * attr, int state) 3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (state == PTHREAD_CREATE_DETACHED) { 3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->flags |= PTHREAD_ATTR_FLAG_DETACHED; 3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else if (state == PTHREAD_CREATE_JOINABLE) { 3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->flags &= ~PTHREAD_ATTR_FLAG_DETACHED; 4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getdetachstate(pthread_attr_t const * attr, int * state) 4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *state = (attr->flags & PTHREAD_ATTR_FLAG_DETACHED) 4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ? PTHREAD_CREATE_DETACHED 4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project : PTHREAD_CREATE_JOINABLE; 4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setschedpolicy(pthread_attr_t * attr, int policy) 4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->sched_policy = policy; 4171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getschedpolicy(pthread_attr_t const * attr, int * policy) 4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *policy = attr->sched_policy; 4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setschedparam(pthread_attr_t * attr, struct sched_param const * param) 4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->sched_priority = param->sched_priority; 4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getschedparam(pthread_attr_t const * attr, struct sched_param * param) 4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project param->sched_priority = attr->sched_priority; 4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setstacksize(pthread_attr_t * attr, size_t stack_size) 4391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { 4411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 4421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->stack_size = stack_size; 4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getstacksize(pthread_attr_t const * attr, size_t * stack_size) 4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *stack_size = attr->stack_size; 4501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 453a12c54454f3a6132988b68873903f6e9eed7f384Wink Savilleint pthread_attr_setstackaddr(pthread_attr_t * attr __attribute__((unused)), 454a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville void * stack_addr __attribute__((unused))) 4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 456a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville // This was removed from POSIX.1-2008, and is not implemented on bionic. 457a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville // Needed for ABI compatibility with the NDK. 4581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ENOSYS; 4591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getstackaddr(pthread_attr_t const * attr, void ** stack_addr) 4621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 463a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville // This was removed from POSIX.1-2008. 464a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville // Needed for ABI compatibility with the NDK. 4653f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner *stack_addr = (char*)attr->stack_base + attr->stack_size; 4661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setstack(pthread_attr_t * attr, void * stack_base, size_t stack_size) 4701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { 4721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 4731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ((uint32_t)stack_base & (PAGE_SIZE - 1)) { 4751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 4761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->stack_base = stack_base; 4781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->stack_size = stack_size; 4791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getstack(pthread_attr_t const * attr, void ** stack_base, size_t * stack_size) 4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *stack_base = attr->stack_base; 4851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *stack_size = attr->stack_size; 4861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_setguardsize(pthread_attr_t * attr, size_t guard_size) 4901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (guard_size & (PAGE_SIZE - 1) || guard_size < PAGE_SIZE) { 4921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 4931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project attr->guard_size = guard_size; 4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_attr_getguardsize(pthread_attr_t const * attr, size_t * guard_size) 5001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *guard_size = attr->guard_size; 5021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 5031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_getattr_np(pthread_t thid, pthread_attr_t * attr) 5061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t * thread = (pthread_internal_t *)thid; 5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *attr = thread->attr; 5091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 5101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 512a12c54454f3a6132988b68873903f6e9eed7f384Wink Savilleint pthread_attr_setscope(pthread_attr_t *attr __attribute__((unused)), int scope) 5131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (scope == PTHREAD_SCOPE_SYSTEM) 5151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (scope == PTHREAD_SCOPE_PROCESS) 5171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ENOTSUP; 5181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 5201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 522a12c54454f3a6132988b68873903f6e9eed7f384Wink Savilleint pthread_attr_getscope(pthread_attr_t const *attr __attribute__((unused))) 5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return PTHREAD_SCOPE_SYSTEM; 5251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions 5291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and thread cancelation 5301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 5311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid __pthread_cleanup_push( __pthread_cleanup_t* c, 5331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project __pthread_cleanup_func_t routine, 5341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void* arg ) 5351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = __get_thread(); 5371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project c->__cleanup_routine = routine; 5391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project c->__cleanup_arg = arg; 5401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project c->__cleanup_prev = thread->cleanup_stack; 5411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->cleanup_stack = c; 5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid __pthread_cleanup_pop( __pthread_cleanup_t* c, int execute ) 5451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = __get_thread(); 5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->cleanup_stack = c->__cleanup_prev; 5491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (execute) 5501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project c->__cleanup_routine(c->__cleanup_arg); 5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* used by pthread_exit() to clean all TLS keys of the current thread */ 5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void pthread_key_clean_all(void); 5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid pthread_exit(void * retval) 5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 5581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = __get_thread(); 5591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void* stack_base = thread->attr.stack_base; 5601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int stack_size = thread->attr.stack_size; 5611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0; 562e480fc83b2887388d469eb3bf58c86c610f5b082Jack Ren sigset_t mask; 5631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // call the cleanup handlers first 5651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project while (thread->cleanup_stack) { 5661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project __pthread_cleanup_t* c = thread->cleanup_stack; 5671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->cleanup_stack = c->__cleanup_prev; 5681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project c->__cleanup_routine(c->__cleanup_arg); 5691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 5701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // call the TLS destructors, it is important to do that before removing this 5721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // thread from the global list. this will ensure that if someone else deletes 5731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // a TLS key, the corresponding value will be set to NULL in this thread's TLS 5741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // space (see pthread_key_delete) 5751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_key_clean_all(); 5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // if the thread is detached, destroy the pthread_internal_t 57810ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov // otherwise, keep it in memory and signal any joiners. 5791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) { 5801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project _pthread_internal_remove(thread); 5811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 5820753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson pthread_mutex_lock(&gThreadListLock); 5830753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson 5840753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson /* make sure that the thread struct doesn't have stale pointers to a stack that 5850753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson * will be unmapped after the exit call below. 5860753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson */ 5870753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson if (!user_stack) { 5880753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson thread->attr.stack_base = NULL; 5890753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson thread->attr.stack_size = 0; 5900753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson thread->tls = NULL; 5910753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson } 5920753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson 5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* the join_count field is used to store the number of threads waiting for 5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the termination of this thread with pthread_join(), 5951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 5961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * if it is positive we need to signal the waiters, and we do not touch 5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the count (it will be decremented by the waiters, the last one will 5981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * also remove/free the thread structure 5991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 6001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * if it is zero, we set the count value to -1 to indicate that the 6011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * thread is in 'zombie' state: it has stopped executing, and its stack 6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * is gone (as well as its TLS area). when another thread calls pthread_join() 6031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * on it, it will immediately free the thread and return. 6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->return_value = retval; 6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (thread->join_count > 0) { 6071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_broadcast(&thread->join_cond); 6081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 6091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->join_count = -1; /* zombie thread */ 6101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gThreadListLock); 6121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 614e480fc83b2887388d469eb3bf58c86c610f5b082Jack Ren sigfillset(&mask); 615e480fc83b2887388d469eb3bf58c86c610f5b082Jack Ren sigdelset(&mask, SIGSEGV); 616e480fc83b2887388d469eb3bf58c86c610f5b082Jack Ren (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL); 617e480fc83b2887388d469eb3bf58c86c610f5b082Jack Ren 6181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // destroy the thread stack 6191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (user_stack) 6201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project _exit_thread((int)retval); 6211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else 6221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project _exit_with_stack_teardown(stack_base, stack_size, (int)retval); 6231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_join(pthread_t thid, void ** ret_val) 6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 6271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = (pthread_internal_t*)thid; 62814f19592ae7c819855052bcebc79de87069c2954Elliott Hughes if (thid == pthread_self()) { 62914f19592ae7c819855052bcebc79de87069c2954Elliott Hughes return EDEADLK; 63014f19592ae7c819855052bcebc79de87069c2954Elliott Hughes } 6311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // check that the thread still exists and is not detached 6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&gThreadListLock); 6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 63514f19592ae7c819855052bcebc79de87069c2954Elliott Hughes for (thread = gThreadList; thread != NULL; thread = thread->next) { 63614f19592ae7c819855052bcebc79de87069c2954Elliott Hughes if (thread == (pthread_internal_t*)thid) { 637a28336c73542f5df1c03de4c142070f408e8d5aaAndré Goddard Rosa goto FoundIt; 63814f19592ae7c819855052bcebc79de87069c2954Elliott Hughes } 63914f19592ae7c819855052bcebc79de87069c2954Elliott Hughes } 6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 641a28336c73542f5df1c03de4c142070f408e8d5aaAndré Goddard Rosa pthread_mutex_unlock(&gThreadListLock); 642a28336c73542f5df1c03de4c142070f408e8d5aaAndré Goddard Rosa return ESRCH; 6431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 644a28336c73542f5df1c03de4c142070f408e8d5aaAndré Goddard RosaFoundIt: 6451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) { 6461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gThreadListLock); 6471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* wait for thread death when needed 6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 6521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * if the 'join_count' is negative, this is a 'zombie' thread that 6531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * is already dead and without stack/TLS 6541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 6551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * otherwise, we need to increment 'join-count' and wait to be signaled 6561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 65714f19592ae7c819855052bcebc79de87069c2954Elliott Hughes int count = thread->join_count; 6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (count >= 0) { 6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thread->join_count += 1; 6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_wait( &thread->join_cond, &gThreadListLock ); 6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project count = --thread->join_count; 6621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 66310ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov if (ret_val) { 6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *ret_val = thread->return_value; 66510ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov } 6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* remove thread descriptor when we're the last joiner or when the 6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * thread was already a zombie. 6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (count <= 0) { 6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project _pthread_internal_remove_locked(thread); 6721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gThreadListLock); 6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_detach( pthread_t thid ) 6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread; 6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int result = 0; 6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&gThreadListLock); 68310ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov for (thread = gThreadList; thread != NULL; thread = thread->next) { 68410ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov if (thread == (pthread_internal_t*)thid) { 6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto FoundIt; 68610ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov } 68710ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov } 6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project result = ESRCH; 6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto Exit; 6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectFoundIt: 69310ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) { 69410ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov result = EINVAL; // Already detached. 69510ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov goto Exit; 69610ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov } 6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 69810ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov if (thread->join_count > 0) { 69910ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov result = 0; // Already being joined; silently do nothing, like glibc. 70010ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov goto Exit; 7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 70210ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov 70310ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED; 70410ce96944eaea4c459392952652fdb24742c9c29Sergey Melnikov 7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectExit: 7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gThreadListLock); 7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return result; 7081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectpthread_t pthread_self(void) 7111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 7121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (pthread_t)__get_thread(); 7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_equal(pthread_t one, pthread_t two) 7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (one == two ? 1 : 0); 7181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_getschedparam(pthread_t thid, int * policy, 7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct sched_param * param) 7221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 7231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int old_errno = errno; 7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t * thread = (pthread_internal_t *)thid; 7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int err = sched_getparam(thread->kernel_id, param); 7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!err) { 7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *policy = sched_getscheduler(thread->kernel_id); 7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project err = errno; 7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = old_errno; 7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return err; 7341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_setschedparam(pthread_t thid, int policy, 7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct sched_param const * param) 7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t * thread = (pthread_internal_t *)thid; 7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int old_errno = errno; 7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int ret; 7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ret = sched_setscheduler(thread->kernel_id, policy, param); 7441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (ret < 0) { 7451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ret = errno; 7461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = old_errno; 7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 7481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ret; 7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* a mutex is implemented as a 32-bit integer holding the following fields 7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * bits: name description 7551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 31-16 tid owner thread's kernel id (recursive and errorcheck only) 7561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 15-14 type mutex type 75788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * 13 shared process-shared flag 75888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * 12-2 counter counter of recursive mutexes 7591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1-0 state lock state (0, 1 or 2) 7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 762e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Convenience macro, creates a mask of 'bits' bits that starts from 763e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the 'shift'-th least significant bit in a 32-bit word. 764e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 765e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * Examples: FIELD_MASK(0,4) -> 0xf 766e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * FIELD_MASK(16,9) -> 0x1ff0000 767e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 768e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define FIELD_MASK(shift,bits) (((1 << (bits))-1) << (shift)) 769e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 770e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* This one is used to create a bit pattern from a given field value */ 771e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define FIELD_TO_BITS(val,shift,bits) (((val) & ((1 << (bits))-1)) << (shift)) 772e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 773e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* And this one does the opposite, i.e. extract a field's value from a bit pattern */ 774e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define FIELD_FROM_BITS(val,shift,bits) (((val) >> (shift)) & ((1 << (bits))-1)) 775e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 776e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Mutex state: 777e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 778e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 0 for unlocked 779e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 1 for locked, no waiters 780e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 2 for locked, maybe waiters 781e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 782e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_SHIFT 0 783e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_LEN 2 784e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 785e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_MASK FIELD_MASK(MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) 786e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_FROM_BITS(v) FIELD_FROM_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) 787e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_TO_BITS(v) FIELD_TO_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) 788e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 789e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_UNLOCKED 0 /* must be 0 to match __PTHREAD_MUTEX_INIT_VALUE */ 790e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_LOCKED_UNCONTENDED 1 /* must be 1 due to atomic dec in unlock operation */ 791e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_LOCKED_CONTENDED 2 /* must be 1 + LOCKED_UNCONTENDED due to atomic dec */ 792e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 793e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_FROM_BITS(v) FIELD_FROM_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) 794e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_TO_BITS(v) FIELD_TO_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) 795e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 796e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_UNLOCKED MUTEX_STATE_TO_BITS(MUTEX_STATE_UNLOCKED) 797e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_LOCKED_UNCONTENDED MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_UNCONTENDED) 798e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_LOCKED_CONTENDED MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_CONTENDED) 799e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 800e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* return true iff the mutex if locked with no waiters */ 801e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED) 802e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 803e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* return true iff the mutex if locked with maybe waiters */ 804e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED) 805e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 806e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* used to flip from LOCKED_UNCONTENDED to LOCKED_CONTENDED */ 807e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_STATE_BITS_FLIP_CONTENTION(v) ((v) ^ (MUTEX_STATE_BITS_LOCKED_CONTENDED ^ MUTEX_STATE_BITS_LOCKED_UNCONTENDED)) 808e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 809e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Mutex counter: 810e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 811e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * We need to check for overflow before incrementing, and we also need to 812e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * detect when the counter is 0 813e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 814e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_SHIFT 2 815e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_LEN 11 816e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_MASK FIELD_MASK(MUTEX_COUNTER_SHIFT, MUTEX_COUNTER_LEN) 817e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 818e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_BITS_WILL_OVERFLOW(v) (((v) & MUTEX_COUNTER_MASK) == MUTEX_COUNTER_MASK) 819e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_BITS_IS_ZERO(v) (((v) & MUTEX_COUNTER_MASK) == 0) 820e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 821e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Used to increment the counter directly after overflow has been checked */ 822e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_BITS_ONE FIELD_TO_BITS(1,MUTEX_COUNTER_SHIFT,MUTEX_COUNTER_LEN) 823e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 824e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Returns true iff the counter is 0 */ 825e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_COUNTER_BITS_ARE_ZERO(v) (((v) & MUTEX_COUNTER_MASK) == 0) 8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 827e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Mutex shared bit flag 828e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 829e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * This flag is set to indicate that the mutex is shared among processes. 830e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * This changes the futex opcode we use for futex wait/wake operations 831e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * (non-shared operations are much faster). 832e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 833e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_SHARED_SHIFT 13 834e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_SHARED_MASK FIELD_MASK(MUTEX_SHARED_SHIFT,1) 835e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 836e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Mutex type: 837e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 838e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * We support normal, recursive and errorcheck mutexes. 839e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 840e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * The constants defined here *cannot* be changed because they must match 841e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the C library ABI which defines the following initialization values in 842e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * <pthread.h>: 843e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 844e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * __PTHREAD_MUTEX_INIT_VALUE 845e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * __PTHREAD_RECURSIVE_MUTEX_VALUE 846e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * __PTHREAD_ERRORCHECK_MUTEX_INIT_VALUE 847e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 848e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_SHIFT 14 849e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_LEN 2 850e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_MASK FIELD_MASK(MUTEX_TYPE_SHIFT,MUTEX_TYPE_LEN) 851022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner 852e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_NORMAL 0 /* Must be 0 to match __PTHREAD_MUTEX_INIT_VALUE */ 853e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_RECURSIVE 1 854e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_ERRORCHECK 2 855e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 856e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_TO_BITS(t) FIELD_TO_BITS(t, MUTEX_TYPE_SHIFT, MUTEX_TYPE_LEN) 857e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 858e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_BITS_NORMAL MUTEX_TYPE_TO_BITS(MUTEX_TYPE_NORMAL) 859e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_BITS_RECURSIVE MUTEX_TYPE_TO_BITS(MUTEX_TYPE_RECURSIVE) 860e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_TYPE_BITS_ERRORCHECK MUTEX_TYPE_TO_BITS(MUTEX_TYPE_ERRORCHECK) 861e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 862e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Mutex owner field: 863e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 864e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * This is only used for recursive and errorcheck mutexes. It holds the 865e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * kernel TID of the owning thread. Note that this works because the Linux 866e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * kernel _only_ uses 16-bit values for thread ids. 867e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 868e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * More specifically, it will wrap to 10000 when it reaches over 32768 for 869e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * application processes. You can check this by running the following inside 870e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * an adb shell session: 871e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 872e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner OLDPID=$$; 873e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner while true; do 874e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner NEWPID=$(sh -c 'echo $$') 875e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if [ "$NEWPID" -gt 32768 ]; then 876e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner echo "AARGH: new PID $NEWPID is too high!" 877e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner exit 1 878e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner fi 879e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if [ "$NEWPID" -lt "$OLDPID" ]; then 880e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner echo "****** Wrapping from PID $OLDPID to $NEWPID. *******" 881e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner else 882e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner echo -n "$NEWPID!" 883e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner fi 884e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner OLDPID=$NEWPID 885e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner done 886e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 887e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * Note that you can run the same example on a desktop Linux system, 888e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the wrapping will also happen at 32768, but will go back to 300 instead. 889e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 890e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_OWNER_SHIFT 16 891e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_OWNER_LEN 16 892e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 893e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_OWNER_FROM_BITS(v) FIELD_FROM_BITS(v,MUTEX_OWNER_SHIFT,MUTEX_OWNER_LEN) 894e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner#define MUTEX_OWNER_TO_BITS(v) FIELD_TO_BITS(v,MUTEX_OWNER_SHIFT,MUTEX_OWNER_LEN) 895e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 896e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner/* Convenience macros. 897e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 898e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * These are used to form or modify the bit pattern of a given mutex value 899e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 9001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 90388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner/* a mutex attribute holds the following fields 90488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * 90588f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * bits: name description 90688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * 0-3 type type of mutex 90788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * 4 shared process-shared flag 90888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner */ 90988f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner#define MUTEXATTR_TYPE_MASK 0x000f 91088f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner#define MUTEXATTR_SHARED_MASK 0x0010 9111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_init(pthread_mutexattr_t *attr) 9141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 9151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (attr) { 9161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *attr = PTHREAD_MUTEX_DEFAULT; 9171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 9181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 9191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 9211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 9241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 9251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (attr) { 9261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *attr = -1; 9271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 9281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 9291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 9311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) 9341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 93588f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if (attr) { 93688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner int atype = (*attr & MUTEXATTR_TYPE_MASK); 93788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 93888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if (atype >= PTHREAD_MUTEX_NORMAL && 93988f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner atype <= PTHREAD_MUTEX_ERRORCHECK) { 94088f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner *type = atype; 94188f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return 0; 94288f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner } 9431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 9441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (attr && type >= PTHREAD_MUTEX_NORMAL && 9501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project type <= PTHREAD_MUTEX_ERRORCHECK ) { 95188f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; 9521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 9531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 9541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* process-shared mutexes are not supported at the moment */ 9581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) 9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 9611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!attr) 9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 964b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian switch (pshared) { 965b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian case PTHREAD_PROCESS_PRIVATE: 96688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner *attr &= ~MUTEXATTR_SHARED_MASK; 96788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return 0; 96888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 969b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian case PTHREAD_PROCESS_SHARED: 970b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian /* our current implementation of pthread actually supports shared 971b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian * mutexes but won't cleanup if a process dies with the mutex held. 972b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian * Nevertheless, it's better than nothing. Shared mutexes are used 973b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian * by surfaceflinger and audioflinger. 974b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian */ 97588f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner *attr |= MUTEXATTR_SHARED_MASK; 976b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian return 0; 977b7681167cbe91c2bb95cccdc08f75184ed1fb839Mathias Agopian } 97888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return EINVAL; 9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) 9821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 98388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if (!attr || !pshared) 9841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 9851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 98688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED 98788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner : PTHREAD_PROCESS_PRIVATE; 9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_mutex_init(pthread_mutex_t *mutex, 9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const pthread_mutexattr_t *attr) 9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 99488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner int value = 0; 9951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 99688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if (mutex == NULL) 99788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return EINVAL; 998ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner 99988f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if (__likely(attr == NULL)) { 1000e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mutex->value = MUTEX_TYPE_BITS_NORMAL; 100188f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return 0; 1002ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner } 100388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 100488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner if ((*attr & MUTEXATTR_SHARED_MASK) != 0) 100588f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner value |= MUTEX_SHARED_MASK; 100688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 100788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner switch (*attr & MUTEXATTR_TYPE_MASK) { 100888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner case PTHREAD_MUTEX_NORMAL: 1009e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner value |= MUTEX_TYPE_BITS_NORMAL; 101088f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner break; 101188f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner case PTHREAD_MUTEX_RECURSIVE: 1012e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner value |= MUTEX_TYPE_BITS_RECURSIVE; 101388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner break; 101488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner case PTHREAD_MUTEX_ERRORCHECK: 1015e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner value |= MUTEX_TYPE_BITS_ERRORCHECK; 101688f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner break; 101788f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner default: 101888f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return EINVAL; 101988f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner } 102088f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 102188f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner mutex->value = value; 102288f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner return 0; 10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Lock a non-recursive mutex. 10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * As noted above, there are three states: 10301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 0 (unlocked, no contention) 10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1 (locked, no contention) 10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2 (locked, contention) 10331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 10341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Non-recursive mutexes don't use the thread-id or counter fields, and the 10351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "type" value is zero, so the only bits that will be set are the ones in 10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the lock state field. 10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 10381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void 1039022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner_normal_lock(pthread_mutex_t* mutex, int shared) 10401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1041e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* convenience shortcuts */ 1042e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; 1043e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; 10448641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio /* 10458641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * The common case is an unlocked mutex, so we begin by trying to 1046e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * change the lock's state from 0 (UNLOCKED) to 1 (LOCKED). 1047e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * __bionic_cmpxchg() returns 0 if it made the swap successfully. 1048e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * If the result is nonzero, this lock is already held by another thread. 10498641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio */ 1050e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(unlocked, locked_uncontended, &mutex->value) != 0) { 1051e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED; 10521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* 10538641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * We want to go to sleep until the mutex is available, which 1054e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * requires promoting it to state 2 (CONTENDED). We need to 1055e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * swap in the new state value and then wait until somebody wakes us up. 10568641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 1057e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * __bionic_swap() returns the previous value. We swap 2 in and 10588641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * see if we got zero back; if so, we have acquired the lock. If 10598641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * not, another thread still holds the lock and we wait again. 10608641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 10618641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * The second argument to the __futex_wait() call is compared 10628641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * against the current value. If it doesn't match, __futex_wait() 10638641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * returns immediately (otherwise, it sleeps for a time specified 10648641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * by the third argument; 0 means sleep forever). This ensures 10658641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * that the mutex is in state 2 when we go to sleep on it, which 10668641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * guarantees a wake-up call. 10678641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio */ 1068e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner while (__bionic_swap(locked_contended, &mutex->value) != unlocked) 1069e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner __futex_wait_ex(&mutex->value, shared, locked_contended, 0); 10701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1071fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden ANDROID_MEMBAR_FULL(); 10721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 10751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Release a non-recursive mutex. The caller is responsible for determining 10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * that we are in fact the owner of this lock. 10771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 10781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void 1079022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner_normal_unlock(pthread_mutex_t* mutex, int shared) 10801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1081fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden ANDROID_MEMBAR_FULL(); 1082fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden 10838641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio /* 108488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner * The mutex state will be 1 or (rarely) 2. We use an atomic decrement 1085e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * to release the lock. __bionic_atomic_dec() returns the previous value; 10868641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * if it wasn't 1 we have to do some additional work. 10878641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio */ 1088e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_atomic_dec(&mutex->value) != (shared|MUTEX_STATE_BITS_LOCKED_UNCONTENDED)) { 10891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* 10908641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * Start by releasing the lock. The decrement changed it from 10918641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * "contended lock" to "uncontended lock", which means we still 10928641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * hold it, and anybody who tries to sneak in will push it back 10938641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * to state 2. 10948641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 10958641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * Once we set it to zero the lock is up for grabs. We follow 10968641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * this with a __futex_wake() to ensure that one of the waiting 10978641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * threads has a chance to grab it. 10988641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 10998641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * This doesn't cause a race with the swap/wait pair in 11008641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * _normal_lock(), because the __futex_wait() call there will 11018641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * return immediately if the mutex value isn't 2. 11028641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio */ 110388f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner mutex->value = shared; 11048641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio 11058641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio /* 11068641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * Wake up one waiting thread. We don't know which thread will be 11078641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * woken or when it'll start executing -- futexes make no guarantees 11088641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * here. There may not even be a thread waiting. 11098641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 11108641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * The newly-woken thread will replace the 0 we just set above 11118641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * with 2, which means that when it eventually releases the mutex 11128641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * it will also call FUTEX_WAKE. This results in one extra wake 11138641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * call whenever a lock is contended, but lets us avoid forgetting 11148641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * anyone without requiring us to track the number of sleepers. 11158641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * 11168641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * It's possible for another thread to sneak in and grab the lock 11178641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * between the zero assignment above and the wake call below. If 11188641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * the new thread is "slow" and holds the lock for a while, we'll 11198641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * wake up a sleeper, which will swap in a 2 and then go back to 11208641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * sleep since the lock is still held. If the new thread is "fast", 11218641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * running to completion before we call wake, the thread we 11228641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * eventually wake will find an unlocked mutex and will execute. 11238641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * Either way we have correct behavior and nobody is orphaned on 11248641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio * the wait queue. 11258641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio */ 11266304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner __futex_wake_ex(&mutex->value, shared, 1); 11271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 11281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1130022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner/* This common inlined function is used to increment the counter of an 1131022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * errorcheck or recursive mutex. 1132022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * 1133022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * For errorcheck mutexes, it will return EDEADLK 1134022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * If the counter overflows, it will return EAGAIN 1135022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * Otherwise, it atomically increments the counter and returns 0 1136022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * after providing an acquire barrier. 1137022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * 1138022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * mtype is the current mutex type 1139022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * mvalue is the current mutex value (already loaded) 1140022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * mutex pointers to the mutex. 1141022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner */ 1142022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turnerstatic __inline__ __attribute__((always_inline)) int 1143022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner_recursive_increment(pthread_mutex_t* mutex, int mvalue, int mtype) 1144022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner{ 1145e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (mtype == MUTEX_TYPE_BITS_ERRORCHECK) { 1146022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner /* trying to re-lock a mutex we already acquired */ 1147022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner return EDEADLK; 1148022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner } 1149022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner 1150022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner /* Detect recursive lock overflow and return EAGAIN. 1151022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner * This is safe because only the owner thread can modify the 1152b57db7581cabb98651c4d8940d65c5c404b914adDavid 'Digit' Turner * counter bits in the mutex value. 1153022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner */ 1154e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (MUTEX_COUNTER_BITS_WILL_OVERFLOW(mvalue)) { 1155022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner return EAGAIN; 1156022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner } 1157022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner 1158022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner /* We own the mutex, but other threads are able to change 1159b57db7581cabb98651c4d8940d65c5c404b914adDavid 'Digit' Turner * the lower bits (e.g. promoting it to "contended"), so we 1160e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * need to use an atomic cmpxchg loop to update the counter. 1161b57db7581cabb98651c4d8940d65c5c404b914adDavid 'Digit' Turner */ 1162e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner for (;;) { 1163e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* increment counter, overflow was already checked */ 1164e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner int newval = mvalue + MUTEX_COUNTER_BITS_ONE; 1165e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__likely(__bionic_cmpxchg(mvalue, newval, &mutex->value) == 0)) { 1166e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* mutex is still locked, not need for a memory barrier */ 1167e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1168e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1169e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the value was changed, this happens when another thread changes 1170e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the lower state bits from 1 to 2 to indicate contention. This 1171e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * cannot change the counter, so simply reload and try again. 1172e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1173e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1174e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 11751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 11761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 11777c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian__LIBC_HIDDEN__ 11787c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_lock_impl(pthread_mutex_t *mutex) 11791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1180a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville int mvalue, mtype, tid, shared; 118140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 118240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__unlikely(mutex == NULL)) 118340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EINVAL; 118440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1185022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mvalue = mutex->value; 1186022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mtype = (mvalue & MUTEX_TYPE_MASK); 1187022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner shared = (mvalue & MUTEX_SHARED_MASK); 118840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 118940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Handle normal case first */ 1190e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( __likely(mtype == MUTEX_TYPE_BITS_NORMAL) ) { 1191022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner _normal_lock(mutex, shared); 119240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return 0; 119340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 119440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 119540e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Do we already own this recursive or error-check mutex ? */ 119640e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner tid = __get_thread()->kernel_id; 1197e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( tid == MUTEX_OWNER_FROM_BITS(mvalue) ) 1198022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner return _recursive_increment(mutex, mvalue, mtype); 119940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1200e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* Add in shared state to avoid extra 'or' operations below */ 12016304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner mtype |= shared; 120288f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 1203e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* First, if the mutex is unlocked, try to quickly acquire it. 1204e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * In the optimistic case where this works, set the state to 1 to 1205e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * indicate locked with no contention */ 1206e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (mvalue == mtype) { 1207e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner int newval = MUTEX_OWNER_TO_BITS(tid) | mtype | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; 1208e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(mvalue, newval, &mutex->value) == 0) { 1209e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); 1210e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 121140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 1212e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* argh, the value changed, reload before entering the loop */ 1213e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1214e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 121540e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1216e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner for (;;) { 1217e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner int newval; 121840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1219e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* if the mutex is unlocked, its value should be 'mtype' and 1220e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * we try to acquire it by setting its owner and state atomically. 1221e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * NOTE: We put the state to 2 since we _know_ there is contention 1222e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * when we are in this loop. This ensures all waiters will be 1223e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * unlocked. 122440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner */ 1225e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (mvalue == mtype) { 1226e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner newval = MUTEX_OWNER_TO_BITS(tid) | mtype | MUTEX_STATE_BITS_LOCKED_CONTENDED; 1227e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* TODO: Change this to __bionic_cmpxchg_acquire when we 1228e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * implement it to get rid of the explicit memory 1229e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * barrier below. 1230e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1231e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__unlikely(__bionic_cmpxchg(mvalue, newval, &mutex->value) != 0)) { 1232e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1233e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner continue; 1234e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1235e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); 1236e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1237e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1238e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 1239e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the mutex is already locked by another thread, if its state is 1 1240e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * we will change it to 2 to indicate contention. */ 1241e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(mvalue)) { 1242e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner newval = MUTEX_STATE_BITS_FLIP_CONTENTION(mvalue); /* locked state 1 => state 2 */ 1243e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__unlikely(__bionic_cmpxchg(mvalue, newval, &mutex->value) != 0)) { 1244e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1245e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner continue; 1246e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1247e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = newval; 1248e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1249e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 1250e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* wait until the mutex is unlocked */ 1251e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner __futex_wait_ex(&mutex->value, shared, mvalue, NULL); 125240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1253e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 125440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 1255e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* NOTREACHED */ 12561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 12571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 12587c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_lock(pthread_mutex_t *mutex) 12597c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian{ 12607c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian int err = pthread_mutex_lock_impl(mutex); 12617c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#ifdef PTHREAD_DEBUG 12627c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (PTHREAD_DEBUG_ENABLED) { 12637c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (!err) { 12647c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian pthread_debug_mutex_lock_check(mutex); 12657c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 12667c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 12677c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#endif 12687c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return err; 12697c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian} 12701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 12717c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian__LIBC_HIDDEN__ 12727c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_unlock_impl(pthread_mutex_t *mutex) 12731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1274a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville int mvalue, mtype, tid, shared; 1275ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner 127640e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__unlikely(mutex == NULL)) 127740e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EINVAL; 127840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1279022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mvalue = mutex->value; 1280022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mtype = (mvalue & MUTEX_TYPE_MASK); 1281022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner shared = (mvalue & MUTEX_SHARED_MASK); 128240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 128340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Handle common case first */ 1284e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__likely(mtype == MUTEX_TYPE_BITS_NORMAL)) { 1285022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner _normal_unlock(mutex, shared); 12868641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio return 0; 1287ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner } 128840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 128940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Do we already own this recursive or error-check mutex ? */ 129040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner tid = __get_thread()->kernel_id; 1291e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( tid != MUTEX_OWNER_FROM_BITS(mvalue) ) 129240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EPERM; 129340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1294e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* If the counter is > 0, we can simply decrement it atomically. 1295e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * Since other threads can mutate the lower state bits (and only the 1296e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * lower state bits), use a cmpxchg to do it. 1297e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1298e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (!MUTEX_COUNTER_BITS_IS_ZERO(mvalue)) { 1299e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner for (;;) { 1300e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner int newval = mvalue - MUTEX_COUNTER_BITS_ONE; 1301e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__likely(__bionic_cmpxchg(mvalue, newval, &mutex->value) == 0)) { 1302e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* success: we still own the mutex, so no memory barrier */ 1303e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1304e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1305e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the value changed, so reload and loop */ 1306e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1307e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 130840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 1309e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 1310e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the counter is 0, so we're going to unlock the mutex by resetting 1311e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * its value to 'unlocked'. We need to perform a swap in order 1312e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * to read the current state, which will be 2 if there are waiters 1313e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * to awake. 1314e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * 1315e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * TODO: Change this to __bionic_swap_release when we implement it 1316e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * to get rid of the explicit memory barrier below. 1317e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1318e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); /* RELEASE BARRIER */ 1319e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = __bionic_swap(mtype | shared | MUTEX_STATE_BITS_UNLOCKED, &mutex->value); 132040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 132140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Wake one waiting thread, if any */ 1322e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(mvalue)) { 13236304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner __futex_wake_ex(&mutex->value, shared, 1); 132488f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner } 132540e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return 0; 13261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 13271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 13287c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_unlock(pthread_mutex_t *mutex) 13297c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian{ 13307c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#ifdef PTHREAD_DEBUG 13317c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (PTHREAD_DEBUG_ENABLED) { 13327c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian pthread_debug_mutex_unlock_check(mutex); 13337c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 13347c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#endif 13357c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return pthread_mutex_unlock_impl(mutex); 13367c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian} 13371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 13387c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian__LIBC_HIDDEN__ 13397c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_trylock_impl(pthread_mutex_t *mutex) 13401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1341a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville int mvalue, mtype, tid, shared; 13421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 134340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__unlikely(mutex == NULL)) 134440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EINVAL; 13451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1346022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mvalue = mutex->value; 1347022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mtype = (mvalue & MUTEX_TYPE_MASK); 1348022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner shared = (mvalue & MUTEX_SHARED_MASK); 13491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 135040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Handle common case first */ 1351e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( __likely(mtype == MUTEX_TYPE_BITS_NORMAL) ) 135240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner { 1353e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(shared|MUTEX_STATE_BITS_UNLOCKED, 1354e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner shared|MUTEX_STATE_BITS_LOCKED_UNCONTENDED, 1355e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner &mutex->value) == 0) { 1356fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden ANDROID_MEMBAR_FULL(); 13578641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio return 0; 1358fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden } 135940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 136040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EBUSY; 136140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 136240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 136340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Do we already own this recursive or error-check mutex ? */ 136440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner tid = __get_thread()->kernel_id; 1365e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( tid == MUTEX_OWNER_FROM_BITS(mvalue) ) 1366022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner return _recursive_increment(mutex, mvalue, mtype); 136740e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1368e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* Same as pthread_mutex_lock, except that we don't want to wait, and 1369e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the only operation that can succeed is a single cmpxchg to acquire the 1370e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * lock if it is released / not owned by anyone. No need for a complex loop. 1371e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1372e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mtype |= shared | MUTEX_STATE_BITS_UNLOCKED; 1373e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = MUTEX_OWNER_TO_BITS(tid) | mtype | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; 137440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1375e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__likely(__bionic_cmpxchg(mtype, mvalue, &mutex->value) == 0)) { 1376e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); 1377e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1378e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 137940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1380e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return EBUSY; 13811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 13821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 13837c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_trylock(pthread_mutex_t *mutex) 13847c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian{ 13857c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian int err = pthread_mutex_trylock_impl(mutex); 13867c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#ifdef PTHREAD_DEBUG 13877c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (PTHREAD_DEBUG_ENABLED) { 13887c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (!err) { 13897c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian pthread_debug_mutex_lock_check(mutex); 13907c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 13917c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 13927c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#endif 13937c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return err; 13947c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian} 13951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 13963f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner/* initialize 'ts' with the difference between 'abstime' and the current time 13973f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner * according to 'clock'. Returns -1 if abstime already expired, or 0 otherwise. 13983f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner */ 13993f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turnerstatic int 14003f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner__timespec_to_absolute(struct timespec* ts, const struct timespec* abstime, clockid_t clock) 14013f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner{ 14023f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner clock_gettime(clock, ts); 14033f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner ts->tv_sec = abstime->tv_sec - ts->tv_sec; 14043f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner ts->tv_nsec = abstime->tv_nsec - ts->tv_nsec; 14053f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner if (ts->tv_nsec < 0) { 14063f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner ts->tv_sec--; 14073f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner ts->tv_nsec += 1000000000; 14083f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner } 1409bc10cd2900cdb7fed077163b6a33e0f8572b2b19David 'Digit' Turner if ((ts->tv_nsec < 0) || (ts->tv_sec < 0)) 14103f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner return -1; 14113f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 14123f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner return 0; 14133f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner} 14143f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 14153f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner/* initialize 'abstime' to the current time according to 'clock' plus 'msecs' 14163f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner * milliseconds. 14173f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner */ 14183f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turnerstatic void 14193f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner__timespec_to_relative_msec(struct timespec* abstime, unsigned msecs, clockid_t clock) 14203f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner{ 14213f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner clock_gettime(clock, abstime); 14223f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner abstime->tv_sec += msecs/1000; 14233f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner abstime->tv_nsec += (msecs%1000)*1000000; 14243f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner if (abstime->tv_nsec >= 1000000000) { 14253f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner abstime->tv_sec++; 14263f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner abstime->tv_nsec -= 1000000000; 14273f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner } 14283f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner} 14293f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 14307c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian__LIBC_HIDDEN__ 14317c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_lock_timeout_np_impl(pthread_mutex_t *mutex, unsigned msecs) 14323f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner{ 14333f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner clockid_t clock = CLOCK_MONOTONIC; 14343f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner struct timespec abstime; 14353f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner struct timespec ts; 1436a12c54454f3a6132988b68873903f6e9eed7f384Wink Saville int mvalue, mtype, tid, shared; 14373f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 14383f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner /* compute absolute expiration time */ 14393f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner __timespec_to_relative_msec(&abstime, msecs, clock); 14403f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 144140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__unlikely(mutex == NULL)) 144240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EINVAL; 144340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1444022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mvalue = mutex->value; 1445022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner mtype = (mvalue & MUTEX_TYPE_MASK); 1446022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner shared = (mvalue & MUTEX_SHARED_MASK); 144740e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 144840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Handle common case first */ 1449e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( __likely(mtype == MUTEX_TYPE_BITS_NORMAL) ) 1450ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner { 1451e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; 1452e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; 1453e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner const int locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED; 1454e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 1455e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* fast path for uncontended lock. Note: MUTEX_TYPE_BITS_NORMAL is 0 */ 1456e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(unlocked, locked_uncontended, &mutex->value) == 0) { 1457fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden ANDROID_MEMBAR_FULL(); 145840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return 0; 1459fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden } 14608641833b62e3b319796dc80ea16eb1592c05edf6Fabrice Di Meglio 146140e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* loop while needed */ 1462e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner while (__bionic_swap(locked_contended, &mutex->value) != unlocked) { 146340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__timespec_to_absolute(&ts, &abstime, clock) < 0) 146440e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EBUSY; 146540e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1466e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner __futex_wait_ex(&mutex->value, shared, locked_contended, &ts); 146740e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 1468fcd00ebbdf3e7f4e1e7782a65ae10fb0fc03a1aaAndy McFadden ANDROID_MEMBAR_FULL(); 146940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return 0; 147040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner } 14713f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 147240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner /* Do we already own this recursive or error-check mutex ? */ 147340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner tid = __get_thread()->kernel_id; 1474e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if ( tid == MUTEX_OWNER_FROM_BITS(mvalue) ) 1475022d303116f742cd337852d37547e2ea24d97a25David 'Digit' Turner return _recursive_increment(mutex, mvalue, mtype); 147640e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1477e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the following implements the same loop than pthread_mutex_lock_impl 1478e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * but adds checks to ensure that the operation never exceeds the 1479e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * absolute expiration time. 148040e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner */ 1481e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mtype |= shared; 148240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1483e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* first try a quick lock */ 1484e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (mvalue == mtype) { 1485e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = MUTEX_OWNER_TO_BITS(tid) | mtype | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; 1486e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__likely(__bionic_cmpxchg(mtype, mvalue, &mutex->value) == 0)) { 1487e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); 1488e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1489e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1490e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1491e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 149288f06cd84a70f8a5212cb03272ec2c7cf0017afaDavid 'Digit' Turner 149340e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner for (;;) { 1494e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner struct timespec ts; 1495e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner 1496e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* if the value is 'unlocked', try to acquire it directly */ 1497e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* NOTE: put state to 2 since we know there is contention */ 1498e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (mvalue == mtype) /* unlocked */ { 1499e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = MUTEX_OWNER_TO_BITS(tid) | mtype | MUTEX_STATE_BITS_LOCKED_CONTENDED; 1500e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(mtype, mvalue, &mutex->value) == 0) { 1501e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner ANDROID_MEMBAR_FULL(); 1502e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return 0; 1503e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1504e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* the value changed before we could lock it. We need to check 1505e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * the time to avoid livelocks, reload the value, then loop again. */ 1506e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__timespec_to_absolute(&ts, &abstime, clock) < 0) 1507e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return EBUSY; 150840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1509e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1510e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner continue; 1511e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 151240e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1513e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* The value is locked. If 'uncontended', try to switch its state 1514e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * to 'contented' to ensure we get woken up later. */ 1515e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(mvalue)) { 1516e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner int newval = MUTEX_STATE_BITS_FLIP_CONTENTION(mvalue); 1517e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__bionic_cmpxchg(mvalue, newval, &mutex->value) != 0) { 1518e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* this failed because the value changed, reload it */ 1519e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1520e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } else { 1521e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* this succeeded, update mvalue */ 1522e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = newval; 1523e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1524e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 152540e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1526e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* check time and update 'ts' */ 152740e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner if (__timespec_to_absolute(&ts, &abstime, clock) < 0) 152840e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner return EBUSY; 152940e6b822866ee59f7823000384321bb899416cb1David 'Digit' Turner 1530e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* Only wait to be woken up if the state is '2', otherwise we'll 1531e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * simply loop right now. This can happen when the second cmpxchg 1532e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * in our loop failed because the mutex was unlocked by another 1533e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner * thread. 1534e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner */ 1535e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(mvalue)) { 1536e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner if (__futex_wait_ex(&mutex->value, shared, mvalue, &ts) == ETIMEDOUT) { 1537e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner return EBUSY; 1538e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1539e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner mvalue = mutex->value; 1540e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner } 1541ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner } 1542e1414aa96bb62057b1a25c6a9ea1797dd38dce59David 'Digit' Turner /* NOTREACHED */ 1543ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner} 1544ba9c6f0989ae94778ba2b9f597adc827c9dc81e8David 'Digit' Turner 15457c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs) 15467c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian{ 15477c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian int err = pthread_mutex_lock_timeout_np_impl(mutex, msecs); 15487c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#ifdef PTHREAD_DEBUG 15497c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (PTHREAD_DEBUG_ENABLED) { 15507c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (!err) { 15517c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian pthread_debug_mutex_lock_check(mutex); 15527c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 15537c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian } 15547c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian#endif 15557c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return err; 15567c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian} 15577c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 15587c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopianint pthread_mutex_destroy(pthread_mutex_t *mutex) 15597c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian{ 15607c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian int ret; 15617c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 15627c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian /* use trylock to ensure that the mutex value is 15637c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian * valid and is not already locked. */ 15647c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian ret = pthread_mutex_trylock_impl(mutex); 15657c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian if (ret != 0) 15667c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return ret; 15677c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 15687c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian mutex->value = 0xdead10cc; 15697c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian return 0; 15707c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian} 15717c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 15727c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 15737c0c3793722aea293c45921ef50e4adcdf9645ceMathias Agopian 1574ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turnerint pthread_condattr_init(pthread_condattr_t *attr) 1575ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner{ 1576ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (attr == NULL) 1577ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1578ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1579ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner *attr = PTHREAD_PROCESS_PRIVATE; 1580ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return 0; 1581ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner} 1582ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1583ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turnerint pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared) 1584ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner{ 1585ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (attr == NULL || pshared == NULL) 1586ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1587ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1588ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner *pshared = *attr; 1589ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return 0; 1590ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner} 1591ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1592ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turnerint pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) 1593ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner{ 1594ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (attr == NULL) 1595ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1596ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1597ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (pshared != PTHREAD_PROCESS_SHARED && 1598ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner pshared != PTHREAD_PROCESS_PRIVATE) 1599ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1600ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1601ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner *attr = pshared; 1602ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return 0; 1603ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner} 1604ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1605ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turnerint pthread_condattr_destroy(pthread_condattr_t *attr) 1606ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner{ 1607ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (attr == NULL) 1608ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1609ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1610ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner *attr = 0xdeada11d; 1611ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return 0; 1612ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner} 1613ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1614ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner/* We use one bit in condition variable values as the 'shared' flag 1615ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner * The rest is a counter. 1616ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner */ 1617b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner#define COND_SHARED_MASK 0x0001 1618ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner#define COND_COUNTER_INCREMENT 0x0002 1619b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner#define COND_COUNTER_MASK (~COND_SHARED_MASK) 1620b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner 1621b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner#define COND_IS_SHARED(c) (((c)->value & COND_SHARED_MASK) != 0) 16223f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner 16231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* XXX *technically* there is a race condition that could allow 16241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * XXX a signal to be missed. If thread A is preempted in _wait() 16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * XXX after unlocking the mutex and before waiting, and if other 1626ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner * XXX threads call signal or broadcast UINT_MAX/2 times (exactly), 16271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * XXX before thread A is scheduled again and calls futex_wait(), 16281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * XXX then the signal will be lost. 16291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_init(pthread_cond_t *cond, 16321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const pthread_condattr_t *attr) 16331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1634ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (cond == NULL) 1635ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1636ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 16371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project cond->value = 0; 1638ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1639ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (attr != NULL && *attr == PTHREAD_PROCESS_SHARED) 1640b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner cond->value |= COND_SHARED_MASK; 1641ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_destroy(pthread_cond_t *cond) 16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1647ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner if (cond == NULL) 1648ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner return EINVAL; 1649ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 16501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project cond->value = 0xdeadc04d; 16511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 16521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1654ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner/* This function is used by pthread_cond_broadcast and 1655b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner * pthread_cond_signal to atomically decrement the counter 1656b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner * then wake-up 'counter' threads. 1657ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner */ 1658b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turnerstatic int 1659b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner__pthread_cond_pulse(pthread_cond_t *cond, int counter) 1660ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner{ 1661b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner long flags; 1662b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner 1663b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner if (__unlikely(cond == NULL)) 1664b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner return EINVAL; 1665ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 1666b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner flags = (cond->value & ~COND_COUNTER_MASK); 1667ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner for (;;) { 1668ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner long oldval = cond->value; 1669ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner long newval = ((oldval - COND_COUNTER_INCREMENT) & COND_COUNTER_MASK) 1670ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner | flags; 1671e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner if (__bionic_cmpxchg(oldval, newval, &cond->value) == 0) 1672ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner break; 1673ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner } 1674b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner 1675e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden /* 1676e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * Ensure that all memory accesses previously made by this thread are 1677e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * visible to the woken thread(s). On the other side, the "wait" 1678e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * code will issue any necessary barriers when locking the mutex. 1679e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * 1680e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * This may not strictly be necessary -- if the caller follows 1681e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * recommended practice and holds the mutex before signaling the cond 1682e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * var, the mutex ops will provide correct semantics. If they don't 1683e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden * hold the mutex, they're subject to race conditions anyway. 1684e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden */ 1685e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden ANDROID_MEMBAR_FULL(); 1686e2ac89869f9b459faa22640fb1bb41e818c1dd55Andy McFadden 16876304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner __futex_wake_ex(&cond->value, COND_IS_SHARED(cond), counter); 1688b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner return 0; 1689ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner} 1690ee7b077abf1d99503b986489ad93374a057cb354David 'Digit' Turner 16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_broadcast(pthread_cond_t *cond) 16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1693b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner return __pthread_cond_pulse(cond, INT_MAX); 16941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_signal(pthread_cond_t *cond) 16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1698b5e4a416060aa7f0a1e2a9ad5b8e318d59986852David 'Digit' Turner return __pthread_cond_pulse(cond, 1); 16991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 17021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return pthread_cond_timedwait(cond, mutex, NULL); 17041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint __pthread_cond_timedwait_relative(pthread_cond_t *cond, 17071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t * mutex, 17081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const struct timespec *reltime) 17091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int status; 17111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int oldvalue = cond->value; 17121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(mutex); 17146304d8b21891fd0cb7b5a4c25159a3d3b1709d62David 'Digit' Turner status = __futex_wait_ex(&cond->value, COND_IS_SHARED(cond), oldvalue, reltime); 17151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(mutex); 17161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (status == (-ETIMEDOUT)) return ETIMEDOUT; 17181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 17191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint __pthread_cond_timedwait(pthread_cond_t *cond, 17221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t * mutex, 17231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const struct timespec *abstime, 17241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project clockid_t clock) 17251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec ts; 17271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec * tsp; 17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (abstime != NULL) { 17303f56b7f65adb9ee35cd0f878ca00b92011eec427David 'Digit' Turner if (__timespec_to_absolute(&ts, abstime, clock) < 0) 17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ETIMEDOUT; 17321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tsp = &ts; 17331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tsp = NULL; 17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 17361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __pthread_cond_timedwait_relative(cond, mutex, tsp); 17381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_timedwait(pthread_cond_t *cond, 17411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t * mutex, 17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const struct timespec *abstime) 17431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __pthread_cond_timedwait(cond, mutex, abstime, CLOCK_REALTIME); 17451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1748a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian/* this one exists only for backward binary compatibility */ 17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_timedwait_monotonic(pthread_cond_t *cond, 17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t * mutex, 17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const struct timespec *abstime) 17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __pthread_cond_timedwait(cond, mutex, abstime, CLOCK_MONOTONIC); 17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1756a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopianint pthread_cond_timedwait_monotonic_np(pthread_cond_t *cond, 1757a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian pthread_mutex_t * mutex, 1758a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian const struct timespec *abstime) 1759a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian{ 1760a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian return __pthread_cond_timedwait(cond, mutex, abstime, CLOCK_MONOTONIC); 1761a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian} 1762a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian 1763a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopianint pthread_cond_timedwait_relative_np(pthread_cond_t *cond, 1764a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian pthread_mutex_t * mutex, 1765a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian const struct timespec *reltime) 1766a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian{ 1767a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian return __pthread_cond_timedwait_relative(cond, mutex, reltime); 1768a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian} 1769a2f5e212448f36f0b35cf695d13bb4defdb4472eMathias Agopian 17701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_cond_timeout_np(pthread_cond_t *cond, 17711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t * mutex, 17721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project unsigned msecs) 17731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 17741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec ts; 17751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ts.tv_sec = msecs / 1000; 17771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ts.tv_nsec = (msecs % 1000) * 1000000; 17781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1779a4e67f4512e2609c13a67d569bff14001413a042Matthieu CASTET return __pthread_cond_timedwait_relative(cond, mutex, &ts); 17801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* A technical note regarding our thread-local-storage (TLS) implementation: 17851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * There can be up to TLSMAP_SIZE independent TLS keys in a given process, 17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * though the first TLSMAP_START keys are reserved for Bionic to hold 17881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * special thread-specific variables like errno or a pointer to 17891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the current thread's descriptor. 17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 17911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * while stored in the TLS area, these entries cannot be accessed through 17921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * pthread_getspecific() / pthread_setspecific() and pthread_key_delete() 17931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 17941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * also, some entries in the key table are pre-allocated (see tlsmap_lock) 17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to greatly simplify and speedup some OpenGL-related operations. though the 17961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * initialy value will be NULL on all threads. 17971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 17981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * you can use pthread_getspecific()/setspecific() on these, and in theory 17991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * you could also call pthread_key_delete() as well, though this would 18001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * probably break some apps. 18011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The 'tlsmap_t' type defined below implements a shared global map of 18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * currently created/allocated TLS keys and the destructors associated 18041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * with them. You should use tlsmap_lock/unlock to access it to avoid 18051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * any race condition. 18061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the global TLS map simply contains a bitmap of allocated keys, and 18081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * an array of destructors. 18091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * each thread has a TLS area that is a simple array of TLSMAP_SIZE void* 18111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * pointers. the TLS area of the main thread is stack-allocated in 18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * __libc_init_common, while the TLS area of other threads is placed at 18131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the top of their stack in pthread_create. 18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * when pthread_key_create() is called, it finds the first free key in the 18161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * bitmap, then set it to 1, saving the destructor altogether 18171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * when pthread_key_delete() is called. it will erase the key's bitmap bit 18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and its destructor, and will also clear the key data in the TLS area of 18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * all created threads. As mandated by Posix, it is the responsability of 18211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the caller of pthread_key_delete() to properly reclaim the objects that 18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * were pointed to by these data fields (either before or after the call). 18231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 18251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TLS Map implementation 18271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 18281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_START (TLS_SLOT_MAX_WELL_KNOWN+1) 18301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_SIZE BIONIC_TLS_SLOTS 18311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_BITS 32 18321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_WORDS ((TLSMAP_SIZE+TLSMAP_BITS-1)/TLSMAP_BITS) 18331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_WORD(m,k) (m)->map[(k)/TLSMAP_BITS] 18341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_MASK(k) (1U << ((k)&(TLSMAP_BITS-1))) 18351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* this macro is used to quickly check that a key belongs to a reasonable range */ 18371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TLSMAP_VALIDATE_KEY(key) \ 18381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ((key) >= TLSMAP_START && (key) < TLSMAP_SIZE) 18391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* the type of tls key destructor functions */ 18411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef void (*tls_dtor_t)(void*); 18421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct { 18441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int init; /* see comment in tlsmap_lock() */ 18451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint32_t map[TLSMAP_WORDS]; /* bitmap of allocated keys */ 18461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tls_dtor_t dtors[TLSMAP_SIZE]; /* key destructors */ 18471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} tlsmap_t; 18481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic pthread_mutex_t _tlsmap_lock = PTHREAD_MUTEX_INITIALIZER; 18501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic tlsmap_t _tlsmap; 18511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* lock the global TLS map lock and return a handle to it */ 18531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ tlsmap_t* tlsmap_lock(void) 18541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 18551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_t* m = &_tlsmap; 18561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&_tlsmap_lock); 18581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* we need to initialize the first entry of the 'map' array 18591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * with the value TLS_DEFAULT_ALLOC_MAP. doing it statically 18601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * when declaring _tlsmap is a bit awkward and is going to 18611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * produce warnings, so do it the first time we use the map 18621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * instead 18631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 18641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (__unlikely(!m->init)) { 18651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project TLSMAP_WORD(m,0) = TLS_DEFAULT_ALLOC_MAP; 18661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project m->init = 1; 18671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return m; 18691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* unlock the global TLS map */ 18721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void tlsmap_unlock(tlsmap_t* m) 18731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 18741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&_tlsmap_lock); 18751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project (void)m; /* a good compiler is a happy compiler */ 18761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* test to see wether a key is allocated */ 18791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ int tlsmap_test(tlsmap_t* m, int key) 18801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 18811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (TLSMAP_WORD(m,key) & TLSMAP_MASK(key)) != 0; 18821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* set the destructor and bit flag on a newly allocated key */ 18851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void tlsmap_set(tlsmap_t* m, int key, tls_dtor_t dtor) 18861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 18871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project TLSMAP_WORD(m,key) |= TLSMAP_MASK(key); 18881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project m->dtors[key] = dtor; 18891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* clear the destructor and bit flag on an existing key */ 18921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void tlsmap_clear(tlsmap_t* m, int key) 18931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 18941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project TLSMAP_WORD(m,key) &= ~TLSMAP_MASK(key); 18951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project m->dtors[key] = NULL; 18961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* allocate a new TLS key, return -1 if no room left */ 18991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int tlsmap_alloc(tlsmap_t* m, tls_dtor_t dtor) 19001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 19011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int key; 19021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for ( key = TLSMAP_START; key < TLSMAP_SIZE; key++ ) { 19041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( !tlsmap_test(m, key) ) { 19051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_set(m, key, dtor); 19061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return key; 19071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 19101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 19111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_key_create(pthread_key_t *key, void (*destructor_function)(void *)) 19141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 19151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint32_t err = ENOMEM; 19161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_t* map = tlsmap_lock(); 19171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int k = tlsmap_alloc(map, destructor_function); 19181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (k >= 0) { 19201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *key = k; 19211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project err = 0; 19221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_unlock(map); 19241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return err; 19251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 19261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* This deletes a pthread_key_t. note that the standard mandates that this does 19291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * not call the destructor of non-NULL key values. Instead, it is the 1930bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes * responsibility of the caller to properly dispose of the corresponding data 1931bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes * and resources, using any means it finds suitable. 19321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 19331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * On the other hand, this function will clear the corresponding key data 19341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * values in all known threads. this prevents later (invalid) calls to 19351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * pthread_getspecific() to receive invalid/stale values. 19361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 19371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_key_delete(pthread_key_t key) 19381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 19391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project uint32_t err; 19401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thr; 19411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_t* map; 19421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!TLSMAP_VALIDATE_KEY(key)) { 19441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return EINVAL; 19451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project map = tlsmap_lock(); 19481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!tlsmap_test(map, key)) { 19501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project err = EINVAL; 19511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto err1; 19521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* clear value in all threads */ 19551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&gThreadListLock); 19561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for ( thr = gThreadList; thr != NULL; thr = thr->next ) { 19571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* avoid zombie threads with a negative 'join_count'. these are really 19581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * already dead and don't have a TLS area anymore. 19591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 19601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * similarly, it is possible to have thr->tls == NULL for threads that 19611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * were just recently created through pthread_create() but whose 19621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * startup trampoline (__thread_entry) hasn't been run yet by the 19630753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson * scheduler. thr->tls will also be NULL after it's stack has been 19640753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson * unmapped but before the ongoing pthread_join() is finished. 19650753dc653eb3b84d3490212437e7490975d4c020Bjorn Andersson * so check for this too. 19661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 19671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (thr->join_count < 0 || !thr->tls) 19681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project continue; 19691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr->tls[key] = NULL; 19711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_clear(map, key); 19731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&gThreadListLock); 19751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project err = 0; 19761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterr1: 19781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_unlock(map); 19791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return err; 19801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 19811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_setspecific(pthread_key_t key, const void *ptr) 19841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 19851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int err = EINVAL; 19861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_t* map; 19871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 19881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (TLSMAP_VALIDATE_KEY(key)) { 19891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* check that we're trying to set data for an allocated key */ 19901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project map = tlsmap_lock(); 19911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (tlsmap_test(map, key)) { 19921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ((uint32_t *)__get_tls())[key] = (uint32_t)ptr; 19931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project err = 0; 19941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_unlock(map); 19961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 19971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return err; 19981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 19991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid * pthread_getspecific(pthread_key_t key) 20011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 20021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!TLSMAP_VALIDATE_KEY(key)) { 20031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return NULL; 20041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* for performance reason, we do not lock/unlock the global TLS map 20071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to check that the key is properly allocated. if the key was not 20081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * allocated, the value read from the TLS should always be NULL 20091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * due to pthread_key_delete() clearing the values for all threads. 20101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (void *)(((unsigned *)__get_tls())[key]); 20121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 20131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Posix mandates that this be defined in <limits.h> but we don't have 20151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * it just yet. 20161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef PTHREAD_DESTRUCTOR_ITERATIONS 20181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# define PTHREAD_DESTRUCTOR_ITERATIONS 4 20191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 20201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* this function is called from pthread_exit() to remove all TLS key data 20221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * from this thread's TLS area. this must call the destructor of all keys 20231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * that have a non-NULL data value (and a non-NULL destructor). 20241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 20251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * because destructors can do funky things like deleting/creating other 20261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * keys, we need to implement this in a loop 20271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void pthread_key_clean_all(void) 20291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 20301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_t* map; 20311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void** tls = (void**)__get_tls(); 20321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int rounds = PTHREAD_DESTRUCTOR_ITERATIONS; 20331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project map = tlsmap_lock(); 20351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (rounds = PTHREAD_DESTRUCTOR_ITERATIONS; rounds > 0; rounds--) 20371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project { 20381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int kk, count = 0; 20391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (kk = TLSMAP_START; kk < TLSMAP_SIZE; kk++) { 20411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( tlsmap_test(map, kk) ) 20421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project { 20431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project void* data = tls[kk]; 20441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tls_dtor_t dtor = map->dtors[kk]; 20451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (data != NULL && dtor != NULL) 20471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project { 20481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* we need to clear the key data now, this will prevent the 20491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * destructor (or a later one) from seeing the old value if 20501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * it calls pthread_getspecific() for some odd reason 20511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 20521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * we do not do this if 'dtor == NULL' just in case another 20531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * destructor function might be responsible for manually 20541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * releasing the corresponding data. 20551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tls[kk] = NULL; 20571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* because the destructor is free to call pthread_key_create 20591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and/or pthread_key_delete, we need to temporarily unlock 20601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the TLS map 20611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_unlock(map); 20631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project (*dtor)(data); 20641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project map = tlsmap_lock(); 20651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project count += 1; 20671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* if we didn't call any destructor, there is no need to check the 20721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * TLS data again 20731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 20741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (count == 0) 20751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project break; 20761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project tlsmap_unlock(map); 20781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 20791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// man says this should be in <linux/unistd.h>, but it isn't 208110c8ce59a40a1d8ae8f49145eca365b364aabe58Jeff Brownextern int tgkill(int tgid, int tid, int sig); 20821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_kill(pthread_t tid, int sig) 20841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 20851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int ret; 20861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int old_errno = errno; 20871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t * thread = (pthread_internal_t *)tid; 20881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 208910c8ce59a40a1d8ae8f49145eca365b364aabe58Jeff Brown ret = tgkill(getpid(), thread->kernel_id, sig); 20901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (ret < 0) { 20911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ret = errno; 20921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = old_errno; 20931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ret; 20961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 20971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_getcpuclockid(pthread_t tid, clockid_t *clockid) 21001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 21011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const int CLOCK_IDTYPE_BITS = 3; 21021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_internal_t* thread = (pthread_internal_t*)tid; 21031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!thread) 21051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return ESRCH; 21061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *clockid = CLOCK_THREAD_CPUTIME_ID | (thread->kernel_id << CLOCK_IDTYPE_BITS); 21081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 21091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 21101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* NOTE: this implementation doesn't support a init function that throws a C++ exception 21131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * or calls fork() 21141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 21151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint pthread_once( pthread_once_t* once_control, void (*init_routine)(void) ) 21161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2117b1c9cc2f2d1b0478b07278cdef885cabf1cd2798Andy McFadden volatile pthread_once_t* ocptr = once_control; 21181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21196c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* PTHREAD_ONCE_INIT is 0, we use the following bit flags 21206c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * 21216c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * bit 0 set -> initialization is under way 21226c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * bit 1 set -> initialization is complete 21236c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner */ 21246c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner#define ONCE_INITIALIZING (1 << 0) 21256c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner#define ONCE_COMPLETED (1 << 1) 21266c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21276c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* First check if the once is already initialized. This will be the common 21286c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * case and we want to make this as fast as possible. Note that this still 21296c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * requires a load_acquire operation here to ensure that all the 21306c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * stores performed by the initialization function are observable on 21316c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * this CPU after we exit. 21326c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner */ 21336c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner if (__likely((*ocptr & ONCE_COMPLETED) != 0)) { 21346c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner ANDROID_MEMBAR_FULL(); 21356c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner return 0; 21366c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner } 21376c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21386c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner for (;;) { 21396c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* Try to atomically set the INITIALIZING flag. 21406c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * This requires a cmpxchg loop, and we may need 2141bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes * to exit prematurely if we detect that 21426c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * COMPLETED is now set. 21436c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner */ 21446c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner int32_t oldval, newval; 21456c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21466c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner do { 21476c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner oldval = *ocptr; 21486c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner if ((oldval & ONCE_COMPLETED) != 0) 21496c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner break; 21506c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21516c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner newval = oldval | ONCE_INITIALIZING; 21526c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner } while (__bionic_cmpxchg(oldval, newval, ocptr) != 0); 21536c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21546c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner if ((oldval & ONCE_COMPLETED) != 0) { 21556c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* We detected that COMPLETED was set while in our loop */ 2156b1c9cc2f2d1b0478b07278cdef885cabf1cd2798Andy McFadden ANDROID_MEMBAR_FULL(); 21576c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner return 0; 21586c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner } 21596c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21606c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner if ((oldval & ONCE_INITIALIZING) == 0) { 21616c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* We got there first, we can jump out of the loop to 21626c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * handle the initialization */ 21636c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner break; 21641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21656c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21666c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* Another thread is running the initialization and hasn't completed 21676c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner * yet, so wait for it, then try again. */ 21686c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner __futex_wait_ex(ocptr, 0, oldval, NULL); 21691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21706c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21716c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* call the initialization function. */ 21726c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner (*init_routine)(); 21736c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21746c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* Do a store_release indicating that initialization is complete */ 21756c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner ANDROID_MEMBAR_FULL(); 21766c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner *ocptr = ONCE_COMPLETED; 21776c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21786c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner /* Wake up any waiters, if any */ 21796c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner __futex_wake_ex(ocptr, 0, INT_MAX); 21806c6de44f0479b202c39555f5c22ef8c494837d3cDavid 'Digit' Turner 21811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 21821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 218378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 218478c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa/* This value is not exported by kernel headers, so hardcode it here */ 218578c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa#define MAX_TASK_COMM_LEN 16 218678c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa#define TASK_COMM_FMT "/proc/self/task/%u/comm" 218778c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 218878c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosaint pthread_setname_np(pthread_t thid, const char *thname) 218978c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa{ 219078c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa size_t thname_len; 219178c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa int saved_errno, ret; 219278c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 219378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa if (thid == 0 || thname == NULL) 219478c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa return EINVAL; 219578c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 219678c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa thname_len = strlen(thname); 219778c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa if (thname_len >= MAX_TASK_COMM_LEN) 219878c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa return ERANGE; 219978c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 220078c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa saved_errno = errno; 220178c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa if (thid == pthread_self()) 220278c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa { 220378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ret = prctl(PR_SET_NAME, (unsigned long)thname, 0, 0, 0) ? errno : 0; 220478c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa } 220578c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa else 220678c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa { 220778c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa /* Have to change another thread's name */ 220878c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa pthread_internal_t *thread = (pthread_internal_t *)thid; 220978c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa char comm_name[sizeof(TASK_COMM_FMT) + 8]; 221078c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ssize_t n; 221178c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa int fd; 221278c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 221378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, (unsigned int)thread->kernel_id); 221478c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa fd = open(comm_name, O_RDWR); 221578c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa if (fd == -1) 221678c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa { 221778c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ret = errno; 221878c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa goto exit; 221978c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa } 222078c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa n = TEMP_FAILURE_RETRY(write(fd, thname, thname_len)); 222178c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa close(fd); 222278c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa 222378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa if (n < 0) 222478c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ret = errno; 222578c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa else if ((size_t)n != thname_len) 222678c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ret = EIO; 222778c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa else 222878c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa ret = 0; 222978c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa } 223078c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosaexit: 223178c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa errno = saved_errno; 223278c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa return ret; 223378c1c04ced772298be8bdb5a94b6ce491bb9b3e1André Goddard Rosa} 2234d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten 2235d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten/* Return the kernel thread ID for a pthread. 2236d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten * This is only defined for implementations where pthread <-> kernel is 1:1, which this is. 2237d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten * Not the same as pthread_getthreadid_np, which is commonly defined to be opaque. 2238d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten * Internal, not an NDK API. 2239d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten */ 2240d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten 2241d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kastenpid_t __pthread_gettid(pthread_t thid) 2242d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten{ 2243d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten pthread_internal_t* thread = (pthread_internal_t*)thid; 2244d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten return thread->kernel_id; 2245d53cae0e45dafdb3a83ccc3675051c0aee532111Glenn Kasten} 2246faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru 2247faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queruint __pthread_settid(pthread_t thid, pid_t tid) 2248faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru{ 2249faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru if (thid == 0) 2250faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru return EINVAL; 2251faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru 2252faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru pthread_internal_t* thread = (pthread_internal_t*)thid; 2253faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru thread->kernel_id = tid; 2254faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru 2255faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru return 0; 2256faca92f2f17cea192c5fbde4d869aa7620315196Jean-Baptiste Queru} 2257