• 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 <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