6f3d41d6a0457fab0c06e8ed1b9d95c38c505c20
[WebKit-https.git] / Source / WTF / wtf / ThreadingWin.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2009 Google Inc. All rights reserved.
4  * Copyright (C) 2009 Torch Mobile, Inc. 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 /*
32  * There are numerous academic and practical works on how to implement pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast
33  * functions on Win32. Here is one example: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html which is widely credited as a 'starting point'
34  * of modern attempts. There are several more or less proven implementations, one in Boost C++ library (http://www.boost.org) and another
35  * in pthreads-win32 (http://sourceware.org/pthreads-win32/).
36  *
37  * The number of articles and discussions is the evidence of significant difficulties in implementing these primitives correctly.
38  * The brief search of revisions, ChangeLog entries, discussions in comp.programming.threads and other places clearly documents
39  * numerous pitfalls and performance problems the authors had to overcome to arrive to the suitable implementations.
40  * Optimally, WebKit would use one of those supported/tested libraries directly. To roll out our own implementation is impractical,
41  * if even for the lack of sufficient testing. However, a faithful reproduction of the code from one of the popular supported
42  * libraries seems to be a good compromise.
43  *
44  * The early Boost implementation (http://www.boxbackup.org/trac/browser/box/nick/win/lib/win32/boost_1_32_0/libs/thread/src/condition.cpp?rev=30)
45  * is identical to pthreads-win32 (http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1.10&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32).
46  * Current Boost uses yet another (although seemingly equivalent) algorithm which came from their 'thread rewrite' effort.
47  *
48  * This file includes timedWait/signal/broadcast implementations translated to WebKit coding style from the latest algorithm by
49  * Alexander Terekhov and Louis Thomas, as captured here: http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1.10&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32
50  * It replaces the implementation of their previous algorithm, also documented in the same source above.
51  * The naming and comments are left very close to original to enable easy cross-check.
52  *
53  * The corresponding Pthreads-win32 License is included below, and CONTRIBUTORS file which it refers to is added to
54  * source directory (as CONTRIBUTORS.pthreads-win32).
55  */
56
57 /*
58  *      Pthreads-win32 - POSIX Threads Library for Win32
59  *      Copyright(C) 1998 John E. Bossom
60  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
61  *
62  *      Contact Email: rpj@callisto.canberra.edu.au
63  *
64  *      The current list of contributors is contained
65  *      in the file CONTRIBUTORS included with the source
66  *      code distribution. The list can also be seen at the
67  *      following World Wide Web location:
68  *      http://sources.redhat.com/pthreads-win32/contributors.html
69  *
70  *      This library is free software; you can redistribute it and/or
71  *      modify it under the terms of the GNU Lesser General Public
72  *      License as published by the Free Software Foundation; either
73  *      version 2 of the License, or (at your option) any later version.
74  *
75  *      This library is distributed in the hope that it will be useful,
76  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
77  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
78  *      Lesser General Public License for more details.
79  *
80  *      You should have received a copy of the GNU Lesser General Public
81  *      License along with this library in the file COPYING.LIB;
82  *      if not, write to the Free Software Foundation, Inc.,
83  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
84  */
85
86 #include "config.h"
87 #include "Threading.h"
88
89 #if OS(WINDOWS)
90
91 #include <errno.h>
92 #include <process.h>
93 #include <windows.h>
94 #include <wtf/HashMap.h>
95 #include <wtf/Lock.h>
96 #include <wtf/MainThread.h>
97 #include <wtf/MathExtras.h>
98 #include <wtf/NeverDestroyed.h>
99 #include <wtf/ThreadingPrimitives.h>
100
101 namespace WTF {
102
103 static Lock globalSuspendLock;
104
105 Thread::~Thread()
106 {
107     // It is OK because FLSAlloc's callback will be called even before there are some open handles.
108     // This easily ensures that all the thread resources are automatically closed.
109     if (m_handle != INVALID_HANDLE_VALUE)
110         CloseHandle(m_handle);
111 }
112
113 void Thread::initializeCurrentThreadEvenIfNonWTFCreated()
114 {
115 }
116
117 // MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
118 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
119
120 #pragma pack(push, 8)
121 typedef struct tagTHREADNAME_INFO {
122     DWORD dwType; // must be 0x1000
123     LPCSTR szName; // pointer to name (in user addr space)
124     DWORD dwThreadID; // thread ID (-1=caller thread)
125     DWORD dwFlags; // reserved for future use, must be zero
126 } THREADNAME_INFO;
127 #pragma pack(pop)
128
129 void Thread::initializeCurrentThreadInternal(const char* szThreadName)
130 {
131 #if COMPILER(MINGW)
132     // FIXME: Implement thread name setting with MingW.
133     UNUSED_PARAM(szThreadName);
134 #else
135     THREADNAME_INFO info;
136     info.dwType = 0x1000;
137     info.szName = Thread::normalizeThreadName(szThreadName);
138     info.dwThreadID = GetCurrentThreadId();
139     info.dwFlags = 0;
140
141     __try {
142         RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
143     } __except (EXCEPTION_CONTINUE_EXECUTION) {
144     }
145 #endif
146     initializeCurrentThreadEvenIfNonWTFCreated();
147 }
148
149 void Thread::initializePlatformThreading()
150 {
151 }
152
153 static unsigned __stdcall wtfThreadEntryPoint(void* data)
154 {
155     Thread::entryPoint(reinterpret_cast<Thread::NewThreadContext*>(data));
156     return 0;
157 }
158
159 bool Thread::establishHandle(NewThreadContext* data)
160 {
161     unsigned threadIdentifier = 0;
162     HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, data, 0, &threadIdentifier));
163     if (!threadHandle) {
164         LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", wtfThreadEntryPoint, data, errno);
165         return false;
166     }
167     establishPlatformSpecificHandle(threadHandle, threadIdentifier);
168     return true;
169 }
170
171 void Thread::changePriority(int delta)
172 {
173     std::lock_guard<std::mutex> locker(m_mutex);
174     SetThreadPriority(m_handle, THREAD_PRIORITY_NORMAL + delta);
175 }
176
177 int Thread::waitForCompletion()
178 {
179     HANDLE handle;
180     {
181         std::lock_guard<std::mutex> locker(m_mutex);
182         handle = m_handle;
183     }
184
185     DWORD joinResult = WaitForSingleObject(handle, INFINITE);
186     if (joinResult == WAIT_FAILED)
187         LOG_ERROR("Thread %p was found to be deadlocked trying to quit", this);
188
189     std::lock_guard<std::mutex> locker(m_mutex);
190     ASSERT(joinableState() == Joinable);
191
192     // The thread has already exited, do nothing.
193     // 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.
194     if (!hasExited())
195         didJoin();
196
197     return joinResult;
198 }
199
200 void Thread::detach()
201 {
202     // We follow the pthread semantics: even after the detach is called,
203     // we can still perform various operations onto the thread. For example,
204     // we can do pthread_kill for the detached thread. The problem in Windows
205     // is that closing HANDLE loses the way to do such operations.
206     // To do so, we do nothing here in Windows. Original detach's purpose,
207     // releasing thread resource when the thread exits, will be achieved by
208     // FlsCallback automatically. FlsCallback will call CloseHandle to clean up
209     // resource. So in this function, we just mark the thread as detached to
210     // avoid calling waitForCompletion for this thread.
211     std::lock_guard<std::mutex> locker(m_mutex);
212     if (!hasExited())
213         didBecomeDetached();
214 }
215
216 auto Thread::suspend() -> Expected<void, PlatformSuspendError>
217 {
218     RELEASE_ASSERT_WITH_MESSAGE(this != &Thread::current(), "We do not support suspending the current thread itself.");
219     LockHolder locker(globalSuspendLock);
220     DWORD result = SuspendThread(m_handle);
221     if (result != (DWORD)-1)
222         return { };
223     return makeUnexpected(result);
224 }
225
226 // During resume, suspend or resume should not be executed from the other threads.
227 void Thread::resume()
228 {
229     LockHolder locker(globalSuspendLock);
230     ResumeThread(m_handle);
231 }
232
233 size_t Thread::getRegisters(PlatformRegisters& registers)
234 {
235     LockHolder locker(globalSuspendLock);
236     registers.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
237     GetThreadContext(m_handle, &registers);
238     return sizeof(CONTEXT);
239 }
240
241 Thread& Thread::initializeCurrentTLS()
242 {
243     // Not a WTF-created thread, ThreadIdentifier is not established yet.
244     Ref<Thread> thread = adoptRef(*new Thread());
245
246     HANDLE handle;
247     bool isSuccessful = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
248     RELEASE_ASSERT(isSuccessful);
249
250     thread->establishPlatformSpecificHandle(handle, currentID());
251     thread->initializeInThread();
252     initializeCurrentThreadEvenIfNonWTFCreated();
253
254     return initializeTLS(WTFMove(thread));
255 }
256
257 ThreadIdentifier Thread::currentID()
258 {
259     return static_cast<ThreadIdentifier>(GetCurrentThreadId());
260 }
261
262 void Thread::establishPlatformSpecificHandle(HANDLE handle, ThreadIdentifier threadID)
263 {
264     std::lock_guard<std::mutex> locker(m_mutex);
265     m_handle = handle;
266     m_id = threadID;
267 }
268
269 #define InvalidThread reinterpret_cast<Thread*>(static_cast<uintptr_t>(0xbbadbeef))
270
271 static std::mutex& threadMapMutex()
272 {
273     static NeverDestroyed<std::mutex> mutex;
274     return mutex.get();
275 }
276
277 static HashMap<ThreadIdentifier, Thread*>& threadMap()
278 {
279     static NeverDestroyed<HashMap<ThreadIdentifier, Thread*>> map;
280     return map.get();
281 }
282
283 void Thread::initializeTLSKey()
284 {
285     threadMapMutex();
286     threadMap();
287     threadSpecificKeyCreate(&s_key, destructTLS);
288 }
289
290 Thread* Thread::currentDying()
291 {
292     ASSERT(s_key != InvalidThreadSpecificKey);
293     // After FLS is destroyed, this map offers the value until the second thread exit callback is called.
294     std::lock_guard<std::mutex> locker(threadMapMutex());
295     return threadMap().get(currentID());
296 }
297
298 // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
299 RefPtr<Thread> Thread::get(ThreadIdentifier id)
300 {
301     std::lock_guard<std::mutex> locker(threadMapMutex());
302     Thread* thread = threadMap().get(id);
303     if (thread)
304         return thread;
305     return nullptr;
306 }
307
308 Thread& Thread::initializeTLS(Ref<Thread>&& thread)
309 {
310     ASSERT(s_key != InvalidThreadSpecificKey);
311     // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
312     auto id = thread->id();
313     // We leak the ref to keep the Thread alive while it is held in TLS. destructTLS will deref it later at thread destruction time.
314     auto& threadInTLS = thread.leakRef();
315     threadSpecificSet(s_key, &threadInTLS);
316     {
317         std::lock_guard<std::mutex> locker(threadMapMutex());
318         threadMap().add(id, &threadInTLS);
319     }
320     return threadInTLS;
321 }
322
323 void Thread::destructTLS(void* data)
324 {
325     if (data == InvalidThread)
326         return;
327
328     Thread* thread = static_cast<Thread*>(data);
329     ASSERT(thread);
330
331     // Delay the deallocation of Thread more.
332     // It defers Thread deallocation after the other ThreadSpecific values are deallocated.
333     static thread_local class ThreadExitCallback {
334     public:
335         ThreadExitCallback(Thread* thread)
336             : m_thread(thread)
337         {
338         }
339
340         ~ThreadExitCallback()
341         {
342             Thread::destructTLS(m_thread);
343         }
344
345     private:
346         Thread* m_thread;
347     } callback(thread);
348
349     if (thread->m_isDestroyedOnce) {
350         {
351             std::lock_guard<std::mutex> locker(threadMapMutex());
352             ASSERT(threadMap().contains(thread->id()));
353             threadMap().remove(thread->id());
354         }
355         thread->didExit();
356         thread->deref();
357
358         // Fill the FLS with the non-nullptr value. While FLS destructor won't be called for that,
359         // non-nullptr value tells us that we already destructed Thread. This allows us to
360         // detect incorrect use of Thread::current() after this point because it will crash.
361         threadSpecificSet(s_key, InvalidThread);
362         return;
363     }
364     threadSpecificSet(s_key, InvalidThread);
365     thread->m_isDestroyedOnce = true;
366 }
367
368 Mutex::Mutex()
369 {
370     InitializeSRWLock(&m_mutex);
371 }
372
373 Mutex::~Mutex()
374 {
375 }
376
377 void Mutex::lock()
378 {
379     AcquireSRWLockExclusive(&m_mutex);
380 }
381
382 bool Mutex::tryLock()
383 {
384     return TryAcquireSRWLockExclusive(&m_mutex);
385 }
386
387 void Mutex::unlock()
388 {
389     ReleaseSRWLockExclusive(&m_mutex);
390 }
391
392 // Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject).
393 static DWORD absoluteTimeToWaitTimeoutInterval(WallTime absoluteTime)
394 {
395     WallTime currentTime = WallTime::now();
396
397     // Time is in the past - return immediately.
398     if (absoluteTime < currentTime)
399         return 0;
400
401     // Time is too far in the future (and would overflow unsigned long) - wait forever.
402     if ((absoluteTime - currentTime) > Seconds::fromMilliseconds(INT_MAX))
403         return INFINITE;
404
405     return static_cast<DWORD>((absoluteTime - currentTime).milliseconds());
406 }
407
408 ThreadCondition::ThreadCondition()
409 {
410     InitializeConditionVariable(&m_condition);
411 }
412
413 ThreadCondition::~ThreadCondition()
414 {
415 }
416
417 void ThreadCondition::wait(Mutex& mutex)
418 {
419     SleepConditionVariableSRW(&m_condition, &mutex.impl(), INFINITE, 0);
420 }
421
422 bool ThreadCondition::timedWait(Mutex& mutex, WallTime absoluteTime)
423 {
424     // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686304(v=vs.85).aspx
425     DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
426     if (!interval) {
427         // Consider the wait to have timed out, even if our condition has already been signaled, to
428         // match the pthreads implementation.
429         return false;
430     }
431
432     if (SleepConditionVariableSRW(&m_condition, &mutex.impl(), interval, 0))
433         return true;
434     ASSERT(GetLastError() == ERROR_TIMEOUT);
435     return false;
436 }
437
438 void ThreadCondition::signal()
439 {
440     WakeConditionVariable(&m_condition);
441 }
442
443 void ThreadCondition::broadcast()
444 {
445     WakeAllConditionVariable(&m_condition);
446 }
447
448 // Remove this workaround code when <rdar://problem/31793213> is fixed.
449 ThreadIdentifier createThread(ThreadFunction function, void* data, const char* threadName)
450 {
451     return Thread::create(threadName, [function, data] {
452         function(data);
453     })->id();
454 }
455
456 int waitForThreadCompletion(ThreadIdentifier threadID)
457 {
458     // This function is implemented based on the old Threading implementation.
459     // It remains only due to the support library using old Threading APIs and
460     // it should not be used in new code.
461     ASSERT(threadID);
462
463     RefPtr<Thread> thread = Thread::get(threadID);
464     if (!thread) {
465         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
466         return WAIT_FAILED;
467     }
468     return thread->waitForCompletion();
469
470 }
471
472 void Thread::yield()
473 {
474     SwitchToThread();
475 }
476
477 } // namespace WTF
478
479 #endif // OS(WINDOWS)