2
* Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
#include "Threading.h"
35
#include "CurrentTime.h"
37
#include "MainThread.h"
38
#include "RandomNumberSeed.h"
39
#include "StdLibExtras.h"
40
#include "UnusedParam.h"
49
#include "jni_utility.h"
54
typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
56
static Mutex* atomicallyInitializedStaticMutex;
58
#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM)
59
static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread.
62
static Mutex& threadMapMutex()
64
DEFINE_STATIC_LOCAL(Mutex, mutex, ());
68
void initializeThreading()
70
if (!atomicallyInitializedStaticMutex) {
71
atomicallyInitializedStaticMutex = new Mutex;
73
initializeRandomNumberGenerator();
74
#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM)
75
mainThreadIdentifier = currentThread();
77
initializeMainThread();
81
void lockAtomicallyInitializedStaticMutex()
83
ASSERT(atomicallyInitializedStaticMutex);
84
atomicallyInitializedStaticMutex->lock();
87
void unlockAtomicallyInitializedStaticMutex()
89
atomicallyInitializedStaticMutex->unlock();
92
static ThreadMap& threadMap()
94
DEFINE_STATIC_LOCAL(ThreadMap, map, ());
98
static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
100
MutexLocker locker(threadMapMutex());
102
ThreadMap::iterator i = threadMap().begin();
103
for (; i != threadMap().end(); ++i) {
104
if (pthread_equal(i->second, pthreadHandle))
111
static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
113
ASSERT(!identifierByPthreadHandle(pthreadHandle));
115
MutexLocker locker(threadMapMutex());
117
static ThreadIdentifier identifierCount = 1;
119
threadMap().add(identifierCount, pthreadHandle);
121
return identifierCount++;
124
static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
126
MutexLocker locker(threadMapMutex());
128
return threadMap().get(id);
131
static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
133
MutexLocker locker(threadMapMutex());
135
ASSERT(threadMap().contains(id));
137
threadMap().remove(id);
140
#if PLATFORM(ANDROID)
141
// On the Android platform, threads must be registered with the VM before they run.
143
ThreadFunction entryPoint;
147
static void* runThreadWithRegistration(void* arg)
149
ThreadData* data = static_cast<ThreadData*>(arg);
150
JavaVM* vm = JSC::Bindings::getJavaVM();
153
if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
154
ret = data->entryPoint(data->arg);
155
vm->DetachCurrentThread();
161
ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
163
pthread_t threadHandle;
164
ThreadData* threadData = new ThreadData();
165
threadData->entryPoint = entryPoint;
166
threadData->arg = data;
168
if (pthread_create(&threadHandle, 0, runThreadWithRegistration, static_cast<void*>(threadData))) {
169
LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
172
return establishIdentifierForPthreadHandle(threadHandle);
175
ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
177
pthread_t threadHandle;
178
if (pthread_create(&threadHandle, 0, entryPoint, data)) {
179
LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
183
return establishIdentifierForPthreadHandle(threadHandle);
187
void setThreadNameInternal(const char* threadName)
189
#if HAVE(PTHREAD_SETNAME_NP)
190
pthread_setname_np(threadName);
192
UNUSED_PARAM(threadName);
196
int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
200
pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
202
int joinResult = pthread_join(pthreadHandle, result);
203
if (joinResult == EDEADLK)
204
LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
206
clearPthreadHandleForIdentifier(threadID);
210
void detachThread(ThreadIdentifier threadID)
214
pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
216
pthread_detach(pthreadHandle);
218
clearPthreadHandleForIdentifier(threadID);
221
ThreadIdentifier currentThread()
223
pthread_t currentThread = pthread_self();
224
if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
226
return establishIdentifierForPthreadHandle(currentThread);
231
#if PLATFORM(DARWIN) && !PLATFORM(CHROMIUM)
232
return pthread_main_np();
234
return currentThread() == mainThreadIdentifier;
240
pthread_mutex_init(&m_mutex, NULL);
245
pthread_mutex_destroy(&m_mutex);
250
int result = pthread_mutex_lock(&m_mutex);
251
ASSERT_UNUSED(result, !result);
254
bool Mutex::tryLock()
256
int result = pthread_mutex_trylock(&m_mutex);
263
ASSERT_NOT_REACHED();
269
int result = pthread_mutex_unlock(&m_mutex);
270
ASSERT_UNUSED(result, !result);
274
ReadWriteLock::ReadWriteLock()
276
pthread_rwlock_init(&m_readWriteLock, NULL);
279
ReadWriteLock::~ReadWriteLock()
281
pthread_rwlock_destroy(&m_readWriteLock);
284
void ReadWriteLock::readLock()
286
int result = pthread_rwlock_rdlock(&m_readWriteLock);
287
ASSERT_UNUSED(result, !result);
290
bool ReadWriteLock::tryReadLock()
292
int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
296
if (result == EBUSY || result == EAGAIN)
299
ASSERT_NOT_REACHED();
303
void ReadWriteLock::writeLock()
305
int result = pthread_rwlock_wrlock(&m_readWriteLock);
306
ASSERT_UNUSED(result, !result);
309
bool ReadWriteLock::tryWriteLock()
311
int result = pthread_rwlock_trywrlock(&m_readWriteLock);
315
if (result == EBUSY || result == EAGAIN)
318
ASSERT_NOT_REACHED();
322
void ReadWriteLock::unlock()
324
int result = pthread_rwlock_unlock(&m_readWriteLock);
325
ASSERT_UNUSED(result, !result);
328
ThreadCondition::ThreadCondition()
330
pthread_cond_init(&m_condition, NULL);
333
ThreadCondition::~ThreadCondition()
335
pthread_cond_destroy(&m_condition);
338
void ThreadCondition::wait(Mutex& mutex)
340
int result = pthread_cond_wait(&m_condition, &mutex.impl());
341
ASSERT_UNUSED(result, !result);
344
bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
346
if (absoluteTime < currentTime())
349
if (absoluteTime > INT_MAX) {
354
int timeSeconds = static_cast<int>(absoluteTime);
355
int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
358
targetTime.tv_sec = timeSeconds;
359
targetTime.tv_nsec = timeNanoseconds;
361
return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
364
void ThreadCondition::signal()
366
int result = pthread_cond_signal(&m_condition);
367
ASSERT_UNUSED(result, !result);
370
void ThreadCondition::broadcast()
372
int result = pthread_cond_broadcast(&m_condition);
373
ASSERT_UNUSED(result, !result);
378
#endif // USE(PTHREADS)