Use prctl to name thread on Linux
[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 #if OS(LINUX)
59 #include <sys/prctl.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     static NeverDestroyed<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     threadMapMutex();
125     initializeRandomNumberGenerator();
126     ThreadIdentifierData::initializeOnce();
127     wtfThreadData();
128     initializeDates();
129 }
130
131 static ThreadMap& threadMap()
132 {
133     static NeverDestroyed<ThreadMap> map;
134     return map;
135 }
136
137 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
138 {
139     MutexLocker locker(threadMapMutex());
140
141     ThreadMap::iterator i = threadMap().begin();
142     for (; i != threadMap().end(); ++i) {
143         if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
144             return i->key;
145     }
146
147     return 0;
148 }
149
150 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
151 {
152     ASSERT(!identifierByPthreadHandle(pthreadHandle));
153     MutexLocker locker(threadMapMutex());
154     static ThreadIdentifier identifierCount = 1;
155     threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
156     return identifierCount++;
157 }
158
159 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
160 {
161     return threadMap().get(id)->pthreadHandle();
162 }
163
164 static void* wtfThreadEntryPoint(void* param)
165 {
166     // Balanced by .leakPtr() in createThreadInternal.
167     auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param));
168     invocation->function(invocation->data);
169     return nullptr;
170 }
171
172 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
173 {
174     auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data);
175     pthread_t threadHandle;
176     pthread_attr_t attr;
177     pthread_attr_init(&attr);
178 #if HAVE(QOS_CLASSES)
179     pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INITIATED, 0);
180 #endif
181     int error = pthread_create(&threadHandle, &attr, wtfThreadEntryPoint, invocation.get());
182     pthread_attr_destroy(&attr);
183     if (error) {
184         LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
185         return 0;
186     }
187
188     // Balanced by std::unique_ptr constructor in wtfThreadEntryPoint.
189     ThreadFunctionInvocation* leakedInvocation = invocation.release();
190     UNUSED_PARAM(leakedInvocation);
191
192     return establishIdentifierForPthreadHandle(threadHandle);
193 }
194
195 void initializeCurrentThreadInternal(const char* threadName)
196 {
197 #if HAVE(PTHREAD_SETNAME_NP)
198     pthread_setname_np(threadName);
199 #elif OS(LINUX)
200     prctl(PR_SET_NAME, threadName);
201 #else
202     UNUSED_PARAM(threadName);
203 #endif
204
205     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
206     ASSERT(id);
207     ThreadIdentifierData::initialize(id);
208 }
209     
210 void changeThreadPriority(ThreadIdentifier threadID, int delta)
211 {
212     pthread_t pthreadHandle;
213     ASSERT(threadID);
214
215     {
216         MutexLocker locker(threadMapMutex());
217         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
218         ASSERT(pthreadHandle);
219     }
220
221     int policy;
222     struct sched_param param;
223
224     if (pthread_getschedparam(pthreadHandle, &policy, &param))
225         return;
226
227     param.sched_priority += delta;
228
229     pthread_setschedparam(pthreadHandle, policy, &param);
230 }
231
232 int waitForThreadCompletion(ThreadIdentifier threadID)
233 {
234     pthread_t pthreadHandle;
235     ASSERT(threadID);
236
237     {
238         // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
239         MutexLocker locker(threadMapMutex());
240         pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
241         ASSERT(pthreadHandle);
242     }
243
244     int joinResult = pthread_join(pthreadHandle, 0);
245
246     if (joinResult == EDEADLK)
247         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
248     else if (joinResult)
249         LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
250
251     MutexLocker locker(threadMapMutex());
252     PthreadState* state = threadMap().get(threadID);
253     ASSERT(state);
254     ASSERT(state->joinableState() == PthreadState::Joinable);
255
256     // The thread has already exited, so clean up after it.
257     if (state->hasExited())
258         threadMap().remove(threadID);
259     // 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.
260     else
261         state->didJoin();
262
263     return joinResult;
264 }
265
266 void detachThread(ThreadIdentifier threadID)
267 {
268     ASSERT(threadID);
269
270     MutexLocker locker(threadMapMutex());
271     pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
272     ASSERT(pthreadHandle);
273
274     int detachResult = pthread_detach(pthreadHandle);
275     if (detachResult)
276         LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
277
278     PthreadState* state = threadMap().get(threadID);
279     ASSERT(state);
280     if (state->hasExited())
281         threadMap().remove(threadID);
282     else
283         threadMap().get(threadID)->didBecomeDetached();
284 }
285
286 void threadDidExit(ThreadIdentifier threadID)
287 {
288     MutexLocker locker(threadMapMutex());
289     PthreadState* state = threadMap().get(threadID);
290     ASSERT(state);
291     
292     state->didExit();
293
294     if (state->joinableState() != PthreadState::Joinable)
295         threadMap().remove(threadID);
296 }
297
298 ThreadIdentifier currentThread()
299 {
300     ThreadIdentifier id = ThreadIdentifierData::identifier();
301     if (id)
302         return id;
303
304     // Not a WTF-created thread, ThreadIdentifier is not established yet.
305     id = establishIdentifierForPthreadHandle(pthread_self());
306     ThreadIdentifierData::initialize(id);
307     return id;
308 }
309
310 Mutex::Mutex()
311 {
312     pthread_mutexattr_t attr;
313     pthread_mutexattr_init(&attr);
314     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
315
316     int result = pthread_mutex_init(&m_mutex, &attr);
317     ASSERT_UNUSED(result, !result);
318
319     pthread_mutexattr_destroy(&attr);
320 }
321
322 Mutex::~Mutex()
323 {
324     int result = pthread_mutex_destroy(&m_mutex);
325     ASSERT_UNUSED(result, !result);
326 }
327
328 void Mutex::lock()
329 {
330     int result = pthread_mutex_lock(&m_mutex);
331     ASSERT_UNUSED(result, !result);
332 }
333
334 bool Mutex::tryLock()
335 {
336     int result = pthread_mutex_trylock(&m_mutex);
337
338     if (result == 0)
339         return true;
340     if (result == EBUSY)
341         return false;
342
343     ASSERT_NOT_REACHED();
344     return false;
345 }
346
347 void Mutex::unlock()
348 {
349     int result = pthread_mutex_unlock(&m_mutex);
350     ASSERT_UNUSED(result, !result);
351 }
352
353 ThreadCondition::ThreadCondition()
354
355     pthread_cond_init(&m_condition, NULL);
356 }
357
358 ThreadCondition::~ThreadCondition()
359 {
360     pthread_cond_destroy(&m_condition);
361 }
362     
363 void ThreadCondition::wait(Mutex& mutex)
364 {
365     int result = pthread_cond_wait(&m_condition, &mutex.impl());
366     ASSERT_UNUSED(result, !result);
367 }
368
369 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
370 {
371     if (absoluteTime < currentTime())
372         return false;
373
374     if (absoluteTime > INT_MAX) {
375         wait(mutex);
376         return true;
377     }
378
379     int timeSeconds = static_cast<int>(absoluteTime);
380     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
381
382     timespec targetTime;
383     targetTime.tv_sec = timeSeconds;
384     targetTime.tv_nsec = timeNanoseconds;
385
386     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
387 }
388
389 void ThreadCondition::signal()
390 {
391     int result = pthread_cond_signal(&m_condition);
392     ASSERT_UNUSED(result, !result);
393 }
394
395 void ThreadCondition::broadcast()
396 {
397     int result = pthread_cond_broadcast(&m_condition);
398     ASSERT_UNUSED(result, !result);
399 }
400
401 } // namespace WTF
402
403 #endif // USE(PTHREADS)