2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "Threading.h"
35 #include "CurrentTime.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"
52 #include "JNIUtility.h"
53 #include "ThreadFunctionInvocation.h"
54 #include <wtf/OwnPtr.h>
55 #include <wtf/PassOwnPtr.h>
58 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
59 #include <objc/objc-auto.h>
64 typedef HashMap
<ThreadIdentifier
, pthread_t
> ThreadMap
;
66 static Mutex
* atomicallyInitializedStaticMutex
;
68 void clearPthreadHandleForIdentifier(ThreadIdentifier
);
70 static Mutex
& threadMapMutex()
72 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
76 void initializeThreading()
78 if (atomicallyInitializedStaticMutex
)
81 atomicallyInitializedStaticMutex
= new Mutex
;
83 initializeRandomNumberGenerator();
86 void lockAtomicallyInitializedStaticMutex()
88 ASSERT(atomicallyInitializedStaticMutex
);
89 atomicallyInitializedStaticMutex
->lock();
92 void unlockAtomicallyInitializedStaticMutex()
94 atomicallyInitializedStaticMutex
->unlock();
97 static ThreadMap
& threadMap()
99 DEFINE_STATIC_LOCAL(ThreadMap
, map
, ());
103 static ThreadIdentifier
identifierByPthreadHandle(const pthread_t
& pthreadHandle
)
105 MutexLocker
locker(threadMapMutex());
107 ThreadMap::iterator i
= threadMap().begin();
108 for (; i
!= threadMap().end(); ++i
) {
109 if (pthread_equal(i
->second
, pthreadHandle
))
116 static ThreadIdentifier
establishIdentifierForPthreadHandle(const pthread_t
& pthreadHandle
)
118 ASSERT(!identifierByPthreadHandle(pthreadHandle
));
120 MutexLocker
locker(threadMapMutex());
122 static ThreadIdentifier identifierCount
= 1;
124 threadMap().add(identifierCount
, pthreadHandle
);
126 return identifierCount
++;
129 static pthread_t
pthreadHandleForIdentifier(ThreadIdentifier id
)
131 MutexLocker
locker(threadMapMutex());
133 return threadMap().get(id
);
136 void clearPthreadHandleForIdentifier(ThreadIdentifier id
)
138 MutexLocker
locker(threadMapMutex());
140 ASSERT(threadMap().contains(id
));
142 threadMap().remove(id
);
146 static void* runThreadWithRegistration(void* arg
)
148 OwnPtr
<ThreadFunctionInvocation
> invocation
= adoptPtr(static_cast<ThreadFunctionInvocation
*>(arg
));
149 JavaVM
* vm
= JSC::Bindings::getJavaVM();
152 if (vm
->AttachCurrentThread(&env
, 0) == JNI_OK
) {
153 ret
= invocation
->function(invocation
->data
);
154 vm
->DetachCurrentThread();
159 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
161 pthread_t threadHandle
;
163 // On the Android platform, threads must be registered with the VM before they run.
164 OwnPtr
<ThreadFunctionInvocation
> invocation
= adoptPtr(new ThreadFunctionInvocation(entryPoint
, data
));
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
);
171 // The thread will take ownership of invocation.
172 invocation
.leakPtr();
174 return establishIdentifierForPthreadHandle(threadHandle
);
177 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
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
);
185 return establishIdentifierForPthreadHandle(threadHandle
);
189 void initializeCurrentThreadInternal(const char* threadName
)
191 #if HAVE(PTHREAD_SETNAME_NP)
192 pthread_setname_np(threadName
);
194 UNUSED_PARAM(threadName
);
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();
203 ThreadIdentifier id
= identifierByPthreadHandle(pthread_self());
205 ThreadIdentifierData::initialize(id
);
208 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
212 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
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
);
223 void detachThread(ThreadIdentifier threadID
)
227 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
231 pthread_detach(pthreadHandle
);
239 ThreadIdentifier
currentThread()
241 ThreadIdentifier id
= ThreadIdentifierData::identifier();
245 // Not a WTF-created thread, ThreadIdentifier is not established yet.
246 id
= establishIdentifierForPthreadHandle(pthread_self());
247 ThreadIdentifierData::initialize(id
);
253 pthread_mutexattr_t attr
;
254 pthread_mutexattr_init(&attr
);
255 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_NORMAL
);
257 pthread_mutex_init(&m_mutex
, &attr
);
259 pthread_mutexattr_destroy(&attr
);
264 pthread_mutex_destroy(&m_mutex
);
269 int result
= pthread_mutex_lock(&m_mutex
);
270 ASSERT_UNUSED(result
, !result
);
273 bool Mutex::tryLock()
275 int result
= pthread_mutex_trylock(&m_mutex
);
282 ASSERT_NOT_REACHED();
288 int result
= pthread_mutex_unlock(&m_mutex
);
289 ASSERT_UNUSED(result
, !result
);
292 #if HAVE(PTHREAD_RWLOCK)
293 ReadWriteLock::ReadWriteLock()
295 pthread_rwlock_init(&m_readWriteLock
, NULL
);
298 ReadWriteLock::~ReadWriteLock()
300 pthread_rwlock_destroy(&m_readWriteLock
);
303 void ReadWriteLock::readLock()
305 int result
= pthread_rwlock_rdlock(&m_readWriteLock
);
306 ASSERT_UNUSED(result
, !result
);
309 bool ReadWriteLock::tryReadLock()
311 int result
= pthread_rwlock_tryrdlock(&m_readWriteLock
);
315 if (result
== EBUSY
|| result
== EAGAIN
)
318 ASSERT_NOT_REACHED();
322 void ReadWriteLock::writeLock()
324 int result
= pthread_rwlock_wrlock(&m_readWriteLock
);
325 ASSERT_UNUSED(result
, !result
);
328 bool ReadWriteLock::tryWriteLock()
330 int result
= pthread_rwlock_trywrlock(&m_readWriteLock
);
334 if (result
== EBUSY
|| result
== EAGAIN
)
337 ASSERT_NOT_REACHED();
341 void ReadWriteLock::unlock()
343 int result
= pthread_rwlock_unlock(&m_readWriteLock
);
344 ASSERT_UNUSED(result
, !result
);
346 #endif // HAVE(PTHREAD_RWLOCK)
348 ThreadCondition::ThreadCondition()
350 pthread_cond_init(&m_condition
, NULL
);
353 ThreadCondition::~ThreadCondition()
355 pthread_cond_destroy(&m_condition
);
358 void ThreadCondition::wait(Mutex
& mutex
)
360 int result
= pthread_cond_wait(&m_condition
, &mutex
.impl());
361 ASSERT_UNUSED(result
, !result
);
364 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
366 if (absoluteTime
< currentTime())
369 if (absoluteTime
> INT_MAX
) {
374 int timeSeconds
= static_cast<int>(absoluteTime
);
375 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
378 targetTime
.tv_sec
= timeSeconds
;
379 targetTime
.tv_nsec
= timeNanoseconds
;
381 return pthread_cond_timedwait(&m_condition
, &mutex
.impl(), &targetTime
) == 0;
384 void ThreadCondition::signal()
386 int result
= pthread_cond_signal(&m_condition
);
387 ASSERT_UNUSED(result
, !result
);
390 void ThreadCondition::broadcast()
392 int result
= pthread_cond_broadcast(&m_condition
);
393 ASSERT_UNUSED(result
, !result
);
398 #endif // USE(PTHREADS)