Add hash traits for std::unique_ptr
[WebKit-https.git] / Source / WTF / 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 "StackStats.h"
43 #include "StdLibExtras.h"
44 #include "ThreadFunctionInvocation.h"
45 #include "ThreadIdentifierDataPthreads.h"
46 #include "ThreadSpecific.h"
47 #include <wtf/OwnPtr.h>
48 #include <wtf/PassOwnPtr.h>
49 #include <wtf/WTFThreadData.h>
50 #include <errno.h>
51
52 #if !COMPILER(MSVC)
53 #include <limits.h>
54 #include <sched.h>
55 #include <sys/time.h>
56 #endif
57
58 #if OS(MAC_OS_X)
59 #include <objc/objc-auto.h>
60 #endif
61
62 namespace WTF {
63
64 class PthreadState {
65     WTF_MAKE_FAST_ALLOCATED;
66 public:
67     enum JoinableState {
68         Joinable, // The default thread state. The thread can be joined on.
69
70         Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a 
71                 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run) 
72                 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's 
73                 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
74
75         Detached // The thread has been detached and can no longer be joined on. At this point, the thread must take care of cleaning up after itself.
76     };
77
78     // Currently all threads created by WTF start out as joinable. 
79     PthreadState(pthread_t handle)
80         : m_joinableState(Joinable)
81         , m_didExit(false)
82         , m_pthreadHandle(handle)
83     {
84     }
85
86     JoinableState joinableState() { return m_joinableState; }
87     pthread_t pthreadHandle() { return m_pthreadHandle; }
88     void didBecomeDetached() { m_joinableState = Detached; }
89     void didExit() { m_didExit = true; }
90     void didJoin() { m_joinableState = Joined; }
91     bool hasExited() { return m_didExit; }
92
93 private:
94     JoinableState m_joinableState;
95     bool m_didExit;
96     pthread_t m_pthreadHandle;
97 };
98
99 typedef HashMap<ThreadIdentifier, std::unique_ptr<PthreadState>> ThreadMap;
100
101 static Mutex* atomicallyInitializedStaticMutex;
102
103 void unsafeThreadWasDetached(ThreadIdentifier);
104 void threadDidExit(ThreadIdentifier);
105 void threadWasJoined(ThreadIdentifier);
106
107 static Mutex& threadMapMutex()
108 {
109     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
110     return mutex;
111 }
112
113 #if OS(QNX) && CPU(ARM_THUMB2)
114 static void enableIEEE754Denormal()
115 {
116     // Clear the ARM_VFP_FPSCR_FZ flag in FPSCR.
117     unsigned fpscr;
118     asm volatile("vmrs %0, fpscr" : "=r"(fpscr));
119     fpscr &= ~0x01000000u;
120     asm volatile("vmsr fpscr, %0" : : "r"(fpscr));
121 }
122 #endif
123
124 void initializeThreading()
125 {
126     if (atomicallyInitializedStaticMutex)
127         return;
128
129 #if OS(QNX) && CPU(ARM_THUMB2)
130     enableIEEE754Denormal();
131 #endif
132
133     WTF::double_conversion::initialize();
134     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
135     // so ensure it has been initialized from here.
136     StringImpl::empty();
137     atomicallyInitializedStaticMutex = new Mutex;
138     threadMapMutex();
139     initializeRandomNumberGenerator();
140     ThreadIdentifierData::initializeOnce();
141     StackStats::initialize();
142     wtfThreadData();
143     s_dtoaP5Mutex = new Mutex;
144     initializeDates();
145 }
146
147 void lockAtomicallyInitializedStaticMutex()
148 {
149     ASSERT(atomicallyInitializedStaticMutex);
150     atomicallyInitializedStaticMutex->lock();
151 }
152
153 void unlockAtomicallyInitializedStaticMutex()
154 {
155     atomicallyInitializedStaticMutex->unlock();
156 }
157
158 static ThreadMap& threadMap()
159 {
160     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
161     return map;
162 }
163
164 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
165 {
166     MutexLocker locker(threadMapMutex());
167
168     ThreadMap::iterator i = threadMap().begin();
169     for (; i != threadMap().end(); ++i) {
170         if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
171             return i->key;
172     }
173
174     return 0;
175 }
176
177 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
178 {
179     ASSERT(!identifierByPthreadHandle(pthreadHandle));
180     MutexLocker locker(threadMapMutex());
181     static ThreadIdentifier identifierCount = 1;
182     threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
183     return identifierCount++;
184 }
185
186 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
187 {
188     return threadMap().get(id)->pthreadHandle();
189 }
190
191 static void* wtfThreadEntryPoint(void* param)
192 {
193     // Balanced by .leakPtr() in createThreadInternal.
194     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
195     invocation->function(invocation->data);
196     return 0;
197 }
198
199 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
200 {
201     auto invocation = WTF::createOwned<ThreadFunctionInvocation>(entryPoint, data);
202     pthread_t threadHandle;
203     if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
204         LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
205         return 0;
206     }
207
208     // Balanced by adoptPtr() in wtfThreadEntryPoint.
209     ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
210     UNUSED_PARAM(leakedInvocation);
211
212     return establishIdentifierForPthreadHandle(threadHandle);
213 }
214
215 void initializeCurrentThreadInternal(const char* threadName)
216 {
217 #if HAVE(PTHREAD_SETNAME_NP)
218     pthread_setname_np(threadName);
219 #elif OS(QNX)
220     pthread_setname_np(pthread_self(), threadName);
221 #else
222     UNUSED_PARAM(threadName);
223 #endif
224
225 #if OS(MAC_OS_X)
226     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
227     // garbage collector in case API implementations use garbage-collected memory.
228     objc_registerThreadWithCollector();
229 #endif
230
231 #if OS(QNX) && CPU(ARM_THUMB2)
232     enableIEEE754Denormal();
233 #endif
234
235     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
236     ASSERT(id);
237     ThreadIdentifierData::initialize(id);
238 }
239
240 int waitForThreadCompletion(ThreadIdentifier threadID)
241 {
242     pthread_t pthreadHandle;
243     ASSERT(threadID);
244
245     {
246         // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
247         MutexLocker locker(threadMapMutex());
248         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
249         ASSERT(pthreadHandle);
250     }
251
252     int joinResult = pthread_join(pthreadHandle, 0);
253
254     if (joinResult == EDEADLK)
255         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
256     else if (joinResult)
257         LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
258
259     MutexLocker locker(threadMapMutex());
260     PthreadState* state = threadMap().get(threadID);
261     ASSERT(state);
262     ASSERT(state->joinableState() == PthreadState::Joinable);
263
264     // The thread has already exited, so clean up after it.
265     if (state->hasExited())
266         threadMap().remove(threadID);
267     // The thread hasn't exited yet, so don't clean anything up. Just signal that we've already joined on it so that it will clean up after itself.
268     else
269         state->didJoin();
270
271     return joinResult;
272 }
273
274 void detachThread(ThreadIdentifier threadID)
275 {
276     ASSERT(threadID);
277
278     MutexLocker locker(threadMapMutex());
279     pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
280     ASSERT(pthreadHandle);
281
282     int detachResult = pthread_detach(pthreadHandle);
283     if (detachResult)
284         LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
285
286     PthreadState* state = threadMap().get(threadID);
287     ASSERT(state);
288     if (state->hasExited())
289         threadMap().remove(threadID);
290     else
291         threadMap().get(threadID)->didBecomeDetached();
292 }
293
294 void threadDidExit(ThreadIdentifier threadID)
295 {
296     MutexLocker locker(threadMapMutex());
297     PthreadState* state = threadMap().get(threadID);
298     ASSERT(state);
299     
300     state->didExit();
301
302     if (state->joinableState() != PthreadState::Joinable)
303         threadMap().remove(threadID);
304 }
305
306 void yield()
307 {
308     sched_yield();
309 }
310
311 ThreadIdentifier currentThread()
312 {
313     ThreadIdentifier id = ThreadIdentifierData::identifier();
314     if (id)
315         return id;
316
317     // Not a WTF-created thread, ThreadIdentifier is not established yet.
318     id = establishIdentifierForPthreadHandle(pthread_self());
319     ThreadIdentifierData::initialize(id);
320     return id;
321 }
322
323 Mutex::Mutex()
324 {
325     pthread_mutexattr_t attr;
326     pthread_mutexattr_init(&attr);
327     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
328
329     int result = pthread_mutex_init(&m_mutex, &attr);
330     ASSERT_UNUSED(result, !result);
331
332     pthread_mutexattr_destroy(&attr);
333 }
334
335 Mutex::~Mutex()
336 {
337     int result = pthread_mutex_destroy(&m_mutex);
338     ASSERT_UNUSED(result, !result);
339 }
340
341 void Mutex::lock()
342 {
343     int result = pthread_mutex_lock(&m_mutex);
344     ASSERT_UNUSED(result, !result);
345 }
346
347 bool Mutex::tryLock()
348 {
349     int result = pthread_mutex_trylock(&m_mutex);
350
351     if (result == 0)
352         return true;
353     if (result == EBUSY)
354         return false;
355
356     ASSERT_NOT_REACHED();
357     return false;
358 }
359
360 void Mutex::unlock()
361 {
362     int result = pthread_mutex_unlock(&m_mutex);
363     ASSERT_UNUSED(result, !result);
364 }
365
366 ThreadCondition::ThreadCondition()
367
368     pthread_cond_init(&m_condition, NULL);
369 }
370
371 ThreadCondition::~ThreadCondition()
372 {
373     pthread_cond_destroy(&m_condition);
374 }
375     
376 void ThreadCondition::wait(Mutex& mutex)
377 {
378     int result = pthread_cond_wait(&m_condition, &mutex.impl());
379     ASSERT_UNUSED(result, !result);
380 }
381
382 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
383 {
384     if (absoluteTime < currentTime())
385         return false;
386
387     if (absoluteTime > INT_MAX) {
388         wait(mutex);
389         return true;
390     }
391
392     int timeSeconds = static_cast<int>(absoluteTime);
393     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
394
395     timespec targetTime;
396     targetTime.tv_sec = timeSeconds;
397     targetTime.tv_nsec = timeNanoseconds;
398
399     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
400 }
401
402 void ThreadCondition::signal()
403 {
404     int result = pthread_cond_signal(&m_condition);
405     ASSERT_UNUSED(result, !result);
406 }
407
408 void ThreadCondition::broadcast()
409 {
410     int result = pthread_cond_broadcast(&m_condition);
411     ASSERT_UNUSED(result, !result);
412 }
413
414 } // namespace WTF
415
416 #endif // USE(PTHREADS)