DrError RChannelReader::GetTerminationStatus(DryadMetaDataRef* pErrorData)
{
    DrError status;

    RChannelItemRef writerTermination;
    RChannelItemRef readerTermination;
    GetTerminationItems(&writerTermination,
                        &readerTermination);

    LogAssert(readerTermination.Ptr() != NULL);
    if (writerTermination.Ptr() != NULL &&
        writerTermination->GetType() != RChannelItem_EndOfStream)
    {
        status = writerTermination->GetErrorFromItem();
        *pErrorData = writerTermination->GetMetaData();
    }
    else if (readerTermination->GetType() == RChannelItem_EndOfStream)
    {
        status = DrError_EndOfStream;
        *pErrorData = readerTermination->GetMetaData();
    }
    else
    {
        status = DryadError_ProcessingInterrupted;
        *pErrorData = readerTermination->GetMetaData();
    }

    return status;
}
Beispiel #2
0
void DryadSubGraphVertex::VertexInfo::DrainChannels()
{
    if (m_virtual || m_vertexProgram == NULL)
    {
        return;
    }

    DrLogI(
        "Vertex draining channels. Vertex ID %u", m_id);

    UInt32 i;
    for (i=0; i<m_inputPortCount; ++i)
    {
        if (m_inputExternal[i])
        {
            DrLogI(
                "Vertex not draining external input. Vertex ID %u port %u", m_id, i);
        }
        else if (m_inputChannel[i] != NULL)
        {
            m_inputChannel[i]->Drain();
            DrLogI(
                "Vertex drained internal input. Vertex ID %u port %u", m_id, i);
        }
    }

    bool errorCondition = false;
    for (i=0; i<m_outputPortCount; ++i)
    {
        if (m_outputExternal[i])
        {
            DrLogI(
                "Vertex not draining external output. Vertex ID %u port %u", m_id, i);
        }
        else if (m_outputChannel[i] != NULL)
        {
            RChannelItemRef writeTermination;
            m_outputChannel[i]->Drain(DrTimeInterval_Zero, &writeTermination);
            if (writeTermination != NULL)
            {
                if (writeTermination->GetType() != RChannelItem_EndOfStream)
                {
                    DrLogI(
                        "Vertex internal output write error. Vertex ID %u port %u type %u", m_id, i,
                        writeTermination->GetType());
                    errorCondition = true;
                }
            }
            DrLogI(
                "Vertex drained internal output. Vertex ID %u port %u", m_id, i);
        }
    }

    if (errorCondition && m_vertexProgram->NoError())
    {
        m_vertexProgram->ReportError(DryadError_ChannelWriteError);
    }
}
//
// Interrupt an input channel for provided reason
//
void RChannelReaderImpl::Interrupt(RChannelItem* interruptItemBase)
{
    RChannelItemRef interruptItem = interruptItemBase;
    bool doInterrupt;
    bool startedSupplier = false;
    BOOL bRet;

    //
    // Enter a critical section and update state from "Running" to "Interrupting"
    //
    {
        AutoCriticalSection acs(&m_baseDR);

        if (m_state == RS_Running)
        {
            doInterrupt = true;
            bRet = ::ResetEvent(m_interruptEvent);
            LogAssert(bRet != 0);
            m_state = RS_InterruptingSupplier;
            startedSupplier = m_startedSupplier;
        }
        else
        {
            doInterrupt = false;
        }
    }

    //
    // If already interrupting, wait for interrupt event to be handled
    //
    if (doInterrupt == false)
    {
        bRet = ::WaitForSingleObject(m_interruptEvent, INFINITE);
        LogAssert(bRet == WAIT_OBJECT_0);
        return;
    }

    ChannelProcessRequestList handlerDispatch;
    ChannelUnitList unitDispatch;
    DrBListEntry* listEntry;
    RChannelInterruptHandler* interruptHandler = NULL;

    if (startedSupplier)
    {
        //
        // startedSupplier just means that we (potentially in another
        // thread) have called or are about to call StartSupplier,
        // outside the lock. We'll wait here until it really gets
        // called before calling InterruptSupplier 
        //
        bRet = ::WaitForSingleObject(m_startedSupplierEvent, INFINITE);
        LogAssert(bRet == WAIT_OBJECT_0);

        //
        // when this returns the buffer reader will not be generating
        // any new buffers and the parser will not be generating any
        // new items.  
        //
        m_supplier->InterruptSupplier();
    }

    {
        AutoCriticalSection acs(&m_baseDR);

        if (interruptItem == NULL)
        {
            if (m_writerTerminationItem == NULL)
            {
                interruptItem.Attach(RChannelMarkerItem::
                                     Create(RChannelItem_Abort, false));
            }
            else
            {
                RChannelItemType interruptType =
                    m_writerTerminationItem->GetType();
                interruptItem.Attach(RChannelMarkerItem::
                                     Create(interruptType, false));
                interruptItem->ReplaceMetaData(m_writerTerminationItem->
                                               GetMetaData());
            }
        }
        else
        {
            RChannelItemType interruptType = interruptItem->GetType();
            LogAssert(RChannelItem::IsTerminationItem(interruptType));
        }

        LogAssert(m_state == RS_InterruptingSupplier);
        /* sanity check that nobody accidentally started the supplier
           while we were getting here */
        LogAssert(startedSupplier == m_startedSupplier);

        m_state = RS_Stopping;

        if (m_unitList.IsEmpty())
        {
            /* gather up any handlers which haven't been given an item
               yet */
            FillEmptyHandlers(&handlerDispatch);
        }
        else
        {
            LogAssert(m_handlerList.IsEmpty());
            /* gather up any units which have been put on the queue
               but don't have a handler waiting */
            bool gotTermination = (m_writerTerminationItem != NULL);
            while (m_unitList.IsEmpty() == false)
            {
                RChannelUnit* unit = m_unitList.CastOut(m_unitList.GetHead());
                if (unit->GetType() == RChannelUnit_Item)
                {
                    /* sanity check that the item sequence is
                       correct */
                    RChannelItemUnit* itemUnit = (RChannelItemUnit *) unit;
                    RChannelItemArray* itemArray = itemUnit->GetItemArray();

                    UInt32 nItems = itemArray->GetNumberOfItems();
                    LogAssert(nItems > 0);
                    RChannelItemRef* a = itemArray->GetItemArray();

                    UInt32 i;
                    for (i=0; i<nItems; ++i)
                    {
                        RChannelItem* item = a[i];
                        RChannelItemType itemType = item->GetType();
                        LogAssert(gotTermination == false);
                        if (RChannelItem::IsTerminationItem(itemType))
                        {
                            gotTermination = true;
                        }
                    }

                    itemUnit->DiscardItems();
                }
                unitDispatch.TransitionToTail(unitDispatch.CastIn(unit));
            }
        }

        /* prepare to trigger any interrupt handler the application
           sent in earlier */
        if (m_interruptHandler != NULL)
        {
            interruptHandler = m_interruptHandler;
            m_interruptHandler = NULL;
        }

        m_unitLatch.AcceptList(&unitDispatch);
    }

    /* these are handlers which had been submitted but not assigned an
       item */
    listEntry = handlerDispatch.GetHead();
    while (listEntry != NULL)
    {
        RChannelProcessRequest* request = handlerDispatch.CastOut(listEntry);
        listEntry = handlerDispatch.GetNext(listEntry);
        handlerDispatch.Remove(handlerDispatch.CastIn(request));
        /* call the process event (which calls back into
           RChannelReaderImpl::ProcessUnit) instead of just calling the
           handler in case there is a thread blocked on a cancellation
           which needs to be woken up. */
        request->Process();
        delete request;
    }

    ReturnUnits(&unitDispatch);

    if (startedSupplier)
    {
        /* assuming we ever started it, wait for the buffer reader to
           process all its returned buffers and tell us whether we can
           restart or not */
        m_supplier->DrainSupplier(interruptItem);
    }

    if (interruptHandler != NULL)
    {
        interruptHandler->ProcessInterrupt(interruptItem);
    }

    {
        AutoCriticalSection acs(&m_baseDR);

        /* sanity check that nobody accidentally started the supplier
           while we were getting here */
        LogAssert(startedSupplier == m_startedSupplier);

        LogAssert(m_unitList.IsEmpty());
        LogAssert(m_handlerList.IsEmpty());
        LogAssert(m_interruptHandler == NULL);
        LogAssert(m_readerTerminationItem == NULL);
        m_readerTerminationItem = interruptItem;
        m_startedSupplier = false;
    }

    bRet = ::SetEvent(m_interruptEvent);
    LogAssert(bRet != 0);
}