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