Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2007, 2008 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 Computer, 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 (at) 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 "DateMath.h"
     92 #include "dtoa.h"
     93 #include "dtoa/cached-powers.h"
     94 
     95 #include "MainThread.h"
     96 #include "ThreadFunctionInvocation.h"
     97 #include "ThreadSpecific.h"
     98 #include <windows.h>
     99 #include "wtf/CurrentTime.h"
    100 #include "wtf/HashMap.h"
    101 #include "wtf/MathExtras.h"
    102 #include "wtf/OwnPtr.h"
    103 #include "wtf/PassOwnPtr.h"
    104 #include "wtf/RandomNumberSeed.h"
    105 #include "wtf/WTFThreadData.h"
    106 
    107 #include <errno.h>
    108 #include <process.h>
    109 
    110 namespace WTF {
    111 
    112 // MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
    113 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
    114 
    115 #pragma pack(push, 8)
    116 typedef struct tagTHREADNAME_INFO {
    117     DWORD dwType; // must be 0x1000
    118     LPCSTR szName; // pointer to name (in user addr space)
    119     DWORD dwThreadID; // thread ID (-1=caller thread)
    120     DWORD dwFlags; // reserved for future use, must be zero
    121 } THREADNAME_INFO;
    122 #pragma pack(pop)
    123 
    124 void initializeCurrentThreadInternal(const char* szThreadName)
    125 {
    126     THREADNAME_INFO info;
    127     info.dwType = 0x1000;
    128     info.szName = szThreadName;
    129     info.dwThreadID = GetCurrentThreadId();
    130     info.dwFlags = 0;
    131 
    132     __try {
    133         RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
    134     } __except (EXCEPTION_CONTINUE_EXECUTION) {
    135     }
    136 }
    137 
    138 static Mutex* atomicallyInitializedStaticMutex;
    139 
    140 void lockAtomicallyInitializedStaticMutex()
    141 {
    142     ASSERT(atomicallyInitializedStaticMutex);
    143     atomicallyInitializedStaticMutex->lock();
    144 }
    145 
    146 void unlockAtomicallyInitializedStaticMutex()
    147 {
    148     atomicallyInitializedStaticMutex->unlock();
    149 }
    150 
    151 static Mutex& threadMapMutex()
    152 {
    153     static Mutex mutex;
    154     return mutex;
    155 }
    156 
    157 void initializeThreading()
    158 {
    159     // This should only be called once.
    160     ASSERT(!atomicallyInitializedStaticMutex);
    161 
    162     WTF::double_conversion::initialize();
    163     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
    164     // so ensure it has been initialized from here.
    165     StringImpl::empty();
    166     atomicallyInitializedStaticMutex = new Mutex;
    167     threadMapMutex();
    168     initializeRandomNumberGenerator();
    169     wtfThreadData();
    170     s_dtoaP5Mutex = new Mutex;
    171     initializeDates();
    172 }
    173 
    174 static HashMap<DWORD, HANDLE>& threadMap()
    175 {
    176     static HashMap<DWORD, HANDLE> map;
    177     return map;
    178 }
    179 
    180 static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
    181 {
    182     MutexLocker locker(threadMapMutex());
    183     ASSERT(!threadMap().contains(threadID));
    184     threadMap().add(threadID, threadHandle);
    185 }
    186 
    187 static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
    188 {
    189     MutexLocker locker(threadMapMutex());
    190     return threadMap().get(id);
    191 }
    192 
    193 static void clearThreadHandleForIdentifier(ThreadIdentifier id)
    194 {
    195     MutexLocker locker(threadMapMutex());
    196     ASSERT(threadMap().contains(id));
    197     threadMap().remove(id);
    198 }
    199 
    200 static unsigned __stdcall wtfThreadEntryPoint(void* param)
    201 {
    202     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
    203     invocation->function(invocation->data);
    204 
    205     // Do the TLS cleanup.
    206     ThreadSpecificThreadExit();
    207 
    208     return 0;
    209 }
    210 
    211 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
    212 {
    213     unsigned threadIdentifier = 0;
    214     ThreadIdentifier threadID = 0;
    215     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
    216     HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation.get(), 0, &threadIdentifier));
    217     if (!threadHandle) {
    218         LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
    219         return 0;
    220     }
    221 
    222     // The thread will take ownership of invocation.
    223     ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
    224     UNUSED_PARAM(leakedInvocation);
    225 
    226     threadID = static_cast<ThreadIdentifier>(threadIdentifier);
    227     storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
    228 
    229     return threadID;
    230 }
    231 
    232 int waitForThreadCompletion(ThreadIdentifier threadID)
    233 {
    234     ASSERT(threadID);
    235 
    236     HANDLE threadHandle = threadHandleForIdentifier(threadID);
    237     if (!threadHandle)
    238         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
    239 
    240     DWORD joinResult = WaitForSingleObject(threadHandle, INFINITE);
    241     if (joinResult == WAIT_FAILED)
    242         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
    243 
    244     CloseHandle(threadHandle);
    245     clearThreadHandleForIdentifier(threadID);
    246 
    247     return joinResult;
    248 }
    249 
    250 void detachThread(ThreadIdentifier threadID)
    251 {
    252     ASSERT(threadID);
    253 
    254     HANDLE threadHandle = threadHandleForIdentifier(threadID);
    255     if (threadHandle)
    256         CloseHandle(threadHandle);
    257     clearThreadHandleForIdentifier(threadID);
    258 }
    259 
    260 void yield()
    261 {
    262     ::Sleep(1);
    263 }
    264 
    265 ThreadIdentifier currentThread()
    266 {
    267     return static_cast<ThreadIdentifier>(GetCurrentThreadId());
    268 }
    269 
    270 Mutex::Mutex()
    271 {
    272     m_mutex.m_recursionCount = 0;
    273     InitializeCriticalSection(&m_mutex.m_internalMutex);
    274 }
    275 
    276 Mutex::~Mutex()
    277 {
    278     DeleteCriticalSection(&m_mutex.m_internalMutex);
    279 }
    280 
    281 void Mutex::lock()
    282 {
    283     EnterCriticalSection(&m_mutex.m_internalMutex);
    284     ++m_mutex.m_recursionCount;
    285 }
    286 
    287 bool Mutex::tryLock()
    288 {
    289     // This method is modeled after the behavior of pthread_mutex_trylock,
    290     // which will return an error if the lock is already owned by the
    291     // current thread.  Since the primitive Win32 'TryEnterCriticalSection'
    292     // treats this as a successful case, it changes the behavior of several
    293     // tests in WebKit that check to see if the current thread already
    294     // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
    295     DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
    296 
    297     if (result != 0) {       // We got the lock
    298         // If this thread already had the lock, we must unlock and
    299         // return false so that we mimic the behavior of POSIX's
    300         // pthread_mutex_trylock:
    301         if (m_mutex.m_recursionCount > 0) {
    302             LeaveCriticalSection(&m_mutex.m_internalMutex);
    303             return false;
    304         }
    305 
    306         ++m_mutex.m_recursionCount;
    307         return true;
    308     }
    309 
    310     return false;
    311 }
    312 
    313 void Mutex::unlock()
    314 {
    315     ASSERT(m_mutex.m_recursionCount);
    316     --m_mutex.m_recursionCount;
    317     LeaveCriticalSection(&m_mutex.m_internalMutex);
    318 }
    319 
    320 bool PlatformCondition::timedWait(PlatformMutex& mutex, DWORD durationMilliseconds)
    321 {
    322     // Enter the wait state.
    323     DWORD res = WaitForSingleObject(m_blockLock, INFINITE);
    324     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
    325     ++m_waitersBlocked;
    326     res = ReleaseSemaphore(m_blockLock, 1, 0);
    327     ASSERT_UNUSED(res, res);
    328 
    329     --mutex.m_recursionCount;
    330     LeaveCriticalSection(&mutex.m_internalMutex);
    331 
    332     // Main wait - use timeout.
    333     bool timedOut = (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT);
    334 
    335     res = WaitForSingleObject(m_unblockLock, INFINITE);
    336     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
    337 
    338     int signalsLeft = m_waitersToUnblock;
    339 
    340     if (m_waitersToUnblock)
    341         --m_waitersToUnblock;
    342     else if (++m_waitersGone == (INT_MAX / 2)) { // timeout/canceled or spurious semaphore
    343         // timeout or spurious wakeup occured, normalize the m_waitersGone count
    344         // this may occur if many calls to wait with a timeout are made and
    345         // no call to notify_* is made
    346         res = WaitForSingleObject(m_blockLock, INFINITE);
    347         ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
    348         m_waitersBlocked -= m_waitersGone;
    349         res = ReleaseSemaphore(m_blockLock, 1, 0);
    350         ASSERT_UNUSED(res, res);
    351         m_waitersGone = 0;
    352     }
    353 
    354     res = ReleaseMutex(m_unblockLock);
    355     ASSERT_UNUSED(res, res);
    356 
    357     if (signalsLeft == 1) {
    358         res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate.
    359         ASSERT_UNUSED(res, res);
    360     }
    361 
    362     EnterCriticalSection (&mutex.m_internalMutex);
    363     ++mutex.m_recursionCount;
    364 
    365     return !timedOut;
    366 }
    367 
    368 void PlatformCondition::signal(bool unblockAll)
    369 {
    370     unsigned signalsToIssue = 0;
    371 
    372     DWORD res = WaitForSingleObject(m_unblockLock, INFINITE);
    373     ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
    374 
    375     if (m_waitersToUnblock) { // the gate is already closed
    376         if (!m_waitersBlocked) { // no-op
    377             res = ReleaseMutex(m_unblockLock);
    378             ASSERT_UNUSED(res, res);
    379             return;
    380         }
    381 
    382         if (unblockAll) {
    383             signalsToIssue = m_waitersBlocked;
    384             m_waitersToUnblock += m_waitersBlocked;
    385             m_waitersBlocked = 0;
    386         } else {
    387             signalsToIssue = 1;
    388             ++m_waitersToUnblock;
    389             --m_waitersBlocked;
    390         }
    391     } else if (m_waitersBlocked > m_waitersGone) {
    392         res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate.
    393         ASSERT_UNUSED(res, res == WAIT_OBJECT_0);
    394         if (m_waitersGone != 0) {
    395             m_waitersBlocked -= m_waitersGone;
    396             m_waitersGone = 0;
    397         }
    398         if (unblockAll) {
    399             signalsToIssue = m_waitersBlocked;
    400             m_waitersToUnblock = m_waitersBlocked;
    401             m_waitersBlocked = 0;
    402         } else {
    403             signalsToIssue = 1;
    404             m_waitersToUnblock = 1;
    405             --m_waitersBlocked;
    406         }
    407     } else { // No-op.
    408         res = ReleaseMutex(m_unblockLock);
    409         ASSERT_UNUSED(res, res);
    410         return;
    411     }
    412 
    413     res = ReleaseMutex(m_unblockLock);
    414     ASSERT_UNUSED(res, res);
    415 
    416     if (signalsToIssue) {
    417         res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0);
    418         ASSERT_UNUSED(res, res);
    419     }
    420 }
    421 
    422 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
    423 
    424 ThreadCondition::ThreadCondition()
    425 {
    426     m_condition.m_waitersGone = 0;
    427     m_condition.m_waitersBlocked = 0;
    428     m_condition.m_waitersToUnblock = 0;
    429     m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0);
    430     m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
    431     m_condition.m_unblockLock = CreateMutex(0, 0, 0);
    432 
    433     if (!m_condition.m_blockLock || !m_condition.m_blockQueue || !m_condition.m_unblockLock) {
    434         if (m_condition.m_blockLock)
    435             CloseHandle(m_condition.m_blockLock);
    436         if (m_condition.m_blockQueue)
    437             CloseHandle(m_condition.m_blockQueue);
    438         if (m_condition.m_unblockLock)
    439             CloseHandle(m_condition.m_unblockLock);
    440     }
    441 }
    442 
    443 ThreadCondition::~ThreadCondition()
    444 {
    445     CloseHandle(m_condition.m_blockLock);
    446     CloseHandle(m_condition.m_blockQueue);
    447     CloseHandle(m_condition.m_unblockLock);
    448 }
    449 
    450 void ThreadCondition::wait(Mutex& mutex)
    451 {
    452     m_condition.timedWait(mutex.impl(), INFINITE);
    453 }
    454 
    455 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
    456 {
    457     DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
    458 
    459     if (!interval) {
    460         // Consider the wait to have timed out, even if our condition has already been signaled, to
    461         // match the pthreads implementation.
    462         return false;
    463     }
    464 
    465     return m_condition.timedWait(mutex.impl(), interval);
    466 }
    467 
    468 void ThreadCondition::signal()
    469 {
    470     m_condition.signal(false); // Unblock only 1 thread.
    471 }
    472 
    473 void ThreadCondition::broadcast()
    474 {
    475     m_condition.signal(true); // Unblock all threads.
    476 }
    477 
    478 DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime)
    479 {
    480     double currentTime = WTF::currentTime();
    481 
    482     // Time is in the past - return immediately.
    483     if (absoluteTime < currentTime)
    484         return 0;
    485 
    486     // Time is too far in the future (and would overflow unsigned long) - wait forever.
    487     if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0)
    488         return INFINITE;
    489 
    490     return static_cast<DWORD>((absoluteTime - currentTime) * 1000.0);
    491 }
    492 
    493 } // namespace WTF
    494 
    495 #endif // OS(WINDOWS)
    496