~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/JavaScriptCore/wtf/ThreadingWin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
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.
3
5
 *
4
6
 * Redistribution and use in source and binary forms, with or without
5
7
 * modification, are permitted provided that the following conditions
24
26
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 
 *
28
 
 * =============================================================================
29
 
 * Note:  The implementation of condition variables under the Windows
30
 
 * plaform was based on that of the excellent BOOST C++ library.  It
31
 
 * has been rewritten to fit in with the WebKit architecture and to
32
 
 * use its coding conventions.
33
 
 * =============================================================================
34
 
 *
35
 
 * The Boost license is virtually identical to the Apple variation at the
36
 
 * top of this file, but is included here for completeness:
37
 
 *
38
 
 * Boost Software License - Version 1.0 - August 17th, 2003
39
 
 *
40
 
 * Permission is hereby granted, free of charge, to any person or organization
41
 
 * obtaining a copy of the software and accompanying documentation covered by
42
 
 * this license (the "Software") to use, reproduce, display, distribute,
43
 
 * execute, and transmit the Software, and to prepare derivative works of the
44
 
 * Software, and to permit third-parties to whom the Software is furnished to
45
 
 * do so, all subject to the following:
46
 
 *
47
 
 * The copyright notices in the Software and this entire statement, including
48
 
 * the above license grant, this restriction and the following disclaimer,
49
 
 * must be included in all copies of the Software, in whole or in part, and
50
 
 * all derivative works of the Software, unless such copies or derivative
51
 
 * works are solely in the form of machine-executable object code generated by
52
 
 * a source language processor.
53
 
 *
54
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
 
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
57
 
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
58
 
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
59
 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
60
 
 * DEALINGS IN THE SOFTWARE.
 
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
61
84
 */
62
85
 
63
86
#include "config.h"
67
90
#if !USE(PTHREADS) && PLATFORM(WIN_OS)
68
91
#include "ThreadSpecific.h"
69
92
#endif
 
93
#if !PLATFORM(WINCE)
70
94
#include <process.h>
 
95
#endif
 
96
#if HAVE(ERRNO_H)
 
97
#include <errno.h>
 
98
#else
 
99
#define NO_ERRNO
 
100
#endif
71
101
#include <windows.h>
 
102
#include <wtf/CurrentTime.h>
72
103
#include <wtf/HashMap.h>
73
104
#include <wtf/MathExtras.h>
74
105
#include <wtf/RandomNumberSeed.h>
75
106
 
76
107
namespace WTF {
77
108
 
78
 
// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadName all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
 
109
// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
79
110
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
80
111
 
81
112
#pragma pack(push, 8)
87
118
} THREADNAME_INFO;
88
119
#pragma pack(pop)
89
120
 
90
 
static void setThreadName(DWORD dwThreadID, LPCSTR szThreadName)
 
121
void setThreadNameInternal(const char* szThreadName)
91
122
{
92
 
    // Visual Studio has a 31-character limit on thread names. Longer names will
93
 
    // be truncated silently, but we'd like callers to know about the limit.
94
 
    ASSERT_ARG(szThreadName, strlen(szThreadName) <= 31);
95
 
 
96
123
    THREADNAME_INFO info;
97
124
    info.dwType = 0x1000;
98
125
    info.szName = szThreadName;
99
 
    info.dwThreadID = dwThreadID;
 
126
    info.dwThreadID = GetCurrentThreadId();
100
127
    info.dwFlags = 0;
101
128
 
102
129
    __try {
134
161
        initializeRandomNumberGenerator();
135
162
        initializeMainThread();
136
163
        mainThreadIdentifier = currentThread();
137
 
        setThreadName(mainThreadIdentifier, "Main Thread");
 
164
        setThreadNameInternal("Main Thread");
138
165
    }
139
166
}
140
167
 
191
218
    unsigned threadIdentifier = 0;
192
219
    ThreadIdentifier threadID = 0;
193
220
    ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data);
 
221
#if PLATFORM(WINCE)
 
222
    // This is safe on WINCE, since CRT is in the core and innately multithreaded.
 
223
    // On desktop Windows, need to use _beginthreadex (not available on WinCE) if using any CRT functions
 
224
    HANDLE threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)wtfThreadEntryPoint, invocation, 0, (LPDWORD)&threadIdentifier);
 
225
#else
194
226
    HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &threadIdentifier));
 
227
#endif
195
228
    if (!threadHandle) {
 
229
#if PLATFORM(WINCE)
 
230
        LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, ::GetLastError());
 
231
#elif defined(NO_ERRNO)
 
232
        LOG_ERROR("Failed to create thread at entry point %p with data %p.", entryPoint, data);
 
233
#else
196
234
        LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
 
235
#endif
197
236
        return 0;
198
237
    }
199
238
 
200
 
    if (threadName)
201
 
        setThreadName(threadIdentifier, threadName);
202
 
 
203
239
    threadID = static_cast<ThreadIdentifier>(threadIdentifier);
204
240
    storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
205
241
 
214
250
    if (!threadHandle)
215
251
        LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
216
252
 
217
 
    DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
 
253
    DWORD joinResult = WaitForSingleObject(threadHandle, INFINITE);
218
254
    if (joinResult == WAIT_FAILED)
219
255
        LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
220
256
 
221
 
    ::CloseHandle(threadHandle);
 
257
    CloseHandle(threadHandle);
222
258
    clearThreadHandleForIdentifier(threadID);
223
259
 
224
260
    return joinResult;
227
263
void detachThread(ThreadIdentifier threadID)
228
264
{
229
265
    ASSERT(threadID);
230
 
    
 
266
 
231
267
    HANDLE threadHandle = threadHandleForIdentifier(threadID);
232
268
    if (threadHandle)
233
 
        ::CloseHandle(threadHandle);
 
269
        CloseHandle(threadHandle);
234
270
    clearThreadHandleForIdentifier(threadID);
235
271
}
236
272
 
237
273
ThreadIdentifier currentThread()
238
274
{
239
 
    return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
 
275
    return static_cast<ThreadIdentifier>(GetCurrentThreadId());
240
276
}
241
277
 
242
278
bool isMainThread()
247
283
Mutex::Mutex()
248
284
{
249
285
    m_mutex.m_recursionCount = 0;
250
 
    ::InitializeCriticalSection(&m_mutex.m_internalMutex);
 
286
    InitializeCriticalSection(&m_mutex.m_internalMutex);
251
287
}
252
288
 
253
289
Mutex::~Mutex()
254
290
{
255
 
    ::DeleteCriticalSection(&m_mutex.m_internalMutex);
 
291
    DeleteCriticalSection(&m_mutex.m_internalMutex);
256
292
}
257
293
 
258
294
void Mutex::lock()
259
295
{
260
 
    ::EnterCriticalSection(&m_mutex.m_internalMutex);
 
296
    EnterCriticalSection(&m_mutex.m_internalMutex);
261
297
    ++m_mutex.m_recursionCount;
262
298
}
263
299
    
269
305
    // treats this as a successful case, it changes the behavior of several
270
306
    // tests in WebKit that check to see if the current thread already
271
307
    // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
272
 
    DWORD result = ::TryEnterCriticalSection(&m_mutex.m_internalMutex);
 
308
    DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
273
309
    
274
310
    if (result != 0) {       // We got the lock
275
311
        // If this thread already had the lock, we must unlock and
276
312
        // return false so that we mimic the behavior of POSIX's
277
313
        // pthread_mutex_trylock:
278
314
        if (m_mutex.m_recursionCount > 0) {
279
 
            ::LeaveCriticalSection(&m_mutex.m_internalMutex);
 
315
            LeaveCriticalSection(&m_mutex.m_internalMutex);
280
316
            return false;
281
317
        }
282
318
 
290
326
void Mutex::unlock()
291
327
{
292
328
    --m_mutex.m_recursionCount;
293
 
    ::LeaveCriticalSection(&m_mutex.m_internalMutex);
 
329
    LeaveCriticalSection(&m_mutex.m_internalMutex);
 
330
}
 
331
 
 
332
bool PlatformCondition::timedWait(PlatformMutex& mutex, DWORD durationMilliseconds)
 
333
{
 
334
    // Enter the wait state.
 
335
    DWORD res = WaitForSingleObject(m_blockLock, INFINITE);
 
336
    ASSERT(res == WAIT_OBJECT_0);
 
337
    ++m_waitersBlocked;
 
338
    res = ReleaseSemaphore(m_blockLock, 1, 0);
 
339
    ASSERT(res);
 
340
 
 
341
    LeaveCriticalSection(&mutex.m_internalMutex);
 
342
 
 
343
    // Main wait - use timeout.
 
344
    bool timedOut = (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT);
 
345
 
 
346
    res = WaitForSingleObject(m_unblockLock, INFINITE);
 
347
    ASSERT(res == WAIT_OBJECT_0);
 
348
 
 
349
    int signalsLeft = m_waitersToUnblock;
 
350
 
 
351
    if (m_waitersToUnblock)
 
352
        --m_waitersToUnblock;
 
353
    else if (++m_waitersGone == (INT_MAX / 2)) { // timeout/canceled or spurious semaphore
 
354
        // timeout or spurious wakeup occured, normalize the m_waitersGone count
 
355
        // this may occur if many calls to wait with a timeout are made and
 
356
        // no call to notify_* is made
 
357
        res = WaitForSingleObject(m_blockLock, INFINITE);
 
358
        ASSERT(res == WAIT_OBJECT_0);
 
359
        m_waitersBlocked -= m_waitersGone;
 
360
        res = ReleaseSemaphore(m_blockLock, 1, 0);
 
361
        ASSERT(res);
 
362
        m_waitersGone = 0;
 
363
    }
 
364
 
 
365
    res = ReleaseMutex(m_unblockLock);
 
366
    ASSERT(res);
 
367
 
 
368
    if (signalsLeft == 1) {
 
369
        res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate.
 
370
        ASSERT(res);
 
371
    }
 
372
 
 
373
    EnterCriticalSection (&mutex.m_internalMutex);
 
374
 
 
375
    return !timedOut;
 
376
}
 
377
 
 
378
void PlatformCondition::signal(bool unblockAll)
 
379
{
 
380
    unsigned signalsToIssue = 0;
 
381
 
 
382
    DWORD res = WaitForSingleObject(m_unblockLock, INFINITE);
 
383
    ASSERT(res == WAIT_OBJECT_0);
 
384
 
 
385
    if (m_waitersToUnblock) { // the gate is already closed
 
386
        if (!m_waitersBlocked) { // no-op
 
387
            res = ReleaseMutex(m_unblockLock);
 
388
            ASSERT(res);
 
389
            return;
 
390
        }
 
391
 
 
392
        if (unblockAll) {
 
393
            signalsToIssue = m_waitersBlocked;
 
394
            m_waitersToUnblock += m_waitersBlocked;
 
395
            m_waitersBlocked = 0;
 
396
        } else {
 
397
            signalsToIssue = 1;
 
398
            ++m_waitersToUnblock;
 
399
            --m_waitersBlocked;
 
400
        }
 
401
    } else if (m_waitersBlocked > m_waitersGone) {
 
402
        res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate.
 
403
        ASSERT(res == WAIT_OBJECT_0);
 
404
        if (m_waitersGone != 0) {
 
405
            m_waitersBlocked -= m_waitersGone;
 
406
            m_waitersGone = 0;
 
407
        }
 
408
        if (unblockAll) {
 
409
            signalsToIssue = m_waitersBlocked;
 
410
            m_waitersToUnblock = m_waitersBlocked;
 
411
            m_waitersBlocked = 0;
 
412
        } else {
 
413
            signalsToIssue = 1;
 
414
            m_waitersToUnblock = 1;
 
415
            --m_waitersBlocked;
 
416
        }
 
417
    } else { // No-op.
 
418
        res = ReleaseMutex(m_unblockLock);
 
419
        ASSERT(res);
 
420
        return;
 
421
    }
 
422
 
 
423
    res = ReleaseMutex(m_unblockLock);
 
424
    ASSERT(res);
 
425
 
 
426
    if (signalsToIssue) {
 
427
        res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0);
 
428
        ASSERT(res);
 
429
    }
294
430
}
295
431
 
296
432
static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
297
433
 
298
434
ThreadCondition::ThreadCondition()
299
435
{
300
 
    m_condition.m_timedOut = 0;
301
 
    m_condition.m_blocked = 0;
302
 
    m_condition.m_waitingForRemoval = 0;
303
 
    m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
304
 
    m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
305
 
    m_condition.m_mutex = ::CreateMutex(0, 0, 0);
 
436
    m_condition.m_waitersGone = 0;
 
437
    m_condition.m_waitersBlocked = 0;
 
438
    m_condition.m_waitersToUnblock = 0;
 
439
    m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0);
 
440
    m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
 
441
    m_condition.m_unblockLock = CreateMutex(0, 0, 0);
306
442
 
307
 
    if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
308
 
        if (m_condition.m_gate)
309
 
            ::CloseHandle(m_condition.m_gate);
310
 
        if (m_condition.m_queue)
311
 
            ::CloseHandle(m_condition.m_queue);
312
 
        if (m_condition.m_mutex)
313
 
            ::CloseHandle(m_condition.m_mutex);
 
443
    if (!m_condition.m_blockLock || !m_condition.m_blockQueue || !m_condition.m_unblockLock) {
 
444
        if (m_condition.m_blockLock)
 
445
            CloseHandle(m_condition.m_blockLock);
 
446
        if (m_condition.m_blockQueue)
 
447
            CloseHandle(m_condition.m_blockQueue);
 
448
        if (m_condition.m_unblockLock)
 
449
            CloseHandle(m_condition.m_unblockLock);
314
450
    }
315
451
}
316
452
 
317
453
ThreadCondition::~ThreadCondition()
318
454
{
319
 
    ::CloseHandle(m_condition.m_gate);
320
 
    ::CloseHandle(m_condition.m_queue);
321
 
    ::CloseHandle(m_condition.m_mutex);
 
455
    CloseHandle(m_condition.m_blockLock);
 
456
    CloseHandle(m_condition.m_blockQueue);
 
457
    CloseHandle(m_condition.m_unblockLock);
322
458
}
323
 
    
 
459
 
324
460
void ThreadCondition::wait(Mutex& mutex)
325
461
{
326
 
    PlatformMutex& cs = mutex.impl();
327
 
 
328
 
    // Enter the wait state.
329
 
    DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
330
 
    ASSERT(res == WAIT_OBJECT_0);
331
 
    ++m_condition.m_blocked;
332
 
    res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
333
 
    ASSERT(res);
334
 
 
335
 
    ::LeaveCriticalSection(&cs.m_internalMutex);
336
 
 
337
 
    res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
338
 
    ASSERT(res == WAIT_OBJECT_0);
339
 
 
340
 
    res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
341
 
    ASSERT(res == WAIT_OBJECT_0);
342
 
    size_t wasWaiting = m_condition.m_waitingForRemoval;
343
 
    size_t wasTimedOut = m_condition.m_timedOut;
344
 
    if (wasWaiting != 0) {
345
 
        if (--m_condition.m_waitingForRemoval == 0) {
346
 
            if (m_condition.m_blocked != 0) {
347
 
                res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);  // open m_gate
348
 
                ASSERT(res);
349
 
                wasWaiting = 0;
350
 
            }
351
 
            else if (m_condition.m_timedOut != 0)
352
 
                m_condition.m_timedOut = 0;
353
 
        }
354
 
    } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
355
 
        // timeout occured, normalize the m_condition.m_timedOut count
356
 
        // this may occur if many calls to wait with a timeout are made and
357
 
        // no call to notify_* is made
358
 
        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
359
 
        ASSERT(res == WAIT_OBJECT_0);
360
 
        m_condition.m_blocked -= m_condition.m_timedOut;
361
 
        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
362
 
        ASSERT(res);
363
 
        m_condition.m_timedOut = 0;
364
 
    }
365
 
    res = ::ReleaseMutex(m_condition.m_mutex);
366
 
    ASSERT(res);
367
 
 
368
 
    if (wasWaiting == 1) {
369
 
        for (/**/ ; wasTimedOut; --wasTimedOut) {
370
 
            // better now than spurious later
371
 
            res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
372
 
            ASSERT(res == WAIT_OBJECT_0);
373
 
        }
374
 
        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
375
 
        ASSERT(res);
376
 
    }
377
 
 
378
 
    ::EnterCriticalSection (&cs.m_internalMutex);
 
462
    m_condition.timedWait(mutex.impl(), INFINITE);
379
463
}
380
464
 
381
 
bool ThreadCondition::timedWait(Mutex& mutex, double interval)
 
465
bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
382
466
{
383
 
    // Empty for now
384
 
    ASSERT(false);
385
 
    return false;
 
467
    double currentTime = WTF::currentTime();
 
468
 
 
469
    // Time is in the past - return immediately.
 
470
    if (absoluteTime < currentTime)
 
471
        return false;
 
472
 
 
473
    // Time is too far in the future (and would overflow unsigned long) - wait forever.
 
474
    if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0) {
 
475
        wait(mutex);
 
476
        return true;
 
477
    }
 
478
 
 
479
    double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0;
 
480
    return m_condition.timedWait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds));
386
481
}
387
482
 
388
483
void ThreadCondition::signal()
389
484
{
390
 
    unsigned signals = 0;
391
 
 
392
 
    DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
393
 
    ASSERT(res == WAIT_OBJECT_0);
394
 
 
395
 
    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
396
 
        if (m_condition.m_blocked == 0) {
397
 
            res = ::ReleaseMutex(m_condition.m_mutex);
398
 
            ASSERT(res);
399
 
            return;
400
 
        }
401
 
 
402
 
        ++m_condition.m_waitingForRemoval;
403
 
        --m_condition.m_blocked;
404
 
 
405
 
        signals = 1;
406
 
    } else {
407
 
        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
408
 
        ASSERT(res == WAIT_OBJECT_0);
409
 
        if (m_condition.m_blocked > m_condition.m_timedOut) {
410
 
            if (m_condition.m_timedOut != 0) {
411
 
                m_condition.m_blocked -= m_condition.m_timedOut;
412
 
                m_condition.m_timedOut = 0;
413
 
            }
414
 
            signals = m_condition.m_waitingForRemoval = 1;
415
 
            --m_condition.m_blocked;
416
 
        } else {
417
 
            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
418
 
            ASSERT(res);
419
 
        }
420
 
    }
421
 
 
422
 
    res =::ReleaseMutex(m_condition.m_mutex);
423
 
    ASSERT(res);
424
 
 
425
 
    if (signals) {
426
 
        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
427
 
        ASSERT(res);
428
 
    }
 
485
    m_condition.signal(false); // Unblock only 1 thread.
429
486
}
430
487
 
431
488
void ThreadCondition::broadcast()
432
489
{
433
 
    unsigned signals = 0;
434
 
 
435
 
    DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
436
 
    ASSERT(res == WAIT_OBJECT_0);
437
 
 
438
 
    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
439
 
        if (m_condition.m_blocked == 0) {
440
 
            res = ::ReleaseMutex(m_condition.m_mutex);
441
 
            ASSERT(res);
442
 
            return;
443
 
        }
444
 
 
445
 
        m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
446
 
        m_condition.m_blocked = 0;
447
 
    } else {
448
 
        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
449
 
        ASSERT(res == WAIT_OBJECT_0);
450
 
        if (m_condition.m_blocked > m_condition.m_timedOut) {
451
 
            if (m_condition.m_timedOut != 0) {
452
 
                m_condition.m_blocked -= m_condition.m_timedOut;
453
 
                m_condition.m_timedOut = 0;
454
 
            }
455
 
            signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
456
 
            m_condition.m_blocked = 0;
457
 
        } else {
458
 
            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
459
 
            ASSERT(res);
460
 
        }
461
 
    }
462
 
 
463
 
    res = ::ReleaseMutex(m_condition.m_mutex);
464
 
    ASSERT(res);
465
 
 
466
 
    if (signals) {
467
 
        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
468
 
        ASSERT(res);
469
 
    }
 
490
    m_condition.signal(true); // Unblock all threads.
470
491
}
471
492
 
472
493
} // namespace WTF