]> git.saurik.com Git - apple/javascriptcore.git/blob - wtf/ThreadingPthreads.cpp
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / wtf / ThreadingPthreads.cpp
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
54 namespace WTF {
55
56 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
57
58 static Mutex* atomicallyInitializedStaticMutex;
59
60 void clearPthreadHandleForIdentifier(ThreadIdentifier);
61
62 static Mutex& threadMapMutex()
63 {
64 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
65 return mutex;
66 }
67
68 void initializeThreading()
69 {
70 if (atomicallyInitializedStaticMutex)
71 return;
72
73 atomicallyInitializedStaticMutex = new Mutex;
74 threadMapMutex();
75 initializeRandomNumberGenerator();
76 }
77
78 void lockAtomicallyInitializedStaticMutex()
79 {
80 ASSERT(atomicallyInitializedStaticMutex);
81 atomicallyInitializedStaticMutex->lock();
82 }
83
84 void unlockAtomicallyInitializedStaticMutex()
85 {
86 atomicallyInitializedStaticMutex->unlock();
87 }
88
89 static ThreadMap& threadMap()
90 {
91 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
92 return map;
93 }
94
95 static 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
108 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
109 {
110 ASSERT(!identifierByPthreadHandle(pthreadHandle));
111
112 MutexLocker locker(threadMapMutex());
113
114 static ThreadIdentifier identifierCount = 1;
115
116 threadMap().add(identifierCount, pthreadHandle);
117
118 return identifierCount++;
119 }
120
121 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
122 {
123 MutexLocker locker(threadMapMutex());
124
125 return threadMap().get(id);
126 }
127
128 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
129 {
130 MutexLocker locker(threadMapMutex());
131
132 ASSERT(threadMap().contains(id));
133
134 threadMap().remove(id);
135 }
136
137 #if OS(ANDROID)
138 // On the Android platform, threads must be registered with the VM before they run.
139 struct ThreadData {
140 ThreadFunction entryPoint;
141 void* arg;
142 };
143
144 static 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
158 ThreadIdentifier 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);
167 delete threadData;
168 return 0;
169 }
170 return establishIdentifierForPthreadHandle(threadHandle);
171 }
172 #else
173 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
174 {
175 pthread_t threadHandle;
176 if (pthread_create(&threadHandle, 0, entryPoint, data)) {
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 }
183 #endif
184
185 void initializeCurrentThreadInternal(const char* threadName)
186 {
187 #if HAVE(PTHREAD_SETNAME_NP)
188 pthread_setname_np(threadName);
189 #else
190 UNUSED_PARAM(threadName);
191 #endif
192
193 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
194 ASSERT(id);
195 ThreadIdentifierData::initialize(id);
196 }
197
198 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
199 {
200 ASSERT(threadID);
201
202 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
203 if (!pthreadHandle)
204 return 0;
205
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);
209
210 return joinResult;
211 }
212
213 void detachThread(ThreadIdentifier threadID)
214 {
215 ASSERT(threadID);
216
217 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
218 if (!pthreadHandle)
219 return;
220
221 pthread_detach(pthreadHandle);
222 }
223
224 ThreadIdentifier currentThread()
225 {
226 ThreadIdentifier id = ThreadIdentifierData::identifier();
227 if (id)
228 return id;
229
230 // Not a WTF-created thread, ThreadIdentifier is not established yet.
231 id = establishIdentifierForPthreadHandle(pthread_self());
232 ThreadIdentifierData::initialize(id);
233 return id;
234 }
235
236 Mutex::Mutex()
237 {
238 pthread_mutex_init(&m_mutex, NULL);
239 }
240
241 Mutex::~Mutex()
242 {
243 pthread_mutex_destroy(&m_mutex);
244 }
245
246 void Mutex::lock()
247 {
248 int result = pthread_mutex_lock(&m_mutex);
249 ASSERT_UNUSED(result, !result);
250 }
251
252 bool Mutex::tryLock()
253 {
254 int result = pthread_mutex_trylock(&m_mutex);
255
256 if (result == 0)
257 return true;
258 if (result == EBUSY)
259 return false;
260
261 ASSERT_NOT_REACHED();
262 return false;
263 }
264
265 void Mutex::unlock()
266 {
267 int result = pthread_mutex_unlock(&m_mutex);
268 ASSERT_UNUSED(result, !result);
269 }
270
271 #if HAVE(PTHREAD_RWLOCK)
272 ReadWriteLock::ReadWriteLock()
273 {
274 pthread_rwlock_init(&m_readWriteLock, NULL);
275 }
276
277 ReadWriteLock::~ReadWriteLock()
278 {
279 pthread_rwlock_destroy(&m_readWriteLock);
280 }
281
282 void ReadWriteLock::readLock()
283 {
284 int result = pthread_rwlock_rdlock(&m_readWriteLock);
285 ASSERT_UNUSED(result, !result);
286 }
287
288 bool 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
301 void ReadWriteLock::writeLock()
302 {
303 int result = pthread_rwlock_wrlock(&m_readWriteLock);
304 ASSERT_UNUSED(result, !result);
305 }
306
307 bool 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
320 void ReadWriteLock::unlock()
321 {
322 int result = pthread_rwlock_unlock(&m_readWriteLock);
323 ASSERT_UNUSED(result, !result);
324 }
325 #endif // HAVE(PTHREAD_RWLOCK)
326
327 ThreadCondition::ThreadCondition()
328 {
329 pthread_cond_init(&m_condition, NULL);
330 }
331
332 ThreadCondition::~ThreadCondition()
333 {
334 pthread_cond_destroy(&m_condition);
335 }
336
337 void ThreadCondition::wait(Mutex& mutex)
338 {
339 int result = pthread_cond_wait(&m_condition, &mutex.impl());
340 ASSERT_UNUSED(result, !result);
341 }
342
343 bool 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
363 void ThreadCondition::signal()
364 {
365 int result = pthread_cond_signal(&m_condition);
366 ASSERT_UNUSED(result, !result);
367 }
368
369 void ThreadCondition::broadcast()
370 {
371 int result = pthread_cond_broadcast(&m_condition);
372 ASSERT_UNUSED(result, !result);
373 }
374
375 } // namespace WTF
376
377 #endif // USE(PTHREADS)