Fix an assertion failure in initializeDates() when launching Safari, which was introd...
[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 void unsafeThreadWasDetached(ThreadIdentifier);
102 void threadDidExit(ThreadIdentifier);
103 void threadWasJoined(ThreadIdentifier);
104
105 static Mutex& threadMapMutex()
106 {
107     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
108     return mutex;
109 }
110
111 void initializeThreading()
112 {
113     static bool isInitialized;
114
115     if (isInitialized)
116         return;
117
118     isInitialized = true;
119
120     WTF::double_conversion::initialize();
121     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
122     // so ensure it has been initialized from here.
123     StringImpl::empty();
124
125     threadMapMutex();
126     initializeRandomNumberGenerator();
127     ThreadIdentifierData::initializeOnce();
128     StackStats::initialize();
129     wtfThreadData();
130     s_dtoaP5Mutex = new Mutex;
131     initializeDates();
132 }
133
134 static ThreadMap& threadMap()
135 {
136     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
137     return map;
138 }
139
140 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
141 {
142     MutexLocker locker(threadMapMutex());
143
144     ThreadMap::iterator i = threadMap().begin();
145     for (; i != threadMap().end(); ++i) {
146         if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
147             return i->key;
148     }
149
150     return 0;
151 }
152
153 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
154 {
155     ASSERT(!identifierByPthreadHandle(pthreadHandle));
156     MutexLocker locker(threadMapMutex());
157     static ThreadIdentifier identifierCount = 1;
158     threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
159     return identifierCount++;
160 }
161
162 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
163 {
164     return threadMap().get(id)->pthreadHandle();
165 }
166
167 static void* wtfThreadEntryPoint(void* param)
168 {
169     // Balanced by .leakPtr() in createThreadInternal.
170     auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param));
171     invocation->function(invocation->data);
172     return nullptr;
173 }
174
175 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
176 {
177     auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data);
178     pthread_t threadHandle;
179     if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
180         LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
181         return 0;
182     }
183
184     // Balanced by std::unique_ptr constructor in wtfThreadEntryPoint.
185     ThreadFunctionInvocation* leakedInvocation = invocation.release();
186     UNUSED_PARAM(leakedInvocation);
187
188     return establishIdentifierForPthreadHandle(threadHandle);
189 }
190
191 void initializeCurrentThreadInternal(const char* threadName)
192 {
193 #if HAVE(PTHREAD_SETNAME_NP)
194     pthread_setname_np(threadName);
195 #else
196     UNUSED_PARAM(threadName);
197 #endif
198
199 #if OS(MAC_OS_X)
200     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
201     // garbage collector in case API implementations use garbage-collected memory.
202     objc_registerThreadWithCollector();
203 #endif
204
205     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
206     ASSERT(id);
207     ThreadIdentifierData::initialize(id);
208 }
209
210 int waitForThreadCompletion(ThreadIdentifier threadID)
211 {
212     pthread_t pthreadHandle;
213     ASSERT(threadID);
214
215     {
216         // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
217         MutexLocker locker(threadMapMutex());
218         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
219         ASSERT(pthreadHandle);
220     }
221
222     int joinResult = pthread_join(pthreadHandle, 0);
223
224     if (joinResult == EDEADLK)
225         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
226     else if (joinResult)
227         LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
228
229     MutexLocker locker(threadMapMutex());
230     PthreadState* state = threadMap().get(threadID);
231     ASSERT(state);
232     ASSERT(state->joinableState() == PthreadState::Joinable);
233
234     // The thread has already exited, so clean up after it.
235     if (state->hasExited())
236         threadMap().remove(threadID);
237     // 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.
238     else
239         state->didJoin();
240
241     return joinResult;
242 }
243
244 void detachThread(ThreadIdentifier threadID)
245 {
246     ASSERT(threadID);
247
248     MutexLocker locker(threadMapMutex());
249     pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
250     ASSERT(pthreadHandle);
251
252     int detachResult = pthread_detach(pthreadHandle);
253     if (detachResult)
254         LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
255
256     PthreadState* state = threadMap().get(threadID);
257     ASSERT(state);
258     if (state->hasExited())
259         threadMap().remove(threadID);
260     else
261         threadMap().get(threadID)->didBecomeDetached();
262 }
263
264 void threadDidExit(ThreadIdentifier threadID)
265 {
266     MutexLocker locker(threadMapMutex());
267     PthreadState* state = threadMap().get(threadID);
268     ASSERT(state);
269     
270     state->didExit();
271
272     if (state->joinableState() != PthreadState::Joinable)
273         threadMap().remove(threadID);
274 }
275
276 ThreadIdentifier currentThread()
277 {
278     ThreadIdentifier id = ThreadIdentifierData::identifier();
279     if (id)
280         return id;
281
282     // Not a WTF-created thread, ThreadIdentifier is not established yet.
283     id = establishIdentifierForPthreadHandle(pthread_self());
284     ThreadIdentifierData::initialize(id);
285     return id;
286 }
287
288 Mutex::Mutex()
289 {
290     pthread_mutexattr_t attr;
291     pthread_mutexattr_init(&attr);
292     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
293
294     int result = pthread_mutex_init(&m_mutex, &attr);
295     ASSERT_UNUSED(result, !result);
296
297     pthread_mutexattr_destroy(&attr);
298 }
299
300 Mutex::~Mutex()
301 {
302     int result = pthread_mutex_destroy(&m_mutex);
303     ASSERT_UNUSED(result, !result);
304 }
305
306 void Mutex::lock()
307 {
308     int result = pthread_mutex_lock(&m_mutex);
309     ASSERT_UNUSED(result, !result);
310 }
311
312 bool Mutex::tryLock()
313 {
314     int result = pthread_mutex_trylock(&m_mutex);
315
316     if (result == 0)
317         return true;
318     if (result == EBUSY)
319         return false;
320
321     ASSERT_NOT_REACHED();
322     return false;
323 }
324
325 void Mutex::unlock()
326 {
327     int result = pthread_mutex_unlock(&m_mutex);
328     ASSERT_UNUSED(result, !result);
329 }
330
331 ThreadCondition::ThreadCondition()
332
333     pthread_cond_init(&m_condition, NULL);
334 }
335
336 ThreadCondition::~ThreadCondition()
337 {
338     pthread_cond_destroy(&m_condition);
339 }
340     
341 void ThreadCondition::wait(Mutex& mutex)
342 {
343     int result = pthread_cond_wait(&m_condition, &mutex.impl());
344     ASSERT_UNUSED(result, !result);
345 }
346
347 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
348 {
349     if (absoluteTime < currentTime())
350         return false;
351
352     if (absoluteTime > INT_MAX) {
353         wait(mutex);
354         return true;
355     }
356
357     int timeSeconds = static_cast<int>(absoluteTime);
358     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
359
360     timespec targetTime;
361     targetTime.tv_sec = timeSeconds;
362     targetTime.tv_nsec = timeNanoseconds;
363
364     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
365 }
366
367 void ThreadCondition::signal()
368 {
369     int result = pthread_cond_signal(&m_condition);
370     ASSERT_UNUSED(result, !result);
371 }
372
373 void ThreadCondition::broadcast()
374 {
375     int result = pthread_cond_broadcast(&m_condition);
376     ASSERT_UNUSED(result, !result);
377 }
378
379 } // namespace WTF
380
381 #endif // USE(PTHREADS)