Use WordLock instead of std::mutex for Threading
[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     auto locker = holdLock(m_mutex);
174     SetThreadPriority(m_handle, THREAD_PRIORITY_NORMAL + delta);
175 }
176
177 int Thread::waitForCompletion()
178 {
179     HANDLE handle;
180     {
181         auto locker = holdLock(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     auto locker = holdLock(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     auto locker = holdLock(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     auto locker = holdLock(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 WordLock threadMapMutex;
272
273 static HashMap<ThreadIdentifier, Thread*>& threadMap()
274 {
275     static NeverDestroyed<HashMap<ThreadIdentifier, Thread*>> map;
276     return map.get();
277 }
278
279 void Thread::initializeTLSKey()
280 {
281     threadMap();
282     threadSpecificKeyCreate(&s_key, destructTLS);
283 }
284
285 Thread* Thread::currentDying()
286 {
287     ASSERT(s_key != InvalidThreadSpecificKey);
288     // After FLS is destroyed, this map offers the value until the second thread exit callback is called.
289     auto locker = holdLock(threadMapMutex);
290     return threadMap().get(currentID());
291 }
292
293 // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
294 RefPtr<Thread> Thread::get(ThreadIdentifier id)
295 {
296     auto locker = holdLock(threadMapMutex);
297     Thread* thread = threadMap().get(id);
298     if (thread)
299         return thread;
300     return nullptr;
301 }
302
303 Thread& Thread::initializeTLS(Ref<Thread>&& thread)
304 {
305     ASSERT(s_key != InvalidThreadSpecificKey);
306     // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
307     auto id = thread->id();
308     // We leak the ref to keep the Thread alive while it is held in TLS. destructTLS will deref it later at thread destruction time.
309     auto& threadInTLS = thread.leakRef();
310     threadSpecificSet(s_key, &threadInTLS);
311     {
312         auto locker = holdLock(threadMapMutex);
313         threadMap().add(id, &threadInTLS);
314     }
315     return threadInTLS;
316 }
317
318 void Thread::destructTLS(void* data)
319 {
320     if (data == InvalidThread)
321         return;
322
323     Thread* thread = static_cast<Thread*>(data);
324     ASSERT(thread);
325
326     // Delay the deallocation of Thread more.
327     // It defers Thread deallocation after the other ThreadSpecific values are deallocated.
328     static thread_local class ThreadExitCallback {
329     public:
330         ThreadExitCallback(Thread* thread)
331             : m_thread(thread)
332         {
333         }
334
335         ~ThreadExitCallback()
336         {
337             Thread::destructTLS(m_thread);
338         }
339
340     private:
341         Thread* m_thread;
342     } callback(thread);
343
344     if (thread->m_isDestroyedOnce) {
345         {
346             auto locker = holdLock(threadMapMutex);
347             ASSERT(threadMap().contains(thread->id()));
348             threadMap().remove(thread->id());
349         }
350         thread->didExit();
351         thread->deref();
352
353         // Fill the FLS with the non-nullptr value. While FLS destructor won't be called for that,
354         // non-nullptr value tells us that we already destructed Thread. This allows us to
355         // detect incorrect use of Thread::current() after this point because it will crash.
356         threadSpecificSet(s_key, InvalidThread);
357         return;
358     }
359     threadSpecificSet(s_key, InvalidThread);
360     thread->m_isDestroyedOnce = true;
361 }
362
363 Mutex::Mutex()
364 {
365     InitializeSRWLock(&m_mutex);
366 }
367
368 Mutex::~Mutex()
369 {
370 }
371
372 void Mutex::lock()
373 {
374     AcquireSRWLockExclusive(&m_mutex);
375 }
376
377 bool Mutex::tryLock()
378 {
379     return TryAcquireSRWLockExclusive(&m_mutex);
380 }
381
382 void Mutex::unlock()
383 {
384     ReleaseSRWLockExclusive(&m_mutex);
385 }
386
387 // Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject).
388 static DWORD absoluteTimeToWaitTimeoutInterval(WallTime absoluteTime)
389 {
390     WallTime currentTime = WallTime::now();
391
392     // Time is in the past - return immediately.
393     if (absoluteTime < currentTime)
394         return 0;
395
396     // Time is too far in the future (and would overflow unsigned long) - wait forever.
397     if ((absoluteTime - currentTime) > Seconds::fromMilliseconds(INT_MAX))
398         return INFINITE;
399
400     return static_cast<DWORD>((absoluteTime - currentTime).milliseconds());
401 }
402
403 ThreadCondition::ThreadCondition()
404 {
405     InitializeConditionVariable(&m_condition);
406 }
407
408 ThreadCondition::~ThreadCondition()
409 {
410 }
411
412 void ThreadCondition::wait(Mutex& mutex)
413 {
414     SleepConditionVariableSRW(&m_condition, &mutex.impl(), INFINITE, 0);
415 }
416
417 bool ThreadCondition::timedWait(Mutex& mutex, WallTime absoluteTime)
418 {
419     // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686304(v=vs.85).aspx
420     DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
421     if (!interval) {
422         // Consider the wait to have timed out, even if our condition has already been signaled, to
423         // match the pthreads implementation.
424         return false;
425     }
426
427     if (SleepConditionVariableSRW(&m_condition, &mutex.impl(), interval, 0))
428         return true;
429     ASSERT(GetLastError() == ERROR_TIMEOUT);
430     return false;
431 }
432
433 void ThreadCondition::signal()
434 {
435     WakeConditionVariable(&m_condition);
436 }
437
438 void ThreadCondition::broadcast()
439 {
440     WakeAllConditionVariable(&m_condition);
441 }
442
443 // Remove this workaround code when <rdar://problem/31793213> is fixed.
444 ThreadIdentifier createThread(ThreadFunction function, void* data, const char* threadName)
445 {
446     return Thread::create(threadName, [function, data] {
447         function(data);
448     })->id();
449 }
450
451 int waitForThreadCompletion(ThreadIdentifier threadID)
452 {
453     // This function is implemented based on the old Threading implementation.
454     // It remains only due to the support library using old Threading APIs and
455     // it should not be used in new code.
456     ASSERT(threadID);
457
458     RefPtr<Thread> thread = Thread::get(threadID);
459     if (!thread) {
460         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
461         return WAIT_FAILED;
462     }
463     return thread->waitForCompletion();
464
465 }
466
467 void Thread::yield()
468 {
469     SwitchToThread();
470 }
471
472 } // namespace WTF
473
474 #endif // OS(WINDOWS)