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