1/*
2** Copyright (C) 2007, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8**     http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#include "cutils/threads.h"
18
19// For gettid.
20#if defined(__APPLE__)
21#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
22#include <stdint.h>
23#include <stdlib.h>
24#include <sys/syscall.h>
25#include <sys/time.h>
26#include <unistd.h>
27#elif defined(__linux__) && !defined(__ANDROID__)
28#include <syscall.h>
29#include <unistd.h>
30#elif defined(_WIN32)
31#include <windows.h>
32#endif
33
34// No definition needed for Android because we'll just pick up bionic's copy.
35#ifndef __ANDROID__
36pid_t gettid() {
37#if defined(__APPLE__)
38  return syscall(SYS_thread_selfid);
39#elif defined(__linux__)
40  return syscall(__NR_gettid);
41#elif defined(_WIN32)
42  return GetCurrentThreadId();
43#endif
44}
45#endif  // __ANDROID__
46
47#if !defined(_WIN32)
48
49void*  thread_store_get( thread_store_t*  store )
50{
51    if (!store->has_tls)
52        return NULL;
53
54    return pthread_getspecific( store->tls );
55}
56
57extern void   thread_store_set( thread_store_t*          store,
58                                void*                    value,
59                                thread_store_destruct_t  destroy)
60{
61    pthread_mutex_lock( &store->lock );
62    if (!store->has_tls) {
63        if (pthread_key_create( &store->tls, destroy) != 0) {
64            pthread_mutex_unlock(&store->lock);
65            return;
66        }
67        store->has_tls = 1;
68    }
69    pthread_mutex_unlock( &store->lock );
70
71    pthread_setspecific( store->tls, value );
72}
73
74#else /* !defined(_WIN32) */
75void*  thread_store_get( thread_store_t*  store )
76{
77    if (!store->has_tls)
78        return NULL;
79
80    return (void*) TlsGetValue( store->tls );
81}
82
83void   thread_store_set( thread_store_t*          store,
84                         void*                    value,
85                         thread_store_destruct_t  destroy )
86{
87    /* XXX: can't use destructor on thread exit */
88    if (!store->lock_init) {
89        store->lock_init = -1;
90        InitializeCriticalSection( &store->lock );
91        store->lock_init = -2;
92    } else while (store->lock_init != -2) {
93        Sleep(10); /* 10ms */
94    }
95
96    EnterCriticalSection( &store->lock );
97    if (!store->has_tls) {
98        store->tls = TlsAlloc();
99        if (store->tls == TLS_OUT_OF_INDEXES) {
100            LeaveCriticalSection( &store->lock );
101            return;
102        }
103        store->has_tls = 1;
104    }
105    LeaveCriticalSection( &store->lock );
106
107    TlsSetValue( store->tls, value );
108}
109#endif /* !defined(_WIN32) */
110