Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL
[WebKit-https.git] / Source / WTF / wtf / ThreadingPthreads.cpp
1 /*
2  * Copyright (C) 2007, 2009, 2015 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 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 "ThreadFunctionInvocation.h"
44 #include "ThreadIdentifierDataPthreads.h"
45 #include "ThreadSpecific.h"
46 #include <wtf/DataLog.h>
47 #include <wtf/NeverDestroyed.h>
48 #include <wtf/RawPointer.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 namespace WTF {
59
60 class PthreadState {
61     WTF_MAKE_FAST_ALLOCATED;
62 public:
63     enum JoinableState {
64         Joinable, // The default thread state. The thread can be joined on.
65
66         Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a 
67                 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run) 
68                 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's 
69                 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
70
71         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.
72     };
73
74     // Currently all threads created by WTF start out as joinable. 
75     PthreadState(pthread_t handle)
76         : m_joinableState(Joinable)
77         , m_didExit(false)
78         , m_pthreadHandle(handle)
79     {
80     }
81
82     JoinableState joinableState() { return m_joinableState; }
83     pthread_t pthreadHandle() { return m_pthreadHandle; }
84     void didBecomeDetached() { m_joinableState = Detached; }
85     void didExit() { m_didExit = true; }
86     void didJoin() { m_joinableState = Joined; }
87     bool hasExited() { return m_didExit; }
88
89 private:
90     JoinableState m_joinableState;
91     bool m_didExit;
92     pthread_t m_pthreadHandle;
93 };
94
95 typedef HashMap<ThreadIdentifier, std::unique_ptr<PthreadState>> ThreadMap;
96
97 void unsafeThreadWasDetached(ThreadIdentifier);
98 void threadDidExit(ThreadIdentifier);
99 void threadWasJoined(ThreadIdentifier);
100
101 static Mutex& threadMapMutex()
102 {
103     static NeverDestroyed<Mutex> mutex;
104     return mutex;
105 }
106
107 void initializeThreading()
108 {
109     static bool isInitialized;
110
111     if (isInitialized)
112         return;
113
114     isInitialized = true;
115
116     WTF::double_conversion::initialize();
117     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
118     // so ensure it has been initialized from here.
119     StringImpl::empty();
120     threadMapMutex();
121     initializeRandomNumberGenerator();
122     ThreadIdentifierData::initializeOnce();
123     wtfThreadData();
124     initializeDates();
125 }
126
127 static ThreadMap& threadMap()
128 {
129     static NeverDestroyed<ThreadMap> map;
130     return map;
131 }
132
133 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
134 {
135     MutexLocker locker(threadMapMutex());
136
137     ThreadMap::iterator i = threadMap().begin();
138     for (; i != threadMap().end(); ++i) {
139         if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
140             return i->key;
141     }
142
143     return 0;
144 }
145
146 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
147 {
148     ASSERT(!identifierByPthreadHandle(pthreadHandle));
149     MutexLocker locker(threadMapMutex());
150     static ThreadIdentifier identifierCount = 1;
151     threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
152     return identifierCount++;
153 }
154
155 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
156 {
157     return threadMap().get(id)->pthreadHandle();
158 }
159
160 static void* wtfThreadEntryPoint(void* param)
161 {
162     // Balanced by .leakPtr() in createThreadInternal.
163     auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param));
164     invocation->function(invocation->data);
165     return nullptr;
166 }
167
168 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
169 {
170     auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data);
171     pthread_t threadHandle;
172     pthread_attr_t attr;
173     pthread_attr_init(&attr);
174 #if HAVE(QOS_CLASSES)
175     pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INITIATED, 0);
176 #endif
177     int error = pthread_create(&threadHandle, &attr, wtfThreadEntryPoint, invocation.get());
178     pthread_attr_destroy(&attr);
179     if (error) {
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     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
200     ASSERT(id);
201     ThreadIdentifierData::initialize(id);
202 }
203     
204 void changeThreadPriority(ThreadIdentifier threadID, int delta)
205 {
206     pthread_t pthreadHandle;
207     ASSERT(threadID);
208
209     {
210         MutexLocker locker(threadMapMutex());
211         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
212         ASSERT(pthreadHandle);
213     }
214
215     int policy;
216     struct sched_param param;
217
218     if (pthread_getschedparam(pthreadHandle, &policy, &param))
219         return;
220
221     param.sched_priority += delta;
222
223     pthread_setschedparam(pthreadHandle, policy, &param);
224 }
225
226 int waitForThreadCompletion(ThreadIdentifier threadID)
227 {
228     pthread_t pthreadHandle;
229     ASSERT(threadID);
230
231     {
232         // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
233         MutexLocker locker(threadMapMutex());
234         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
235         ASSERT(pthreadHandle);
236     }
237
238     int joinResult = pthread_join(pthreadHandle, 0);
239
240     if (joinResult == EDEADLK)
241         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
242     else if (joinResult)
243         LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
244
245     MutexLocker locker(threadMapMutex());
246     PthreadState* state = threadMap().get(threadID);
247     ASSERT(state);
248     ASSERT(state->joinableState() == PthreadState::Joinable);
249
250     // The thread has already exited, so clean up after it.
251     if (state->hasExited())
252         threadMap().remove(threadID);
253     // 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.
254     else
255         state->didJoin();
256
257     return joinResult;
258 }
259
260 void detachThread(ThreadIdentifier threadID)
261 {
262     ASSERT(threadID);
263
264     MutexLocker locker(threadMapMutex());
265     pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
266     ASSERT(pthreadHandle);
267
268     int detachResult = pthread_detach(pthreadHandle);
269     if (detachResult)
270         LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
271
272     PthreadState* state = threadMap().get(threadID);
273     ASSERT(state);
274     if (state->hasExited())
275         threadMap().remove(threadID);
276     else
277         threadMap().get(threadID)->didBecomeDetached();
278 }
279
280 void threadDidExit(ThreadIdentifier threadID)
281 {
282     MutexLocker locker(threadMapMutex());
283     PthreadState* state = threadMap().get(threadID);
284     ASSERT(state);
285     
286     state->didExit();
287
288     if (state->joinableState() != PthreadState::Joinable)
289         threadMap().remove(threadID);
290 }
291
292 ThreadIdentifier currentThread()
293 {
294     ThreadIdentifier id = ThreadIdentifierData::identifier();
295     if (id)
296         return id;
297
298     // Not a WTF-created thread, ThreadIdentifier is not established yet.
299     id = establishIdentifierForPthreadHandle(pthread_self());
300     ThreadIdentifierData::initialize(id);
301     return id;
302 }
303
304 Mutex::Mutex()
305 {
306     pthread_mutexattr_t attr;
307     pthread_mutexattr_init(&attr);
308     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
309
310     int result = pthread_mutex_init(&m_mutex, &attr);
311     ASSERT_UNUSED(result, !result);
312
313     pthread_mutexattr_destroy(&attr);
314 }
315
316 Mutex::~Mutex()
317 {
318     int result = pthread_mutex_destroy(&m_mutex);
319     ASSERT_UNUSED(result, !result);
320 }
321
322 void Mutex::lock()
323 {
324     int result = pthread_mutex_lock(&m_mutex);
325     ASSERT_UNUSED(result, !result);
326 }
327
328 bool Mutex::tryLock()
329 {
330     int result = pthread_mutex_trylock(&m_mutex);
331
332     if (result == 0)
333         return true;
334     if (result == EBUSY)
335         return false;
336
337     ASSERT_NOT_REACHED();
338     return false;
339 }
340
341 void Mutex::unlock()
342 {
343     int result = pthread_mutex_unlock(&m_mutex);
344     ASSERT_UNUSED(result, !result);
345 }
346
347 ThreadCondition::ThreadCondition()
348
349     pthread_cond_init(&m_condition, NULL);
350 }
351
352 ThreadCondition::~ThreadCondition()
353 {
354     pthread_cond_destroy(&m_condition);
355 }
356     
357 void ThreadCondition::wait(Mutex& mutex)
358 {
359     int result = pthread_cond_wait(&m_condition, &mutex.impl());
360     ASSERT_UNUSED(result, !result);
361 }
362
363 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
364 {
365     if (absoluteTime < currentTime())
366         return false;
367
368     if (absoluteTime > INT_MAX) {
369         wait(mutex);
370         return true;
371     }
372
373     int timeSeconds = static_cast<int>(absoluteTime);
374     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
375
376     timespec targetTime;
377     targetTime.tv_sec = timeSeconds;
378     targetTime.tv_nsec = timeNanoseconds;
379
380     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
381 }
382
383 void ThreadCondition::signal()
384 {
385     int result = pthread_cond_signal(&m_condition);
386     ASSERT_UNUSED(result, !result);
387 }
388
389 void ThreadCondition::broadcast()
390 {
391     int result = pthread_cond_broadcast(&m_condition);
392     ASSERT_UNUSED(result, !result);
393 }
394
395 } // namespace WTF
396
397 #endif // USE(PTHREADS)