763ec2bbbbd39f1dcd527116792dacf79fd65754
[WebKit-https.git] / Source / JavaScriptCore / wtf / ThreadingPthreads.cpp
1 /*
2  * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer. 
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution. 
15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission. 
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "Threading.h"
33
34 #if USE(PTHREADS)
35
36 #include "CurrentTime.h"
37 #include "DateMath.h"
38 #include "dtoa.h"
39 #include "dtoa/cached-powers.h"
40 #include "HashMap.h"
41 #include "RandomNumberSeed.h"
42 #include "StdLibExtras.h"
43 #include "ThreadIdentifierDataPthreads.h"
44 #include "ThreadSpecific.h"
45 #include "UnusedParam.h"
46 #include <wtf/WTFThreadData.h>
47 #include <errno.h>
48
49 #if !COMPILER(MSVC)
50 #include <limits.h>
51 #include <sched.h>
52 #include <sys/time.h>
53 #endif
54
55 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
56 #include <objc/objc-auto.h>
57 #endif
58
59 #if PLATFORM(BLACKBERRY)
60 #include <BlackBerryPlatformMisc.h>
61 #include <BlackBerryPlatformSettings.h>
62 #endif
63
64 namespace WTF {
65
66 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
67
68 static Mutex* atomicallyInitializedStaticMutex;
69
70 void clearPthreadHandleForIdentifier(ThreadIdentifier);
71
72 static Mutex& threadMapMutex()
73 {
74     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
75     return mutex;
76 }
77
78 void initializeThreading()
79 {
80     if (atomicallyInitializedStaticMutex)
81         return;
82
83     WTF::double_conversion::initialize();
84     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
85     // so ensure it has been initialized from here.
86     StringImpl::empty();
87     atomicallyInitializedStaticMutex = new Mutex;
88     threadMapMutex();
89     initializeRandomNumberGenerator();
90     ThreadIdentifierData::initializeOnce();
91     wtfThreadData();
92     s_dtoaP5Mutex = new Mutex;
93     initializeDates();
94 }
95
96 void lockAtomicallyInitializedStaticMutex()
97 {
98     ASSERT(atomicallyInitializedStaticMutex);
99     atomicallyInitializedStaticMutex->lock();
100 }
101
102 void unlockAtomicallyInitializedStaticMutex()
103 {
104     atomicallyInitializedStaticMutex->unlock();
105 }
106
107 static ThreadMap& threadMap()
108 {
109     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
110     return map;
111 }
112
113 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
114 {
115     MutexLocker locker(threadMapMutex());
116
117     ThreadMap::iterator i = threadMap().begin();
118     for (; i != threadMap().end(); ++i) {
119         if (pthread_equal(i->second, pthreadHandle))
120             return i->first;
121     }
122
123     return 0;
124 }
125
126 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
127 {
128     ASSERT(!identifierByPthreadHandle(pthreadHandle));
129
130     MutexLocker locker(threadMapMutex());
131
132     static ThreadIdentifier identifierCount = 1;
133
134     threadMap().add(identifierCount, pthreadHandle);
135
136     return identifierCount++;
137 }
138
139 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
140 {
141     MutexLocker locker(threadMapMutex());
142
143     return threadMap().get(id);
144 }
145
146 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
147 {
148     MutexLocker locker(threadMapMutex());
149
150     ASSERT(threadMap().contains(id));
151
152     threadMap().remove(id);
153 }
154
155 #if PLATFORM(BLACKBERRY)
156 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
157 {
158     pthread_attr_t attr;
159     if (pthread_attr_init(&attr)) {
160         LOG_ERROR("pthread_attr_init() failed: %d", errno);
161         return 0;
162     }
163
164     void* stackAddr;
165     size_t stackSize;
166     if (pthread_attr_getstack(&attr, &stackAddr, &stackSize))
167         LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
168     else {
169         stackSize = BlackBerry::Platform::Settings::get()->secondaryThreadStackSize();
170         if (pthread_attr_setstack(&attr, stackAddr, stackSize))
171             LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
172     }
173
174     pthread_t threadHandle;
175     if (pthread_create(&threadHandle, &attr, entryPoint, data)) {
176         LOG_ERROR("pthread_create() failed: %d", errno);
177         threadHandle = 0;
178     }
179     pthread_setname_np(threadHandle, threadName);
180
181     pthread_attr_destroy(&attr);
182
183     if (!threadHandle)
184         return 0;
185
186     return establishIdentifierForPthreadHandle(threadHandle);
187 }
188 #else
189 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
190 {
191     pthread_t threadHandle;
192     if (pthread_create(&threadHandle, 0, entryPoint, data)) {
193         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
194         return 0;
195     }
196
197     return establishIdentifierForPthreadHandle(threadHandle);
198 }
199 #endif
200
201 void initializeCurrentThreadInternal(const char* threadName)
202 {
203 #if HAVE(PTHREAD_SETNAME_NP)
204     pthread_setname_np(threadName);
205 #else
206     UNUSED_PARAM(threadName);
207 #endif
208
209 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
210     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
211     // garbage collector in case API implementations use garbage-collected memory.
212     objc_registerThreadWithCollector();
213 #endif
214
215     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
216     ASSERT(id);
217     ThreadIdentifierData::initialize(id);
218 }
219
220 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
221 {
222     ASSERT(threadID);
223
224     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
225     if (!pthreadHandle)
226         return 0;
227
228     int joinResult = pthread_join(pthreadHandle, result);
229     if (joinResult == EDEADLK)
230         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
231
232     return joinResult;
233 }
234
235 void detachThread(ThreadIdentifier threadID)
236 {
237     ASSERT(threadID);
238
239     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
240     if (!pthreadHandle)
241         return;
242
243     pthread_detach(pthreadHandle);
244 }
245
246 void yield()
247 {
248     sched_yield();
249 }
250
251 ThreadIdentifier currentThread()
252 {
253     ThreadIdentifier id = ThreadIdentifierData::identifier();
254     if (id)
255         return id;
256
257     // Not a WTF-created thread, ThreadIdentifier is not established yet.
258     id = establishIdentifierForPthreadHandle(pthread_self());
259     ThreadIdentifierData::initialize(id);
260     return id;
261 }
262
263 Mutex::Mutex()
264 {
265     pthread_mutexattr_t attr;
266     pthread_mutexattr_init(&attr);
267     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
268
269     pthread_mutex_init(&m_mutex, &attr);
270
271     pthread_mutexattr_destroy(&attr);
272 }
273
274 Mutex::~Mutex()
275 {
276     pthread_mutex_destroy(&m_mutex);
277 }
278
279 void Mutex::lock()
280 {
281     int result = pthread_mutex_lock(&m_mutex);
282     ASSERT_UNUSED(result, !result);
283 }
284
285 bool Mutex::tryLock()
286 {
287     int result = pthread_mutex_trylock(&m_mutex);
288
289     if (result == 0)
290         return true;
291     if (result == EBUSY)
292         return false;
293
294     ASSERT_NOT_REACHED();
295     return false;
296 }
297
298 void Mutex::unlock()
299 {
300     int result = pthread_mutex_unlock(&m_mutex);
301     ASSERT_UNUSED(result, !result);
302 }
303
304 #if HAVE(PTHREAD_RWLOCK)
305 ReadWriteLock::ReadWriteLock()
306 {
307     pthread_rwlock_init(&m_readWriteLock, NULL);
308 }
309
310 ReadWriteLock::~ReadWriteLock()
311 {
312     pthread_rwlock_destroy(&m_readWriteLock);
313 }
314
315 void ReadWriteLock::readLock()
316 {
317     int result = pthread_rwlock_rdlock(&m_readWriteLock);
318     ASSERT_UNUSED(result, !result);
319 }
320
321 bool ReadWriteLock::tryReadLock()
322 {
323     int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
324
325     if (result == 0)
326         return true;
327     if (result == EBUSY || result == EAGAIN)
328         return false;
329
330     ASSERT_NOT_REACHED();
331     return false;
332 }
333
334 void ReadWriteLock::writeLock()
335 {
336     int result = pthread_rwlock_wrlock(&m_readWriteLock);
337     ASSERT_UNUSED(result, !result);
338 }
339
340 bool ReadWriteLock::tryWriteLock()
341 {
342     int result = pthread_rwlock_trywrlock(&m_readWriteLock);
343
344     if (result == 0)
345         return true;
346     if (result == EBUSY || result == EAGAIN)
347         return false;
348
349     ASSERT_NOT_REACHED();
350     return false;
351 }
352
353 void ReadWriteLock::unlock()
354 {
355     int result = pthread_rwlock_unlock(&m_readWriteLock);
356     ASSERT_UNUSED(result, !result);
357 }
358 #endif  // HAVE(PTHREAD_RWLOCK)
359
360 ThreadCondition::ThreadCondition()
361
362     pthread_cond_init(&m_condition, NULL);
363 }
364
365 ThreadCondition::~ThreadCondition()
366 {
367     pthread_cond_destroy(&m_condition);
368 }
369     
370 void ThreadCondition::wait(Mutex& mutex)
371 {
372     int result = pthread_cond_wait(&m_condition, &mutex.impl());
373     ASSERT_UNUSED(result, !result);
374 }
375
376 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
377 {
378     if (absoluteTime < currentTime())
379         return false;
380
381     if (absoluteTime > INT_MAX) {
382         wait(mutex);
383         return true;
384     }
385
386     int timeSeconds = static_cast<int>(absoluteTime);
387     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
388
389     timespec targetTime;
390     targetTime.tv_sec = timeSeconds;
391     targetTime.tv_nsec = timeNanoseconds;
392
393     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
394 }
395
396 void ThreadCondition::signal()
397 {
398     int result = pthread_cond_signal(&m_condition);
399     ASSERT_UNUSED(result, !result);
400 }
401
402 void ThreadCondition::broadcast()
403 {
404     int result = pthread_cond_broadcast(&m_condition);
405     ASSERT_UNUSED(result, !result);
406 }
407
408 } // namespace WTF
409
410 #endif // USE(PTHREADS)