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"
51 #include "jni_utility.h"
56 typedef HashMap
<ThreadIdentifier
, pthread_t
> ThreadMap
;
58 static Mutex
* atomicallyInitializedStaticMutex
;
60 void clearPthreadHandleForIdentifier(ThreadIdentifier
);
62 static Mutex
& threadMapMutex()
64 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
68 void initializeThreading()
70 if (atomicallyInitializedStaticMutex
)
73 atomicallyInitializedStaticMutex
= new Mutex
;
75 initializeRandomNumberGenerator();
78 void lockAtomicallyInitializedStaticMutex()
80 ASSERT(atomicallyInitializedStaticMutex
);
81 atomicallyInitializedStaticMutex
->lock();
84 void unlockAtomicallyInitializedStaticMutex()
86 atomicallyInitializedStaticMutex
->unlock();
89 static ThreadMap
& threadMap()
91 DEFINE_STATIC_LOCAL(ThreadMap
, map
, ());
95 static ThreadIdentifier
identifierByPthreadHandle(const pthread_t
& pthreadHandle
)
97 MutexLocker
locker(threadMapMutex());
99 ThreadMap::iterator i
= threadMap().begin();
100 for (; i
!= threadMap().end(); ++i
) {
101 if (pthread_equal(i
->second
, pthreadHandle
))
108 static ThreadIdentifier
establishIdentifierForPthreadHandle(const pthread_t
& pthreadHandle
)
110 ASSERT(!identifierByPthreadHandle(pthreadHandle
));
112 MutexLocker
locker(threadMapMutex());
114 static ThreadIdentifier identifierCount
= 1;
116 threadMap().add(identifierCount
, pthreadHandle
);
118 return identifierCount
++;
121 static pthread_t
pthreadHandleForIdentifier(ThreadIdentifier id
)
123 MutexLocker
locker(threadMapMutex());
125 return threadMap().get(id
);
128 void clearPthreadHandleForIdentifier(ThreadIdentifier id
)
130 MutexLocker
locker(threadMapMutex());
132 ASSERT(threadMap().contains(id
));
134 threadMap().remove(id
);
138 // On the Android platform, threads must be registered with the VM before they run.
140 ThreadFunction entryPoint
;
144 static void* runThreadWithRegistration(void* arg
)
146 ThreadData
* data
= static_cast<ThreadData
*>(arg
);
147 JavaVM
* vm
= JSC::Bindings::getJavaVM();
150 if (vm
->AttachCurrentThread(&env
, 0) == JNI_OK
) {
151 ret
= data
->entryPoint(data
->arg
);
152 vm
->DetachCurrentThread();
158 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
160 pthread_t threadHandle
;
161 ThreadData
* threadData
= new ThreadData();
162 threadData
->entryPoint
= entryPoint
;
163 threadData
->arg
= data
;
165 if (pthread_create(&threadHandle
, 0, runThreadWithRegistration
, static_cast<void*>(threadData
))) {
166 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint
, data
);
170 return establishIdentifierForPthreadHandle(threadHandle
);
173 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
175 pthread_t threadHandle
;
176 if (pthread_create(&threadHandle
, 0, entryPoint
, data
)) {
177 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint
, data
);
181 return establishIdentifierForPthreadHandle(threadHandle
);
185 void initializeCurrentThreadInternal(const char* threadName
)
187 #if HAVE(PTHREAD_SETNAME_NP)
188 pthread_setname_np(threadName
);
190 UNUSED_PARAM(threadName
);
193 ThreadIdentifier id
= identifierByPthreadHandle(pthread_self());
195 ThreadIdentifierData::initialize(id
);
198 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
202 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
206 int joinResult
= pthread_join(pthreadHandle
, result
);
207 if (joinResult
== EDEADLK
)
208 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID
);
213 void detachThread(ThreadIdentifier threadID
)
217 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
221 pthread_detach(pthreadHandle
);
224 ThreadIdentifier
currentThread()
226 ThreadIdentifier id
= ThreadIdentifierData::identifier();
230 // Not a WTF-created thread, ThreadIdentifier is not established yet.
231 id
= establishIdentifierForPthreadHandle(pthread_self());
232 ThreadIdentifierData::initialize(id
);
238 pthread_mutex_init(&m_mutex
, NULL
);
243 pthread_mutex_destroy(&m_mutex
);
248 int result
= pthread_mutex_lock(&m_mutex
);
249 ASSERT_UNUSED(result
, !result
);
252 bool Mutex::tryLock()
254 int result
= pthread_mutex_trylock(&m_mutex
);
261 ASSERT_NOT_REACHED();
267 int result
= pthread_mutex_unlock(&m_mutex
);
268 ASSERT_UNUSED(result
, !result
);
271 #if HAVE(PTHREAD_RWLOCK)
272 ReadWriteLock::ReadWriteLock()
274 pthread_rwlock_init(&m_readWriteLock
, NULL
);
277 ReadWriteLock::~ReadWriteLock()
279 pthread_rwlock_destroy(&m_readWriteLock
);
282 void ReadWriteLock::readLock()
284 int result
= pthread_rwlock_rdlock(&m_readWriteLock
);
285 ASSERT_UNUSED(result
, !result
);
288 bool ReadWriteLock::tryReadLock()
290 int result
= pthread_rwlock_tryrdlock(&m_readWriteLock
);
294 if (result
== EBUSY
|| result
== EAGAIN
)
297 ASSERT_NOT_REACHED();
301 void ReadWriteLock::writeLock()
303 int result
= pthread_rwlock_wrlock(&m_readWriteLock
);
304 ASSERT_UNUSED(result
, !result
);
307 bool ReadWriteLock::tryWriteLock()
309 int result
= pthread_rwlock_trywrlock(&m_readWriteLock
);
313 if (result
== EBUSY
|| result
== EAGAIN
)
316 ASSERT_NOT_REACHED();
320 void ReadWriteLock::unlock()
322 int result
= pthread_rwlock_unlock(&m_readWriteLock
);
323 ASSERT_UNUSED(result
, !result
);
325 #endif // HAVE(PTHREAD_RWLOCK)
327 ThreadCondition::ThreadCondition()
329 pthread_cond_init(&m_condition
, NULL
);
332 ThreadCondition::~ThreadCondition()
334 pthread_cond_destroy(&m_condition
);
337 void ThreadCondition::wait(Mutex
& mutex
)
339 int result
= pthread_cond_wait(&m_condition
, &mutex
.impl());
340 ASSERT_UNUSED(result
, !result
);
343 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
345 if (absoluteTime
< currentTime())
348 if (absoluteTime
> INT_MAX
) {
353 int timeSeconds
= static_cast<int>(absoluteTime
);
354 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
357 targetTime
.tv_sec
= timeSeconds
;
358 targetTime
.tv_nsec
= timeNanoseconds
;
360 return pthread_cond_timedwait(&m_condition
, &mutex
.impl(), &targetTime
) == 0;
363 void ThreadCondition::signal()
365 int result
= pthread_cond_signal(&m_condition
);
366 ASSERT_UNUSED(result
, !result
);
369 void ThreadCondition::broadcast()
371 int result
= pthread_cond_broadcast(&m_condition
);
372 ASSERT_UNUSED(result
, !result
);
377 #endif // USE(PTHREADS)