]> git.saurik.com Git - apple/javascriptcore.git/blame - wtf/ThreadingPthreads.cpp
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / wtf / ThreadingPthreads.cpp
CommitLineData
9dae56ea 1/*
ba379fdc 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
9dae56ea
A
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
17 *
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.
28 */
ba379fdc 29
9dae56ea
A
30#include "config.h"
31#include "Threading.h"
32
9dae56ea
A
33#if USE(PTHREADS)
34
35#include "CurrentTime.h"
36#include "HashMap.h"
37#include "MainThread.h"
38#include "RandomNumberSeed.h"
ba379fdc 39#include "StdLibExtras.h"
f9bf01c6
A
40#include "ThreadIdentifierDataPthreads.h"
41#include "ThreadSpecific.h"
ba379fdc 42#include "UnusedParam.h"
9dae56ea 43#include <errno.h>
f9bf01c6
A
44
45#if !COMPILER(MSVC)
9dae56ea
A
46#include <limits.h>
47#include <sys/time.h>
f9bf01c6 48#endif
9dae56ea 49
f9bf01c6 50#if OS(ANDROID)
ba379fdc
A
51#include "jni_utility.h"
52#endif
53
9dae56ea
A
54namespace WTF {
55
56typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
57
58static Mutex* atomicallyInitializedStaticMutex;
59
f9bf01c6 60void clearPthreadHandleForIdentifier(ThreadIdentifier);
9dae56ea
A
61
62static Mutex& threadMapMutex()
63{
64 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
65 return mutex;
66}
67
68void initializeThreading()
69{
4e4e5a6f
A
70 if (atomicallyInitializedStaticMutex)
71 return;
72
73 atomicallyInitializedStaticMutex = new Mutex;
74 threadMapMutex();
75 initializeRandomNumberGenerator();
9dae56ea
A
76}
77
78void lockAtomicallyInitializedStaticMutex()
79{
80 ASSERT(atomicallyInitializedStaticMutex);
81 atomicallyInitializedStaticMutex->lock();
82}
83
84void unlockAtomicallyInitializedStaticMutex()
85{
86 atomicallyInitializedStaticMutex->unlock();
87}
88
89static ThreadMap& threadMap()
90{
91 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
92 return map;
93}
94
95static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
96{
97 MutexLocker locker(threadMapMutex());
98
99 ThreadMap::iterator i = threadMap().begin();
100 for (; i != threadMap().end(); ++i) {
101 if (pthread_equal(i->second, pthreadHandle))
102 return i->first;
103 }
104
105 return 0;
106}
107
f9bf01c6 108static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
9dae56ea
A
109{
110 ASSERT(!identifierByPthreadHandle(pthreadHandle));
111
112 MutexLocker locker(threadMapMutex());
113
114 static ThreadIdentifier identifierCount = 1;
115
116 threadMap().add(identifierCount, pthreadHandle);
ba379fdc 117
9dae56ea
A
118 return identifierCount++;
119}
120
121static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
122{
123 MutexLocker locker(threadMapMutex());
ba379fdc 124
9dae56ea
A
125 return threadMap().get(id);
126}
127
f9bf01c6 128void clearPthreadHandleForIdentifier(ThreadIdentifier id)
9dae56ea
A
129{
130 MutexLocker locker(threadMapMutex());
131
132 ASSERT(threadMap().contains(id));
ba379fdc 133
9dae56ea
A
134 threadMap().remove(id);
135}
136
f9bf01c6 137#if OS(ANDROID)
ba379fdc
A
138// On the Android platform, threads must be registered with the VM before they run.
139struct ThreadData {
140 ThreadFunction entryPoint;
141 void* arg;
142};
143
144static void* runThreadWithRegistration(void* arg)
145{
146 ThreadData* data = static_cast<ThreadData*>(arg);
147 JavaVM* vm = JSC::Bindings::getJavaVM();
148 JNIEnv* env;
149 void* ret = 0;
150 if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
151 ret = data->entryPoint(data->arg);
152 vm->DetachCurrentThread();
153 }
154 delete data;
155 return ret;
156}
157
158ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
159{
160 pthread_t threadHandle;
161 ThreadData* threadData = new ThreadData();
162 threadData->entryPoint = entryPoint;
163 threadData->arg = data;
164
165 if (pthread_create(&threadHandle, 0, runThreadWithRegistration, static_cast<void*>(threadData))) {
166 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
f9bf01c6 167 delete threadData;
ba379fdc
A
168 return 0;
169 }
170 return establishIdentifierForPthreadHandle(threadHandle);
171}
172#else
9dae56ea
A
173ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
174{
175 pthread_t threadHandle;
ba379fdc 176 if (pthread_create(&threadHandle, 0, entryPoint, data)) {
9dae56ea
A
177 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
178 return 0;
179 }
180
181 return establishIdentifierForPthreadHandle(threadHandle);
182}
ba379fdc
A
183#endif
184
f9bf01c6 185void initializeCurrentThreadInternal(const char* threadName)
ba379fdc
A
186{
187#if HAVE(PTHREAD_SETNAME_NP)
188 pthread_setname_np(threadName);
189#else
190 UNUSED_PARAM(threadName);
191#endif
f9bf01c6
A
192
193 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
194 ASSERT(id);
195 ThreadIdentifierData::initialize(id);
ba379fdc 196}
9dae56ea
A
197
198int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
199{
200 ASSERT(threadID);
ba379fdc 201
9dae56ea 202 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
f9bf01c6
A
203 if (!pthreadHandle)
204 return 0;
ba379fdc 205
9dae56ea
A
206 int joinResult = pthread_join(pthreadHandle, result);
207 if (joinResult == EDEADLK)
208 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
ba379fdc 209
9dae56ea
A
210 return joinResult;
211}
212
213void detachThread(ThreadIdentifier threadID)
214{
215 ASSERT(threadID);
ba379fdc 216
9dae56ea 217 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
f9bf01c6
A
218 if (!pthreadHandle)
219 return;
ba379fdc 220
9dae56ea 221 pthread_detach(pthreadHandle);
9dae56ea
A
222}
223
224ThreadIdentifier currentThread()
225{
f9bf01c6
A
226 ThreadIdentifier id = ThreadIdentifierData::identifier();
227 if (id)
9dae56ea 228 return id;
f9bf01c6
A
229
230 // Not a WTF-created thread, ThreadIdentifier is not established yet.
231 id = establishIdentifierForPthreadHandle(pthread_self());
232 ThreadIdentifierData::initialize(id);
233 return id;
9dae56ea
A
234}
235
9dae56ea
A
236Mutex::Mutex()
237{
238 pthread_mutex_init(&m_mutex, NULL);
239}
240
241Mutex::~Mutex()
242{
243 pthread_mutex_destroy(&m_mutex);
244}
245
246void Mutex::lock()
247{
ba379fdc
A
248 int result = pthread_mutex_lock(&m_mutex);
249 ASSERT_UNUSED(result, !result);
9dae56ea 250}
ba379fdc 251
9dae56ea
A
252bool Mutex::tryLock()
253{
254 int result = pthread_mutex_trylock(&m_mutex);
ba379fdc 255
9dae56ea
A
256 if (result == 0)
257 return true;
ba379fdc 258 if (result == EBUSY)
9dae56ea
A
259 return false;
260
ba379fdc 261 ASSERT_NOT_REACHED();
9dae56ea
A
262 return false;
263}
264
265void Mutex::unlock()
266{
ba379fdc
A
267 int result = pthread_mutex_unlock(&m_mutex);
268 ASSERT_UNUSED(result, !result);
269}
270
f9bf01c6 271#if HAVE(PTHREAD_RWLOCK)
ba379fdc
A
272ReadWriteLock::ReadWriteLock()
273{
274 pthread_rwlock_init(&m_readWriteLock, NULL);
275}
276
277ReadWriteLock::~ReadWriteLock()
278{
279 pthread_rwlock_destroy(&m_readWriteLock);
280}
281
282void ReadWriteLock::readLock()
283{
284 int result = pthread_rwlock_rdlock(&m_readWriteLock);
285 ASSERT_UNUSED(result, !result);
286}
287
288bool ReadWriteLock::tryReadLock()
289{
290 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
291
292 if (result == 0)
293 return true;
294 if (result == EBUSY || result == EAGAIN)
295 return false;
296
297 ASSERT_NOT_REACHED();
298 return false;
299}
300
301void ReadWriteLock::writeLock()
302{
303 int result = pthread_rwlock_wrlock(&m_readWriteLock);
304 ASSERT_UNUSED(result, !result);
305}
306
307bool ReadWriteLock::tryWriteLock()
308{
309 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
310
311 if (result == 0)
312 return true;
313 if (result == EBUSY || result == EAGAIN)
314 return false;
315
316 ASSERT_NOT_REACHED();
317 return false;
318}
319
320void ReadWriteLock::unlock()
321{
322 int result = pthread_rwlock_unlock(&m_readWriteLock);
323 ASSERT_UNUSED(result, !result);
9dae56ea 324}
f9bf01c6 325#endif // HAVE(PTHREAD_RWLOCK)
9dae56ea
A
326
327ThreadCondition::ThreadCondition()
328{
329 pthread_cond_init(&m_condition, NULL);
330}
331
332ThreadCondition::~ThreadCondition()
333{
334 pthread_cond_destroy(&m_condition);
335}
336
337void ThreadCondition::wait(Mutex& mutex)
338{
ba379fdc
A
339 int result = pthread_cond_wait(&m_condition, &mutex.impl());
340 ASSERT_UNUSED(result, !result);
9dae56ea
A
341}
342
343bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
344{
345 if (absoluteTime < currentTime())
346 return false;
347
348 if (absoluteTime > INT_MAX) {
349 wait(mutex);
350 return true;
351 }
352
353 int timeSeconds = static_cast<int>(absoluteTime);
354 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
355
356 timespec targetTime;
357 targetTime.tv_sec = timeSeconds;
358 targetTime.tv_nsec = timeNanoseconds;
359
360 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
361}
362
363void ThreadCondition::signal()
364{
ba379fdc
A
365 int result = pthread_cond_signal(&m_condition);
366 ASSERT_UNUSED(result, !result);
9dae56ea
A
367}
368
369void ThreadCondition::broadcast()
370{
ba379fdc
A
371 int result = pthread_cond_broadcast(&m_condition);
372 ASSERT_UNUSED(result, !result);
9dae56ea 373}
ba379fdc 374
9dae56ea
A
375} // namespace WTF
376
377#endif // USE(PTHREADS)