void DrCriticalSectionBase::SetCriticalSectionLoggingParameters(
    bool logUsage,
    DrTimeInterval logHeldTooLongTimeout
)
{
    _logHeldTooLongTimeoutMs = DrGetTimerMsFromInterval(logHeldTooLongTimeout);
    _logUsage = logUsage;
}
void DrCriticalSectionBase::Init(
    __in PCSTR name,
    DWORD spinCount,
    bool logUsage,
    DrTimeInterval logHeldTooLongTimeout
    )
{
    _name = (name != NULL) ? name : "UnknownCritSec";
    _logUsage = logUsage;
    _logHeldTooLongTimeoutMs = DrGetTimerMsFromInterval(logHeldTooLongTimeout);
    _lastFunctionName = NULL;
    _lastFileName = NULL;
    _lastLineNumber = 0;
    _enterTimeMs = 0;
    LogAssert( InitializeCriticalSectionAndSpinCount( this, spinCount ) );
}
void RChannelFifoWriter::Drain(DrTimeInterval csTimeOut,
                               RChannelItemRef* pReturnItem)
{
    DrTimeStamp startTime = DrGetCurrentTimeStamp();

    bool waitForWriterDrain = false;

    {
        AutoCriticalSection acs(&m_baseDR);

        LogAssert(m_writerState == WS_Running);
        LogAssert(m_writerTerminationItem != NULL);
        LogAssert(m_availableUnits == 0);

        if (m_supplierState == SS_Running && m_outstandingUnits == 0)
        {
            LogAssert(m_blockedList.IsEmpty());
        }

        if (m_outstandingUnits > 0 || m_blockedList.IsEmpty() == false)
        {
            LogAssert(m_terminationUnit != NULL);
            m_writerState = WS_Draining;
            waitForWriterDrain = true;
        }
    }

    if (waitForWriterDrain)
    {
        DWORD dRet = ::WaitForSingleObject(m_writerDrainEvent, INFINITE);
        LogAssert(dRet == WAIT_OBJECT_0);
    }

    {
        AutoCriticalSection acs(&m_baseDR);

        LogAssert(m_outstandingUnits == 0);
        LogAssert(m_blockedList.IsEmpty());
        LogAssert(m_availableUnits == 0);
        LogAssert(m_reader != NULL);
        LogAssert(m_outstandingUnits == 0);
        LogAssert(m_terminationUnit == NULL);

        m_writerState = WS_Stopped;
        ++m_writerEpoch;
        m_nextDeliverySequenceNumber = 0;
        m_nextDataSequenceNumber = 0;
    }

    DrTimeStamp currentTime = DrGetCurrentTimeStamp();
    DrTimeInterval elapsed = DrGetElapsedTime(startTime, currentTime);
    if (elapsed < csTimeOut)
    {
        DWORD timeOut = DrGetTimerMsFromInterval(csTimeOut - elapsed);
        DWORD dRet = ::WaitForSingleObject(m_supplierDrainEvent, timeOut);
        LogAssert(dRet == WAIT_TIMEOUT || dRet == WAIT_OBJECT_0);
    }

    if (pReturnItem != NULL)
    {
        AutoCriticalSection acs(&m_baseDR);

        *pReturnItem = m_readerTerminationItem;
    }
}
void DrCriticalSectionBase::SetCriticalSectionLogHeldTooLongTimeout(
    DrTimeInterval logHeldTooLongTimeout
)
{
    _logHeldTooLongTimeoutMs = DrGetTimerMsFromInterval(logHeldTooLongTimeout);
}
bool RChannelReaderImpl::FetchNextItemArray(UInt32 maxArraySize,
                                            RChannelItemArrayRef* pItemArray,
                                            DrTimeInterval csTimeOut)
{
    ChannelProcessRequestList requestList;
    ChannelUnitList returnUnitList;
    DryadHandleListEntry* event = NULL;
    bool timedOut = false;
    bool mustBlock = false;
    bool startSupplier = false;

    {
        AutoCriticalSection acs(&m_baseDR);

        if (m_state != RS_Running)
        {
            LogAssert(m_state != RS_Closed);
            /* return an empty array */
            pItemArray->Attach(new RChannelItemArray());
            return true;
        }

        if (!m_unitList.IsEmpty())
        {
            LogAssert(m_startedSupplier == true);
            LogAssert(m_handlerList.IsEmpty());

            RChannelReaderSyncWaiter dummyHandler(NULL,
                                                  INVALID_HANDLE_VALUE,
                                                  NULL);
            dummyHandler.SetMaximumArraySize(maxArraySize);
            RChannelProcessRequest dummyRequest(NULL, &dummyHandler, NULL);
            m_handlerList.InsertAsTail(m_handlerList.CastIn(&dummyRequest));

            TransferWaitingItems("FetchNextItemArray",
                                 &requestList, &returnUnitList);

            RChannelProcessRequest* dummyReturn =
                requestList.CastOut(requestList.RemoveHead());
            LogAssert(dummyReturn == &dummyRequest);

            pItemArray->Set(dummyRequest.GetItemArray());
            LogAssert((*pItemArray)->GetNumberOfItems() > 0);
        }
        else if (m_writerTerminationItem != NULL ||
                 m_readerTerminationItem != NULL)
        {
            /* we have already sent a termination item for processing
               so there aren't going to be any more arriving on the
               queue and we can return an empty list immediately */
            pItemArray->Attach(new RChannelItemArray());
        }
        else if (csTimeOut > DrTimeInterval_Zero)
        {
            if (m_startedSupplier == false)
            {
                /* when we exit the lock, we will start the supplier
                   since this is the first read we have
                   received. After the supplier has been started we'll
                   set m_startedSupplierEvent to prevent a race
                   condition in Interrupt */
                startSupplier = true;
                BOOL bRet = ::ResetEvent(m_startedSupplierEvent);
                LogAssert(bRet != 0);
                m_startedSupplier = true;
            }

            /* we are going to block */
            mustBlock = true;
            event = m_eventCache.GetEvent(true);
        }
        else
        {
            /* there's no item available and a zero timeout --- return
               an empty list immediately */
            pItemArray->Attach(new RChannelItemArray());
            LogAssert(csTimeOut == DrTimeInterval_Zero);
            timedOut = true;
        }

        m_unitLatch.AcceptList(&returnUnitList);
        FOO(&requestList);
        m_sendLatch.AcceptList(&requestList);
    }

    if (startSupplier)
    {
//         DrLogI( "Starting Supplier");
        m_supplier->StartSupplier(m_prefetchCookie);
//         DrLogI( "Started Supplier");
        BOOL bRet = ::SetEvent(m_startedSupplierEvent);
        LogAssert(bRet != 0);
    }

    DispatchRequests("FetchNextItemArray", &requestList, &returnUnitList);

    if (mustBlock == false)
    {
        LogAssert(event == NULL);
    }
    else
    {
        LogAssert(event != NULL);

        *pItemArray = NULL;

        RChannelReaderSyncWaiter* waiter =
            new RChannelReaderSyncWaiter(this, event->GetHandle(), pItemArray);
        this->SupplyHandler(waiter, waiter);

        DWORD timeOut = DrGetTimerMsFromInterval(csTimeOut);
        DWORD dRet = ::WaitForSingleObject(event->GetHandle(), timeOut);

        if (dRet == WAIT_TIMEOUT)
        {
            /* when cancel returns it's guaranteed the handler has
               been called */
            this->Cancel(waiter);
        }
        else
        {
            LogAssert(dRet == WAIT_OBJECT_0);
        }

        LogAssert(*pItemArray != NULL);

        delete waiter;

        {
            AutoCriticalSection acs(&m_baseDR);

            /* save this event in case we need one again in the
               future */
            m_eventCache.ReturnEvent(event);

            /* even if we actually timed out the wait, the handler may
               have supplied an item immediately afterwards or during
               the cancel. We only return a timed out value if there's
               no item ready but we haven't processed a termination
               item, so it's worth waiting for another one. */
            timedOut = ((*pItemArray)->GetNumberOfItems() == 0 &&
                        m_writerTerminationItem == NULL &&
                        m_readerTerminationItem == NULL);
        }
    }

    return (!timedOut);
}