Ignore:
Timestamp:
Feb 23, 2008, 1:52:07 PM (17 years ago)
Author:
[email protected]
Message:

Windows build fix - move ThreadCondition implementation from WebCore to WTF.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/wtf/ThreadingWin.cpp

    r30522 r30527  
    2525 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    2626 * 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.
    2761 */
    2862
     
    165199}
    166200
     201static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
     202
     203ThreadCondition::ThreadCondition()
     204{
     205    m_condition.m_timedOut = 0;
     206    m_condition.m_blocked = 0;
     207    m_condition.m_waitingForRemoval = 0;
     208    m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
     209    m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
     210    m_condition.m_mutex = ::CreateMutex(0, 0, 0);
     211
     212    if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
     213        if (m_condition.m_gate)
     214            ::CloseHandle(m_condition.m_gate);
     215        if (m_condition.m_queue)
     216            ::CloseHandle(m_condition.m_queue);
     217        if (m_condition.m_mutex)
     218            ::CloseHandle(m_condition.m_mutex);
     219    }
     220}
     221
     222ThreadCondition::~ThreadCondition()
     223{
     224    ::CloseHandle(m_condition.m_gate);
     225    ::CloseHandle(m_condition.m_queue);
     226    ::CloseHandle(m_condition.m_mutex);
     227}
     228   
     229void ThreadCondition::wait(Mutex& mutex)
     230{
     231    PlatformMutex& cs = mutex.impl();
     232
     233    // Enter the wait state.
     234    DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
     235    ASSERT(res == WAIT_OBJECT_0);
     236    ++m_condition.m_blocked;
     237    res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
     238    ASSERT(res);
     239
     240    ::LeaveCriticalSection(&cs.m_internalMutex);
     241
     242    res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
     243    ASSERT(res == WAIT_OBJECT_0);
     244
     245    res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
     246    ASSERT(res == WAIT_OBJECT_0);
     247    size_t wasWaiting = m_condition.m_waitingForRemoval;
     248    size_t wasTimedOut = m_condition.m_timedOut;
     249    if (wasWaiting != 0) {
     250        if (--m_condition.m_waitingForRemoval == 0) {
     251            if (m_condition.m_blocked != 0) {
     252                res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);  // open m_gate
     253                ASSERT(res);
     254                wasWaiting = 0;
     255            }
     256            else if (m_condition.m_timedOut != 0)
     257                m_condition.m_timedOut = 0;
     258        }
     259    } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
     260        // timeout occured, normalize the m_condition.m_timedOut count
     261        // this may occur if many calls to wait with a timeout are made and
     262        // no call to notify_* is made
     263        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
     264        ASSERT(res == WAIT_OBJECT_0);
     265        m_condition.m_blocked -= m_condition.m_timedOut;
     266        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
     267        ASSERT(res);
     268        m_condition.m_timedOut = 0;
     269    }
     270    res = ::ReleaseMutex(m_condition.m_mutex);
     271    ASSERT(res);
     272
     273    if (wasWaiting == 1) {
     274        for (/**/ ; wasTimedOut; --wasTimedOut) {
     275            // better now than spurious later
     276            res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
     277            ASSERT(res == WAIT_OBJECT_0);
     278        }
     279        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
     280        ASSERT(res);
     281    }
     282
     283    ::EnterCriticalSection (&cs.m_internalMutex);
     284}
     285
     286void ThreadCondition::signal()
     287{
     288    unsigned signals = 0;
     289
     290    DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
     291    ASSERT(res == WAIT_OBJECT_0);
     292
     293    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
     294        if (m_condition.m_blocked == 0) {
     295            res = ::ReleaseMutex(m_condition.m_mutex);
     296            ASSERT(res);
     297            return;
     298        }
     299
     300        ++m_condition.m_waitingForRemoval;
     301        --m_condition.m_blocked;
     302
     303        signals = 1;
     304    } else {
     305        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
     306        ASSERT(res == WAIT_OBJECT_0);
     307        if (m_condition.m_blocked > m_condition.m_timedOut) {
     308            if (m_condition.m_timedOut != 0) {
     309                m_condition.m_blocked -= m_condition.m_timedOut;
     310                m_condition.m_timedOut = 0;
     311            }
     312            signals = m_condition.m_waitingForRemoval = 1;
     313            --m_condition.m_blocked;
     314        } else {
     315            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
     316            ASSERT(res);
     317        }
     318    }
     319
     320    res =::ReleaseMutex(m_condition.m_mutex);
     321    ASSERT(res);
     322
     323    if (signals) {
     324        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
     325        ASSERT(res);
     326    }
     327}
     328
     329void ThreadCondition::broadcast()
     330{
     331    unsigned signals = 0;
     332
     333    WORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
     334    ASSERT(res == WAIT_OBJECT_0);
     335
     336    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
     337        if (m_condition.m_blocked == 0) {
     338            res = ::ReleaseMutex(m_condition.m_mutex);
     339            ASSERT(res);
     340            return;
     341        }
     342
     343        m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
     344        m_condition.m_blocked = 0;
     345    } else {
     346        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
     347        ASSERT(res == WAIT_OBJECT_0);
     348        if (m_condition.m_blocked > m_condition.m_timedOut) {
     349            if (m_condition.m_timedOut != 0) {
     350                m_condition.m_blocked -= m_condition.m_timedOut;
     351                m_condition.m_timedOut = 0;
     352            }
     353            signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
     354            m_condition.m_blocked = 0;
     355        } else {
     356            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
     357            ASSERT(res);
     358        }
     359    }
     360
     361    res = ::ReleaseMutex(m_condition.m_mutex);
     362    ASSERT(res);
     363
     364    if (signals) {
     365        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
     366        ASSERT(res);
     367    }
     368}
     369
    167370} // namespace WTF
Note: See TracChangeset for help on using the changeset viewer.