• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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