Визуальное моделирование сложных реагирующих систем при помощи диаграмм состояния UML Harel - Последовательность действий при обработке событий в StateWizard

ОГЛАВЛЕНИЕ

Последовательность действий при обработке событий в StateWizard

Цикл обработки событий

Функция SmeRun() – это функция цикла обработки событий ядра конечного автомата. Если в очереди нет событий, эта функция ждет внешнего события. Если любое событие было запущено, она передаст его соответствующим приложениям и будет обеспечивать выполнение конечными автоматами соответствующих переходов и действий.

Если было запущено внешнее событие, оно будет преобразовано во внутреннее событие при помощи ожидающей внешнее событие функции, которая является функцией виртуального уровня операционной системы.

Если функция разрушения внешнего события привязана, SmeRun() вызовет эту функцию, чтобы разрушить внешнее событие, когда внешнее событие использовано.

void SmeRun(void)
{
    SME_EVENT_T ExtEvent;
    SME_EVENT_T *pEvent=NULL;
    SME_OBJ_T *pObj;

    SME_THREAD_CONTEXT_PT pThreadContext=NULL;
    if (g_pfnGetThreadContext)
        pThreadContext = (*g_pfnGetThreadContext)();
    if (!pThreadContext) return;

    if (!g_pfnGetExtEvent) return;

    pObj = pThreadContext->pActObjHdr;

    while (TRUE)
    {
        /* Сначала проверяется внутренний пул событий. */
        pEvent = GetEventFromQueue();
        if (pEvent == NULL)
        {
            /* Ожидание внешнего события. */
            if (FALSE == (*g_pfnGetExtEvent)(&ExtEvent))
                return; // Завершение потока.

            pEvent = &ExtEvent;
            pEvent->nOrigin = SME_EVENT_ORIGIN_EXTERNAL;

            /* Вызов привязанной функции при наступлении внешнего события. */
            if (pThreadContext->fnOnEventComeHook)
                (*pThreadContext->fnOnEventComeHook)
                (SME_EVENT_ORIGIN_EXTERNAL, pEvent);
        }else
        {
            /* Вызов привязанной функции при наступлении внутреннего события. */
            if (pThreadContext->fnOnEventComeHook)
                (*pThreadContext->fnOnEventComeHook)
                (SME_EVENT_ORIGIN_INTERNAL, pEvent);
        }

        do {
            DispatchEventToApps(pThreadContext, pEvent);

            /* Освобождение внутреннего события. Позже освобождается внешнее событие. */
            if (pEvent != &ExtEvent)
                SmeDeleteEvent(pEvent);

            /* Извлечение события из очереди событий при наличии такового. */
            pEvent = GetEventFromQueue();
            if (pEvent != NULL)
            {
                /* Вызов привязанной функции при наступлении внутреннего события. */
                if (pThreadContext->fnOnEventComeHook)
                    (*pThreadContext->fnOnEventComeHook)
                    (SME_EVENT_ORIGIN_INTERNAL, pEvent);
            }
            else
            {
                /* Очередь внутренних событий пуста. */
                break;
            }
        } while (TRUE); /* Извлечение всех событий из пула внутренних событий. */

        /* Освобождение внешнего события при необходимости. */
        if (g_pfnDelExtEvent)
        {
            (*g_pfnDelExtEvent)(&ExtEvent);
            // Ядро должно удалить это событие,
            // так как преобразование внешнего события
            // создаст внутреннее событие.
            SmeDeleteEvent(&ExtEvent);
        }

    } /* Ожидание внешнего события. */
}

Функция SmeSetExtEventOprProc() устанавливает зависящие от платформы рабочие функции внешнего события. Они работают в качестве виртуального слоя ОС StateWizard. Функция цикла обработки событий SmeRun() вызывает функцию fnGetExtEvent, чтобы получить внешнее событие и освободить его после обработки при помощи fnDelExtEvent

void SmeSetExtEventOprProc(SME_GET_EXT_EVENT_PROC_T fnGetExtEvent,
            SME_DEL_EXT_EVENT_PROC_T fnDelExtEvent,
    SME_POST_THREAD_EXT_INT_EVENT_PROC_T fnPostThreadExtIntEvent,
    SME_POST_THREAD_EXT_PTR_EVENT_PROC_T fnPostThreadExtPtrEvent,
    SME_INIT_THREAD_EXT_MSG_BUF_PROC_T fnInitThreadExtMsgBuf,
    SME_INIT_THREAD_EXT_MSG_BUF_PROC_T fnFreeThreadExtMsgBuf)
{
    g_pfnGetExtEvent = fnGetExtEvent;
    g_pfnDelExtEvent = fnDelExtEvent;

    g_pfnPostThreadExtIntEvent = fnPostThreadExtIntEvent;
    g_pfnPostThreadExtPtrEvent = fnPostThreadExtPtrEvent;

    g_pfnInitThreadExtMsgBuf = fnInitThreadExtMsgBuf;
    g_pfnFreeThreadExtMsgBuf = fnFreeThreadExtMsgBuf;
}

 

Управление внешними событиями

Функция SmeSetExtEventOprProc()устанавливает зависящие от платформы рабочие функции внешнего события. Они работают в качестве виртуального слоя ОС StateWizard. Функция цикла обработки событий SmeRun()вызывает функцию fnGetExtEvent, чтобы получить внешнее событие и освободить его после обработки при помощи fnDelExtEvent.

BOOL XGetExtEvent(SME_EVENT_T* pEvent)
{
    X_EXT_MSG_T NativeMsg;
    int ret=0;

    SME_THREAD_CONTEXT_T* p = XGetThreadContext();
    X_EXT_MSG_POOL_T *pMsgPool;
    if (NULL==pEvent || NULL==p || NULL==p->pExtEventPool)
        return FALSE;

    pMsgPool = (X_EXT_MSG_POOL_T*)(p->pExtEventPool);

    memset(&NativeMsg,0,sizeof(NativeMsg));
    while (TRUE)
    {
        ret = XWaitForEvent(&(pMsgPool->EventToThread),
            &(pMsgPool->MutexForPool),
            (XIS_CODITION_OK_T)XIsMsgAvailable, NULL,
            (XTHREAD_SAFE_ACTION_T)XGetMsgFromBuf,&NativeMsg);

        if (NativeMsg.nMsgID == SME_EVENT_EXIT_LOOP)
        {
            return FALSE; //Запрашиваем выход
        }
#ifdef SME_WIN32
#else
        // Встроенный таймер обратного вызова в Linux
        else if (SME_EVENT_TIMER == NativeMsg.nMsgID 
            && SME_TIMER_TYPE_CALLBACK == NativeMsg.Data.Int.nParam1)
        {
            // Вызов функции обратного вызова.
            SME_TIMER_PROC_T pfnCallback =
                (SME_TIMER_PROC_T)(NativeMsg.Data.Int.nParam2);
            (*pfnCallback)(NativeMsg.pDestObj, NativeMsg.nSequenceNum);
        }
#endif
        else {
            // Преобразование собственного сообщения в событие SME.
            memset(pEvent,0,sizeof(SME_EVENT_T));
            pEvent->nEventID = NativeMsg.nMsgID;
            pEvent->pDestObj = NativeMsg.pDestObj;
            pEvent->nSequenceNum = NativeMsg.nSequenceNum;
            pEvent->nDataFormat = NativeMsg.nDataFormat;
            pEvent->nCategory = NativeMsg.nCategory;
            pEvent->bIsConsumed = FALSE;
            memcpy(&(pEvent->Data),&(NativeMsg.Data),
                    sizeof(union SME_EVENT_DATA_T));
        }

        //printf("Получено внешнее сообщение. \n");

        return TRUE;
    }; // while (TRUE)
}

BOOL XDelExtEvent(SME_EVENT_T *pEvent)
{
    if (0==pEvent)
        return FALSE;

    if (pEvent->nDataFormat == SME_EVENT_DATA_FORMAT_PTR)
    {
        if (pEvent->Data.Ptr.pData)
        {
#if SME_CPP
            delete pEvent->Data.Ptr.pData;
#else
            free(pEvent->Data.Ptr.pData);
#endif
            pEvent->Data.Ptr.pData=NULL;
        }
    }
    return TRUE;
}