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 #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.
64 void clearPthreadHandleForIdentifier(ThreadIdentifier
);
66 static Mutex
& threadMapMutex()
68 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
72 void initializeThreading()
74 if (!atomicallyInitializedStaticMutex
) {
75 atomicallyInitializedStaticMutex
= new Mutex
;
77 initializeRandomNumberGenerator();
78 #if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD)
79 mainThread
= pthread_self();
81 initializeMainThread();
85 void lockAtomicallyInitializedStaticMutex()
87 ASSERT(atomicallyInitializedStaticMutex
);
88 atomicallyInitializedStaticMutex
->lock();
91 void unlockAtomicallyInitializedStaticMutex()
93 atomicallyInitializedStaticMutex
->unlock();
96 static ThreadMap
& threadMap()
98 DEFINE_STATIC_LOCAL(ThreadMap
, map
, ());
102 static ThreadIdentifier
identifierByPthreadHandle(const pthread_t
& pthreadHandle
)
104 MutexLocker
locker(threadMapMutex());
106 ThreadMap::iterator i
= threadMap().begin();
107 for (; i
!= threadMap().end(); ++i
) {
108 if (pthread_equal(i
->second
, pthreadHandle
))
115 static ThreadIdentifier
establishIdentifierForPthreadHandle(const pthread_t
& pthreadHandle
)
117 ASSERT(!identifierByPthreadHandle(pthreadHandle
));
119 MutexLocker
locker(threadMapMutex());
121 static ThreadIdentifier identifierCount
= 1;
123 threadMap().add(identifierCount
, pthreadHandle
);
125 return identifierCount
++;
128 static pthread_t
pthreadHandleForIdentifier(ThreadIdentifier id
)
130 MutexLocker
locker(threadMapMutex());
132 return threadMap().get(id
);
135 void clearPthreadHandleForIdentifier(ThreadIdentifier id
)
137 MutexLocker
locker(threadMapMutex());
139 ASSERT(threadMap().contains(id
));
141 threadMap().remove(id
);
145 // On the Android platform, threads must be registered with the VM before they run.
147 ThreadFunction entryPoint
;
151 static void* runThreadWithRegistration(void* arg
)
153 ThreadData
* data
= static_cast<ThreadData
*>(arg
);
154 JavaVM
* vm
= JSC::Bindings::getJavaVM();
157 if (vm
->AttachCurrentThread(&env
, 0) == JNI_OK
) {
158 ret
= data
->entryPoint(data
->arg
);
159 vm
->DetachCurrentThread();
165 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
167 pthread_t threadHandle
;
168 ThreadData
* threadData
= new ThreadData();
169 threadData
->entryPoint
= entryPoint
;
170 threadData
->arg
= data
;
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
);
177 return establishIdentifierForPthreadHandle(threadHandle
);
180 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
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
);
188 return establishIdentifierForPthreadHandle(threadHandle
);
192 void initializeCurrentThreadInternal(const char* threadName
)
194 #if HAVE(PTHREAD_SETNAME_NP)
195 pthread_setname_np(threadName
);
197 UNUSED_PARAM(threadName
);
200 ThreadIdentifier id
= identifierByPthreadHandle(pthread_self());
202 ThreadIdentifierData::initialize(id
);
205 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
209 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
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
);
220 void detachThread(ThreadIdentifier threadID
)
224 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
228 pthread_detach(pthreadHandle
);
231 ThreadIdentifier
currentThread()
233 ThreadIdentifier id
= ThreadIdentifierData::identifier();
237 // Not a WTF-created thread, ThreadIdentifier is not established yet.
238 id
= establishIdentifierForPthreadHandle(pthread_self());
239 ThreadIdentifierData::initialize(id
);
245 #if OS(DARWIN) && !PLATFORM(CHROMIUM) && !USE(WEB_THREAD)
246 return pthread_main_np();
248 return pthread_equal(pthread_self(), mainThread
);
254 pthread_mutex_init(&m_mutex
, NULL
);
259 pthread_mutex_destroy(&m_mutex
);
264 int result
= pthread_mutex_lock(&m_mutex
);
265 ASSERT_UNUSED(result
, !result
);
268 bool Mutex::tryLock()
270 int result
= pthread_mutex_trylock(&m_mutex
);
277 ASSERT_NOT_REACHED();
283 int result
= pthread_mutex_unlock(&m_mutex
);
284 ASSERT_UNUSED(result
, !result
);
287 #if HAVE(PTHREAD_RWLOCK)
288 ReadWriteLock::ReadWriteLock()
290 pthread_rwlock_init(&m_readWriteLock
, NULL
);
293 ReadWriteLock::~ReadWriteLock()
295 pthread_rwlock_destroy(&m_readWriteLock
);
298 void ReadWriteLock::readLock()
300 int result
= pthread_rwlock_rdlock(&m_readWriteLock
);
301 ASSERT_UNUSED(result
, !result
);
304 bool ReadWriteLock::tryReadLock()
306 int result
= pthread_rwlock_tryrdlock(&m_readWriteLock
);
310 if (result
== EBUSY
|| result
== EAGAIN
)
313 ASSERT_NOT_REACHED();
317 void ReadWriteLock::writeLock()
319 int result
= pthread_rwlock_wrlock(&m_readWriteLock
);
320 ASSERT_UNUSED(result
, !result
);
323 bool ReadWriteLock::tryWriteLock()
325 int result
= pthread_rwlock_trywrlock(&m_readWriteLock
);
329 if (result
== EBUSY
|| result
== EAGAIN
)
332 ASSERT_NOT_REACHED();
336 void ReadWriteLock::unlock()
338 int result
= pthread_rwlock_unlock(&m_readWriteLock
);
339 ASSERT_UNUSED(result
, !result
);
341 #endif // HAVE(PTHREAD_RWLOCK)
343 ThreadCondition::ThreadCondition()
345 pthread_cond_init(&m_condition
, NULL
);
348 ThreadCondition::~ThreadCondition()
350 pthread_cond_destroy(&m_condition
);
353 void ThreadCondition::wait(Mutex
& mutex
)
355 int result
= pthread_cond_wait(&m_condition
, &mutex
.impl());
356 ASSERT_UNUSED(result
, !result
);
359 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
361 if (absoluteTime
< currentTime())
364 if (absoluteTime
> INT_MAX
) {
369 int timeSeconds
= static_cast<int>(absoluteTime
);
370 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
373 targetTime
.tv_sec
= timeSeconds
;
374 targetTime
.tv_nsec
= timeNanoseconds
;
376 return pthread_cond_timedwait(&m_condition
, &mutex
.impl(), &targetTime
) == 0;
379 void ThreadCondition::signal()
381 int result
= pthread_cond_signal(&m_condition
);
382 ASSERT_UNUSED(result
, !result
);
385 void ThreadCondition::broadcast()
387 int result
= pthread_cond_broadcast(&m_condition
);
388 ASSERT_UNUSED(result
, !result
);
393 #endif // USE(PTHREADS)