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 "JNIUtility.h"
52 #endif
53
54 namespace WTF {
55
56 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
57
58 static Mutex* atomicallyInitializedStaticMutex;
59
60 #if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD)
61 static pthread_t mainThread; // The thread that was the first to call initializeThreading(), which must be the main thread.
62 #endif
63
64 void clearPthreadHandleForIdentifier(ThreadIdentifier);
65
threadMapMutex()66 static Mutex& threadMapMutex()
67 {
68 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
69 return mutex;
70 }
71
initializeThreading()72 void 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
lockAtomicallyInitializedStaticMutex()85 void lockAtomicallyInitializedStaticMutex()
86 {
87 ASSERT(atomicallyInitializedStaticMutex);
88 atomicallyInitializedStaticMutex->lock();
89 }
90
unlockAtomicallyInitializedStaticMutex()91 void unlockAtomicallyInitializedStaticMutex()
92 {
93 atomicallyInitializedStaticMutex->unlock();
94 }
95
threadMap()96 static ThreadMap& threadMap()
97 {
98 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
99 return map;
100 }
101
identifierByPthreadHandle(const pthread_t & pthreadHandle)102 static 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
establishIdentifierForPthreadHandle(const pthread_t & pthreadHandle)115 static 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
pthreadHandleForIdentifier(ThreadIdentifier id)128 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
129 {
130 MutexLocker locker(threadMapMutex());
131
132 return threadMap().get(id);
133 }
134
clearPthreadHandleForIdentifier(ThreadIdentifier id)135 void 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.
146 struct ThreadData {
147 ThreadFunction entryPoint;
148 void* arg;
149 };
150
runThreadWithRegistration(void * arg)151 static 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
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)165 ThreadIdentifier 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
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)180 ThreadIdentifier 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
initializeCurrentThreadInternal(const char * threadName)192 void 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
waitForThreadCompletion(ThreadIdentifier threadID,void ** result)205 int 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
detachThread(ThreadIdentifier threadID)220 void 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
currentThread()231 ThreadIdentifier 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
isMainThread()243 bool 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
Mutex()252 Mutex::Mutex()
253 {
254 pthread_mutex_init(&m_mutex, NULL);
255 }
256
~Mutex()257 Mutex::~Mutex()
258 {
259 pthread_mutex_destroy(&m_mutex);
260 }
261
lock()262 void Mutex::lock()
263 {
264 int result = pthread_mutex_lock(&m_mutex);
265 ASSERT_UNUSED(result, !result);
266 }
267
tryLock()268 bool 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
unlock()281 void Mutex::unlock()
282 {
283 int result = pthread_mutex_unlock(&m_mutex);
284 ASSERT_UNUSED(result, !result);
285 }
286
287 #if HAVE(PTHREAD_RWLOCK)
ReadWriteLock()288 ReadWriteLock::ReadWriteLock()
289 {
290 pthread_rwlock_init(&m_readWriteLock, NULL);
291 }
292
~ReadWriteLock()293 ReadWriteLock::~ReadWriteLock()
294 {
295 pthread_rwlock_destroy(&m_readWriteLock);
296 }
297
readLock()298 void ReadWriteLock::readLock()
299 {
300 int result = pthread_rwlock_rdlock(&m_readWriteLock);
301 ASSERT_UNUSED(result, !result);
302 }
303
tryReadLock()304 bool 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
writeLock()317 void ReadWriteLock::writeLock()
318 {
319 int result = pthread_rwlock_wrlock(&m_readWriteLock);
320 ASSERT_UNUSED(result, !result);
321 }
322
tryWriteLock()323 bool 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
unlock()336 void ReadWriteLock::unlock()
337 {
338 int result = pthread_rwlock_unlock(&m_readWriteLock);
339 ASSERT_UNUSED(result, !result);
340 }
341 #endif // HAVE(PTHREAD_RWLOCK)
342
ThreadCondition()343 ThreadCondition::ThreadCondition()
344 {
345 pthread_cond_init(&m_condition, NULL);
346 }
347
~ThreadCondition()348 ThreadCondition::~ThreadCondition()
349 {
350 pthread_cond_destroy(&m_condition);
351 }
352
wait(Mutex & mutex)353 void ThreadCondition::wait(Mutex& mutex)
354 {
355 int result = pthread_cond_wait(&m_condition, &mutex.impl());
356 ASSERT_UNUSED(result, !result);
357 }
358
timedWait(Mutex & mutex,double absoluteTime)359 bool 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
signal()379 void ThreadCondition::signal()
380 {
381 int result = pthread_cond_signal(&m_condition);
382 ASSERT_UNUSED(result, !result);
383 }
384
broadcast()385 void 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)
394