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, &param) == -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