source: webkit/trunk/JavaScriptCore/wtf/ThreadingPthreads.cpp@ 44651

Last change on this file since 44651 was 44651, checked in by [email protected], 16 years ago

2009-06-12 Dave Hyatt <[email protected]>

Reviewed by Anders Carlsson.

https://bugs.webkit.org/show_bug.cgi?id=26373

Add a new class to Threading in wtf called ReadWriteLock that handles single writer/multiple reader locking.
Provide a pthreads-only implementation of the lock for now, as this class is only going to be used
on Snow Leopard at first.

  • wtf/Threading.h: (WTF::ReadWriteLock::impl):
  • wtf/ThreadingPthreads.cpp: (WTF::ReadWriteLock::ReadWriteLock): (WTF::ReadWriteLock::~ReadWriteLock): (WTF::ReadWriteLock::readLock): (WTF::ReadWriteLock::tryReadLock): (WTF::ReadWriteLock::writeLock): (WTF::ReadWriteLock::tryWriteLock): (WTF::ReadWriteLock::unlock):
  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1/*
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood ([email protected])
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 "UnusedParam.h"
41#include <errno.h>
42#include <limits.h>
43#include <sys/time.h>
44
45#if PLATFORM(ANDROID)
46#include "jni_utility.h"
47#endif
48
49namespace WTF {
50
51typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
52
53static Mutex* atomicallyInitializedStaticMutex;
54
55#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM)
56static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread.
57#endif
58
59static Mutex& threadMapMutex()
60{
61 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
62 return mutex;
63}
64
65void initializeThreading()
66{
67 if (!atomicallyInitializedStaticMutex) {
68 atomicallyInitializedStaticMutex = new Mutex;
69 threadMapMutex();
70 initializeRandomNumberGenerator();
71#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM)
72 mainThreadIdentifier = currentThread();
73#endif
74 initializeMainThread();
75 }
76}
77
78void lockAtomicallyInitializedStaticMutex()
79{
80 ASSERT(atomicallyInitializedStaticMutex);
81 atomicallyInitializedStaticMutex->lock();
82}
83
84void unlockAtomicallyInitializedStaticMutex()
85{
86 atomicallyInitializedStaticMutex->unlock();
87}
88
89static ThreadMap& threadMap()
90{
91 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
92 return map;
93}
94
95static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
96{
97 MutexLocker locker(threadMapMutex());
98
99 ThreadMap::iterator i = threadMap().begin();
100 for (; i != threadMap().end(); ++i) {
101 if (pthread_equal(i->second, pthreadHandle))
102 return i->first;
103 }
104
105 return 0;
106}
107
108static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
109{
110 ASSERT(!identifierByPthreadHandle(pthreadHandle));
111
112 MutexLocker locker(threadMapMutex());
113
114 static ThreadIdentifier identifierCount = 1;
115
116 threadMap().add(identifierCount, pthreadHandle);
117
118 return identifierCount++;
119}
120
121static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
122{
123 MutexLocker locker(threadMapMutex());
124
125 return threadMap().get(id);
126}
127
128static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
129{
130 MutexLocker locker(threadMapMutex());
131
132 ASSERT(threadMap().contains(id));
133
134 threadMap().remove(id);
135}
136
137#if PLATFORM(ANDROID)
138// On the Android platform, threads must be registered with the VM before they run.
139struct ThreadData {
140 ThreadFunction entryPoint;
141 void* arg;
142};
143
144static void* runThreadWithRegistration(void* arg)
145{
146 ThreadData* data = static_cast<ThreadData*>(arg);
147 JavaVM* vm = JSC::Bindings::getJavaVM();
148 JNIEnv* env;
149 void* ret = 0;
150 if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
151 ret = data->entryPoint(data->arg);
152 vm->DetachCurrentThread();
153 }
154 delete data;
155 return ret;
156}
157
158ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
159{
160 pthread_t threadHandle;
161 ThreadData* threadData = new ThreadData();
162 threadData->entryPoint = entryPoint;
163 threadData->arg = data;
164
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);
167 return 0;
168 }
169 return establishIdentifierForPthreadHandle(threadHandle);
170}
171#else
172ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
173{
174 pthread_t threadHandle;
175 if (pthread_create(&threadHandle, 0, entryPoint, data)) {
176 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
177 return 0;
178 }
179
180 return establishIdentifierForPthreadHandle(threadHandle);
181}
182#endif
183
184void setThreadNameInternal(const char* threadName)
185{
186#if PLATFORM(DARWIN) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !PLATFORM(IPHONE)
187 pthread_setname_np(threadName);
188#else
189 UNUSED_PARAM(threadName);
190#endif
191}
192
193int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
194{
195 ASSERT(threadID);
196
197 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
198
199 int joinResult = pthread_join(pthreadHandle, result);
200 if (joinResult == EDEADLK)
201 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
202
203 clearPthreadHandleForIdentifier(threadID);
204 return joinResult;
205}
206
207void detachThread(ThreadIdentifier threadID)
208{
209 ASSERT(threadID);
210
211 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
212
213 pthread_detach(pthreadHandle);
214
215 clearPthreadHandleForIdentifier(threadID);
216}
217
218ThreadIdentifier currentThread()
219{
220 pthread_t currentThread = pthread_self();
221 if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
222 return id;
223 return establishIdentifierForPthreadHandle(currentThread);
224}
225
226bool isMainThread()
227{
228#if PLATFORM(DARWIN) && !PLATFORM(CHROMIUM)
229 return pthread_main_np();
230#else
231 return currentThread() == mainThreadIdentifier;
232#endif
233}
234
235Mutex::Mutex()
236{
237 pthread_mutex_init(&m_mutex, NULL);
238}
239
240Mutex::~Mutex()
241{
242 pthread_mutex_destroy(&m_mutex);
243}
244
245void Mutex::lock()
246{
247 int result = pthread_mutex_lock(&m_mutex);
248 ASSERT_UNUSED(result, !result);
249}
250
251bool Mutex::tryLock()
252{
253 int result = pthread_mutex_trylock(&m_mutex);
254
255 if (result == 0)
256 return true;
257 if (result == EBUSY)
258 return false;
259
260 ASSERT_NOT_REACHED();
261 return false;
262}
263
264void Mutex::unlock()
265{
266 int result = pthread_mutex_unlock(&m_mutex);
267 ASSERT_UNUSED(result, !result);
268}
269
270
271ReadWriteLock::ReadWriteLock()
272{
273 pthread_rwlock_init(&m_readWriteLock, NULL);
274}
275
276ReadWriteLock::~ReadWriteLock()
277{
278 pthread_rwlock_destroy(&m_readWriteLock);
279}
280
281void ReadWriteLock::readLock()
282{
283 int result = pthread_rwlock_rdlock(&m_readWriteLock);
284 ASSERT_UNUSED(result, !result);
285}
286
287bool ReadWriteLock::tryReadLock()
288{
289 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
290
291 if (result == 0)
292 return true;
293 if (result == EBUSY || result == EAGAIN)
294 return false;
295
296 ASSERT_NOT_REACHED();
297 return false;
298}
299
300void ReadWriteLock::writeLock()
301{
302 int result = pthread_rwlock_wrlock(&m_readWriteLock);
303 ASSERT_UNUSED(result, !result);
304}
305
306bool ReadWriteLock::tryWriteLock()
307{
308 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
309
310 if (result == 0)
311 return true;
312 if (result == EBUSY || result == EAGAIN)
313 return false;
314
315 ASSERT_NOT_REACHED();
316 return false;
317}
318
319void ReadWriteLock::unlock()
320{
321 int result = pthread_rwlock_unlock(&m_readWriteLock);
322 ASSERT_UNUSED(result, !result);
323}
324
325ThreadCondition::ThreadCondition()
326{
327 pthread_cond_init(&m_condition, NULL);
328}
329
330ThreadCondition::~ThreadCondition()
331{
332 pthread_cond_destroy(&m_condition);
333}
334
335void ThreadCondition::wait(Mutex& mutex)
336{
337 int result = pthread_cond_wait(&m_condition, &mutex.impl());
338 ASSERT_UNUSED(result, !result);
339}
340
341bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
342{
343 if (absoluteTime < currentTime())
344 return false;
345
346 if (absoluteTime > INT_MAX) {
347 wait(mutex);
348 return true;
349 }
350
351 int timeSeconds = static_cast<int>(absoluteTime);
352 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
353
354 timespec targetTime;
355 targetTime.tv_sec = timeSeconds;
356 targetTime.tv_nsec = timeNanoseconds;
357
358 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
359}
360
361void ThreadCondition::signal()
362{
363 int result = pthread_cond_signal(&m_condition);
364 ASSERT_UNUSED(result, !result);
365}
366
367void ThreadCondition::broadcast()
368{
369 int result = pthread_cond_broadcast(&m_condition);
370 ASSERT_UNUSED(result, !result);
371}
372
373} // namespace WTF
374
375#endif // USE(PTHREADS)
Note: See TracBrowser for help on using the repository browser.