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