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 "UnusedParam.h"
46 #include "jni_utility.h"
51 typedef HashMap
<ThreadIdentifier
, pthread_t
> ThreadMap
;
53 static Mutex
* atomicallyInitializedStaticMutex
;
55 static ThreadIdentifier mainThreadIdentifier
; // The thread that was the first to call initializeThreading(), which must be the main thread.
57 static Mutex
& threadMapMutex()
59 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
63 void initializeThreading()
65 if (!atomicallyInitializedStaticMutex
) {
66 atomicallyInitializedStaticMutex
= new Mutex
;
68 initializeRandomNumberGenerator();
69 mainThreadIdentifier
= currentThread();
70 initializeMainThread();
74 void lockAtomicallyInitializedStaticMutex()
76 ASSERT(atomicallyInitializedStaticMutex
);
77 atomicallyInitializedStaticMutex
->lock();
80 void unlockAtomicallyInitializedStaticMutex()
82 atomicallyInitializedStaticMutex
->unlock();
85 static ThreadMap
& threadMap()
87 DEFINE_STATIC_LOCAL(ThreadMap
, map
, ());
91 static ThreadIdentifier
identifierByPthreadHandle(const pthread_t
& pthreadHandle
)
93 MutexLocker
locker(threadMapMutex());
95 ThreadMap::iterator i
= threadMap().begin();
96 for (; i
!= threadMap().end(); ++i
) {
97 if (pthread_equal(i
->second
, pthreadHandle
))
104 static ThreadIdentifier
establishIdentifierForPthreadHandle(pthread_t
& pthreadHandle
)
106 ASSERT(!identifierByPthreadHandle(pthreadHandle
));
108 MutexLocker
locker(threadMapMutex());
110 static ThreadIdentifier identifierCount
= 1;
112 threadMap().add(identifierCount
, pthreadHandle
);
114 return identifierCount
++;
117 static pthread_t
pthreadHandleForIdentifier(ThreadIdentifier id
)
119 MutexLocker
locker(threadMapMutex());
121 return threadMap().get(id
);
124 static void clearPthreadHandleForIdentifier(ThreadIdentifier id
)
126 MutexLocker
locker(threadMapMutex());
128 ASSERT(threadMap().contains(id
));
130 threadMap().remove(id
);
133 #if PLATFORM(ANDROID)
134 // On the Android platform, threads must be registered with the VM before they run.
136 ThreadFunction entryPoint
;
140 static void* runThreadWithRegistration(void* arg
)
142 ThreadData
* data
= static_cast<ThreadData
*>(arg
);
143 JavaVM
* vm
= JSC::Bindings::getJavaVM();
146 if (vm
->AttachCurrentThread(&env
, 0) == JNI_OK
) {
147 ret
= data
->entryPoint(data
->arg
);
148 vm
->DetachCurrentThread();
154 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
156 pthread_t threadHandle
;
157 ThreadData
* threadData
= new ThreadData();
158 threadData
->entryPoint
= entryPoint
;
159 threadData
->arg
= data
;
161 if (pthread_create(&threadHandle
, 0, runThreadWithRegistration
, static_cast<void*>(threadData
))) {
162 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint
, data
);
165 return establishIdentifierForPthreadHandle(threadHandle
);
168 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
170 pthread_t threadHandle
;
171 if (pthread_create(&threadHandle
, 0, entryPoint
, data
)) {
172 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint
, data
);
176 return establishIdentifierForPthreadHandle(threadHandle
);
180 void setThreadNameInternal(const char* threadName
)
182 #if HAVE(PTHREAD_SETNAME_NP)
183 pthread_setname_np(threadName
);
185 UNUSED_PARAM(threadName
);
189 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
193 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
195 int joinResult
= pthread_join(pthreadHandle
, result
);
196 if (joinResult
== EDEADLK
)
197 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID
);
199 clearPthreadHandleForIdentifier(threadID
);
203 void detachThread(ThreadIdentifier threadID
)
207 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
209 pthread_detach(pthreadHandle
);
211 clearPthreadHandleForIdentifier(threadID
);
214 ThreadIdentifier
currentThread()
216 pthread_t currentThread
= pthread_self();
217 if (ThreadIdentifier id
= identifierByPthreadHandle(currentThread
))
219 return establishIdentifierForPthreadHandle(currentThread
);
224 return currentThread() == mainThreadIdentifier
;
229 pthread_mutex_init(&m_mutex
, NULL
);
234 pthread_mutex_destroy(&m_mutex
);
239 int result
= pthread_mutex_lock(&m_mutex
);
240 ASSERT_UNUSED(result
, !result
);
243 bool Mutex::tryLock()
245 int result
= pthread_mutex_trylock(&m_mutex
);
252 ASSERT_NOT_REACHED();
258 int result
= pthread_mutex_unlock(&m_mutex
);
259 ASSERT_UNUSED(result
, !result
);
263 ReadWriteLock::ReadWriteLock()
265 pthread_rwlock_init(&m_readWriteLock
, NULL
);
268 ReadWriteLock::~ReadWriteLock()
270 pthread_rwlock_destroy(&m_readWriteLock
);
273 void ReadWriteLock::readLock()
275 int result
= pthread_rwlock_rdlock(&m_readWriteLock
);
276 ASSERT_UNUSED(result
, !result
);
279 bool ReadWriteLock::tryReadLock()
281 int result
= pthread_rwlock_tryrdlock(&m_readWriteLock
);
285 if (result
== EBUSY
|| result
== EAGAIN
)
288 ASSERT_NOT_REACHED();
292 void ReadWriteLock::writeLock()
294 int result
= pthread_rwlock_wrlock(&m_readWriteLock
);
295 ASSERT_UNUSED(result
, !result
);
298 bool ReadWriteLock::tryWriteLock()
300 int result
= pthread_rwlock_trywrlock(&m_readWriteLock
);
304 if (result
== EBUSY
|| result
== EAGAIN
)
307 ASSERT_NOT_REACHED();
311 void ReadWriteLock::unlock()
313 int result
= pthread_rwlock_unlock(&m_readWriteLock
);
314 ASSERT_UNUSED(result
, !result
);
317 ThreadCondition::ThreadCondition()
319 pthread_cond_init(&m_condition
, NULL
);
322 ThreadCondition::~ThreadCondition()
324 pthread_cond_destroy(&m_condition
);
327 void ThreadCondition::wait(Mutex
& mutex
)
329 int result
= pthread_cond_wait(&m_condition
, &mutex
.impl());
330 ASSERT_UNUSED(result
, !result
);
333 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
335 if (absoluteTime
< currentTime())
338 if (absoluteTime
> INT_MAX
) {
343 int timeSeconds
= static_cast<int>(absoluteTime
);
344 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
347 targetTime
.tv_sec
= timeSeconds
;
348 targetTime
.tv_nsec
= timeNanoseconds
;
350 return pthread_cond_timedwait(&m_condition
, &mutex
.impl(), &targetTime
) == 0;
353 void ThreadCondition::signal()
355 int result
= pthread_cond_signal(&m_condition
);
356 ASSERT_UNUSED(result
, !result
);
359 void ThreadCondition::broadcast()
361 int result
= pthread_cond_broadcast(&m_condition
);
362 ASSERT_UNUSED(result
, !result
);
367 #endif // USE(PTHREADS)