e931dffb8f4dbd07e8a6245d273b683834b38184
[WebKit.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/CurrentTime.h>
95 #include <wtf/Lock.h>
96 #include <wtf/MainThread.h>
97 #include <wtf/MathExtras.h>
98 #include <wtf/NeverDestroyed.h>
99 #include <wtf/ThreadHolder.h>
100 #include <wtf/ThreadingPrimitives.h>
101
102 namespace WTF {
103
104 static StaticLock globalSuspendLock;
105
106 Thread::Thread()
107 {
108 }
109
110 Thread::~Thread()
111 {
112     // It is OK because FLSAlloc's callback will be called even before there are some open handles.
113     // This easily ensures that all the thread resources are automatically closed.
114     if (m_handle != INVALID_HANDLE_VALUE)
115         CloseHandle(m_handle);
116 }
117
118 void Thread::initializeCurrentThreadEvenIfNonWTFCreated()
119 {
120 }
121
122 // MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
123 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
124
125 #pragma pack(push, 8)
126 typedef struct tagTHREADNAME_INFO {
127     DWORD dwType; // must be 0x1000
128     LPCSTR szName; // pointer to name (in user addr space)
129     DWORD dwThreadID; // thread ID (-1=caller thread)
130     DWORD dwFlags; // reserved for future use, must be zero
131 } THREADNAME_INFO;
132 #pragma pack(pop)
133
134 void Thread::initializeCurrentThreadInternal(const char* szThreadName)
135 {
136 #if COMPILER(MINGW)
137     // FIXME: Implement thread name setting with MingW.
138     UNUSED_PARAM(szThreadName);
139 #else
140     THREADNAME_INFO info;
141     info.dwType = 0x1000;
142     info.szName = Thread::normalizeThreadName(szThreadName);
143     info.dwThreadID = GetCurrentThreadId();
144     info.dwFlags = 0;
145
146     __try {
147         RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
148     } __except (EXCEPTION_CONTINUE_EXECUTION) {
149     }
150 #endif
151     initializeCurrentThreadEvenIfNonWTFCreated();
152 }
153
154 void Thread::initializePlatformThreading()
155 {
156 }
157
158 static unsigned __stdcall wtfThreadEntryPoint(void* data)
159 {
160     Thread::entryPoint(reinterpret_cast<Thread::NewThreadContext*>(data));
161     return 0;
162 }
163
164 bool Thread::establishHandle(NewThreadContext* data)
165 {
166     unsigned threadIdentifier = 0;
167     HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, data, 0, &threadIdentifier));
168     if (!threadHandle) {
169         LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", wtfThreadEntryPoint, data, errno);
170         return false;
171     }
172     establishPlatformSpecificHandle(threadHandle, threadIdentifier);
173     return true;
174 }
175
176 void Thread::changePriority(int delta)
177 {
178     std::lock_guard<std::mutex> locker(m_mutex);
179     SetThreadPriority(m_handle, THREAD_PRIORITY_NORMAL + delta);
180 }
181
182 int Thread::waitForCompletion()
183 {
184     HANDLE handle;
185     {
186         std::lock_guard<std::mutex> locker(m_mutex);
187         handle = m_handle;
188     }
189
190     DWORD joinResult = WaitForSingleObject(handle, INFINITE);
191     if (joinResult == WAIT_FAILED)
192         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", m_id);
193
194     std::lock_guard<std::mutex> locker(m_mutex);
195     ASSERT(joinableState() == Joinable);
196
197     // The thread has already exited, do nothing.
198     // 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.
199     if (!hasExited())
200         didJoin();
201
202     return joinResult;
203 }
204
205 void Thread::detach()
206 {
207     // We follow the pthread semantics: even after the detach is called,
208     // we can still perform various operations onto the thread. For example,
209     // we can do pthread_kill for the detached thread. The problem in Windows
210     // is that closing HANDLE loses the way to do such operations.
211     // To do so, we do nothing here in Windows. Original detach's purpose,
212     // releasing thread resource when the thread exits, will be achieved by
213     // FlsCallback automatically. FlsCallback will call CloseHandle to clean up
214     // resource. So in this function, we just mark the thread as detached to
215     // avoid calling waitForCompletion for this thread.
216     std::lock_guard<std::mutex> locker(m_mutex);
217     if (!hasExited())
218         didBecomeDetached();
219 }
220
221 auto Thread::suspend() -> Expected<void, PlatformSuspendError>
222 {
223     RELEASE_ASSERT_WITH_MESSAGE(id() != currentThread(), "We do not support suspending the current thread itself.");
224     LockHolder locker(globalSuspendLock);
225     DWORD result = SuspendThread(m_handle);
226     if (result != (DWORD)-1)
227         return { };
228     return makeUnexpected(result);
229 }
230
231 // During resume, suspend or resume should not be executed from the other threads.
232 void Thread::resume()
233 {
234     LockHolder locker(globalSuspendLock);
235     ResumeThread(m_handle);
236 }
237
238 size_t Thread::getRegisters(PlatformRegisters& registers)
239 {
240     LockHolder locker(globalSuspendLock);
241     registers.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
242     GetThreadContext(m_handle, &registers);
243     return sizeof(CONTEXT);
244 }
245
246 Ref<Thread> Thread::createCurrentThread()
247 {
248     // Not a WTF-created thread, ThreadIdentifier is not established yet.
249     Ref<Thread> thread = adoptRef(*new Thread());
250
251     HANDLE handle;
252     bool isSuccessful = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
253     RELEASE_ASSERT(isSuccessful);
254
255     thread->establishPlatformSpecificHandle(handle, currentID());
256     thread->m_stack = StackBounds::currentThreadStackBounds();
257     thread->initializeInThread();
258     initializeCurrentThreadEvenIfNonWTFCreated();
259     return thread;
260 }
261
262 ThreadIdentifier Thread::currentID()
263 {
264     return static_cast<ThreadIdentifier>(GetCurrentThreadId());
265 }
266
267 void Thread::establishPlatformSpecificHandle(HANDLE handle, ThreadIdentifier threadID)
268 {
269     std::lock_guard<std::mutex> locker(m_mutex);
270     m_handle = handle;
271     m_id = threadID;
272 }
273
274 Mutex::Mutex()
275 {
276     m_mutex.m_recursionCount = 0;
277     InitializeCriticalSection(&m_mutex.m_internalMutex);
278 }
279
280 Mutex::~Mutex()
281 {
282     DeleteCriticalSection(&m_mutex.m_internalMutex);
283 }
284
285 void Mutex::lock()
286 {
287     EnterCriticalSection(&m_mutex.m_internalMutex);
288     ++m_mutex.m_recursionCount;
289 }
290     
291 #pragma warning(suppress: 26115)
292 bool Mutex::tryLock()
293 {
294     // This method is modeled after the behavior of pthread_mutex_trylock,
295     // which will return an error if the lock is already owned by the
296     // current thread.  Since the primitive Win32 'TryEnterCriticalSection'
297     // treats this as a successful case, it changes the behavior of several
298     // tests in WebKit that check to see if the current thread already
299     // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
300     DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
301     
302     if (result != 0) {       // We got the lock
303         // If this thread already had the lock, we must unlock and
304         // return false so that we mimic the behavior of POSIX's
305         // pthread_mutex_trylock:
306         if (m_mutex.m_recursionCount > 0) {
307             LeaveCriticalSection(&m_mutex.m_internalMutex);
308             return false;
309         }
310
311         ++m_mutex.m_recursionCount;
312         return true;
313     }
314
315     return false;
316 }
317
318 void Mutex::unlock()
319 {
320     ASSERT(m_mutex.m_recursionCount);
321     --m_mutex.m_recursionCount;
322     LeaveCriticalSection(&m_mutex.m_internalMutex);
323 }
324
325 bool PlatformCondition::timedWait(PlatformMutex& mutex, DWORD durationMilliseconds)
326 {
327     // Enter the wait state.
328     DWORD res = WaitForSingleObject(m_blockLock, INFINITE);
329     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
330     ++m_waitersBlocked;
331     res = ReleaseSemaphore(m_blockLock, 1, 0);
332     ASSERT_UNUSED(res, res);
333
334     --mutex.m_recursionCount;
335     LeaveCriticalSection(&mutex.m_internalMutex);
336
337     // Main wait - use timeout.
338     bool timedOut = (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT);
339
340     res = WaitForSingleObject(m_unblockLock, INFINITE);
341     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
342
343     int signalsLeft = m_waitersToUnblock;
344
345     if (m_waitersToUnblock)
346         --m_waitersToUnblock;
347     else if (++m_waitersGone == (INT_MAX / 2)) { // timeout/canceled or spurious semaphore
348         // timeout or spurious wakeup occured, normalize the m_waitersGone count
349         // this may occur if many calls to wait with a timeout are made and
350         // no call to notify_* is made
351         res = WaitForSingleObject(m_blockLock, INFINITE);
352         ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
353         m_waitersBlocked -= m_waitersGone;
354         res = ReleaseSemaphore(m_blockLock, 1, 0);
355         ASSERT_UNUSED(res, res);
356         m_waitersGone = 0;
357     }
358
359     res = ReleaseMutex(m_unblockLock);
360     ASSERT_UNUSED(res, res);
361
362     if (signalsLeft == 1) {
363         res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate.
364         ASSERT_UNUSED(res, res);
365     }
366
367     EnterCriticalSection (&mutex.m_internalMutex);
368     ++mutex.m_recursionCount;
369
370     return !timedOut;
371 }
372
373 void PlatformCondition::signal(bool unblockAll)
374 {
375     unsigned signalsToIssue = 0;
376
377     DWORD res = WaitForSingleObject(m_unblockLock, INFINITE);
378     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
379
380     if (m_waitersToUnblock) { // the gate is already closed
381         if (!m_waitersBlocked) { // no-op
382             res = ReleaseMutex(m_unblockLock);
383             ASSERT_UNUSED(res, res);
384             return;
385         }
386
387         if (unblockAll) {
388             signalsToIssue = m_waitersBlocked;
389             m_waitersToUnblock += m_waitersBlocked;
390             m_waitersBlocked = 0;
391         } else {
392             signalsToIssue = 1;
393             ++m_waitersToUnblock;
394             --m_waitersBlocked;
395         }
396     } else if (m_waitersBlocked > m_waitersGone) {
397         res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate.
398         ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
399         if (m_waitersGone != 0) {
400             m_waitersBlocked -= m_waitersGone;
401             m_waitersGone = 0;
402         }
403         if (unblockAll) {
404             signalsToIssue = m_waitersBlocked;
405             m_waitersToUnblock = m_waitersBlocked;
406             m_waitersBlocked = 0;
407         } else {
408             signalsToIssue = 1;
409             m_waitersToUnblock = 1;
410             --m_waitersBlocked;
411         }
412     } else { // No-op.
413         res = ReleaseMutex(m_unblockLock);
414         ASSERT_UNUSED(res, res);
415         return;
416     }
417
418     res = ReleaseMutex(m_unblockLock);
419     ASSERT_UNUSED(res, res);
420
421     if (signalsToIssue) {
422         res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0);
423         ASSERT_UNUSED(res, res);
424     }
425 }
426
427 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
428
429 ThreadCondition::ThreadCondition()
430 {
431     m_condition.m_waitersGone = 0;
432     m_condition.m_waitersBlocked = 0;
433     m_condition.m_waitersToUnblock = 0;
434     m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0);
435     m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
436     m_condition.m_unblockLock = CreateMutex(0, 0, 0);
437
438     if (!m_condition.m_blockLock || !m_condition.m_blockQueue || !m_condition.m_unblockLock) {
439         if (m_condition.m_blockLock)
440             CloseHandle(m_condition.m_blockLock);
441         if (m_condition.m_blockQueue)
442             CloseHandle(m_condition.m_blockQueue);
443         if (m_condition.m_unblockLock)
444             CloseHandle(m_condition.m_unblockLock);
445     }
446 }
447
448 ThreadCondition::~ThreadCondition()
449 {
450     CloseHandle(m_condition.m_blockLock);
451     CloseHandle(m_condition.m_blockQueue);
452     CloseHandle(m_condition.m_unblockLock);
453 }
454
455 void ThreadCondition::wait(Mutex& mutex)
456 {
457     m_condition.timedWait(mutex.impl(), INFINITE);
458 }
459
460 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
461 {
462     DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
463
464     if (!interval) {
465         // Consider the wait to have timed out, even if our condition has already been signaled, to
466         // match the pthreads implementation.
467         return false;
468     }
469
470     return m_condition.timedWait(mutex.impl(), interval);
471 }
472
473 void ThreadCondition::signal()
474 {
475     m_condition.signal(false); // Unblock only 1 thread.
476 }
477
478 void ThreadCondition::broadcast()
479 {
480     m_condition.signal(true); // Unblock all threads.
481 }
482
483 DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime)
484 {
485     double currentTime = WTF::currentTime();
486
487     // Time is in the past - return immediately.
488     if (absoluteTime < currentTime)
489         return 0;
490
491     // Time is too far in the future (and would overflow unsigned long) - wait forever.
492     if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0)
493         return INFINITE;
494
495     return static_cast<DWORD>((absoluteTime - currentTime) * 1000.0);
496 }
497
498 // Remove this workaround code when <rdar://problem/31793213> is fixed.
499 ThreadIdentifier createThread(ThreadFunction function, void* data, const char* threadName)
500 {
501     return Thread::create(threadName, [function, data] {
502         function(data);
503     })->id();
504 }
505
506 int waitForThreadCompletion(ThreadIdentifier threadID)
507 {
508     // This function is implemented based on the old Threading implementation.
509     // It remains only due to the support library using old Threading APIs and
510     // it should not be used in new code.
511     ASSERT(threadID);
512
513     RefPtr<Thread> thread = ThreadHolder::get(threadID);
514     if (!thread) {
515         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
516         return WAIT_FAILED;
517     }
518     return thread->waitForCompletion();
519
520 }
521
522 void Thread::yield()
523 {
524     SwitchToThread();
525 }
526
527 } // namespace WTF
528
529 #endif // OS(WINDOWS)