FORCEINLINE PRT_BOOLEAN PrtStateHasDefaultTransitionOrAction( _In_ PRT_MACHINEINST_PRIV *context ) { PrtAssert(context->receive == NULL, "This function should not be called at a receive"); PRT_STATEDECL *stateDecl = PrtGetCurrentStateDecl(context); PRT_BOOLEAN hasDefaultTransition = (context->process->program->eventSets[stateDecl->transSetIndex].packedEvents[0] & 0x1) == 1; PRT_BOOLEAN hasDefaultAction = (context->currentActionSetCompact[0] & 0x1) == 1; return hasDefaultTransition || hasDefaultAction; }
FORCEINLINE void PrtRunExitFunction( _In_ PRT_MACHINEINST_PRIV *context, _In_ PRT_UINT32 transIndex ) { PRT_STATEDECL *stateDecl = PrtGetCurrentStateDecl(context); context->lastOperation = ReturnStatement; PrtLog(PRT_STEP_EXIT, context); PRT_UINT32 exitFunIndex = context->process->program->machines[context->instanceOf].states[context->currentState].exitFunIndex; PrtPushNewEventHandlerFrame(context, exitFunIndex, NULL); PrtGetExitFunction(context)((PRT_MACHINEINST *)context); if (transIndex < stateDecl->nTransitions) { PRT_UINT32 transFunIndex = stateDecl->transitions[transIndex].transFunIndex; PRT_DBG_ASSERT(transFunIndex != PRT_SPECIAL_ACTION_PUSH_OR_IGN, "Must be valid function index"); PrtPushNewEventHandlerFrame(context, transFunIndex, NULL); context->process->program->machines[context->instanceOf].funs[transFunIndex].implementation((PRT_MACHINEINST *)context); } PRT_DBG_ASSERT(context->lastOperation == ReturnStatement, "Exit function must terminate with a ReturnStatement"); }
void PrtRunStateMachine( _Inout_ PRT_MACHINEINST_PRIV *context, _In_ PRT_BOOLEAN doDequeue ) { PRT_BOOLEAN lockHeld; PRT_DODECL *currActionDecl; PRT_UINT32 eventValue; context->isRunning = PRT_TRUE; if (doDequeue) { lockHeld = PRT_TRUE; goto DoDequeue; } else { lockHeld = PRT_FALSE; PrtUnlockMutex(context->stateMachineLock); goto DoEntry; } DoEntry: PrtUpdateCurrentActionsSet(context); PrtUpdateCurrentDeferredSet(context); context->lastOperation = ReturnStatement; if (context->funStack.length == 0) { PrtLog(PRT_STEP_ENTRY, context); PRT_UINT32 entryFunIndex = context->process->program->machines[context->instanceOf].states[context->currentState].entryFunIndex; PrtPushNewEventHandlerFrame(context, entryFunIndex, NULL); } PRT_UINT32 funIndex = PrtBottomOfFunStack(context)->funIndex; context->process->program->machines[context->instanceOf].funs[funIndex].implementation((PRT_MACHINEINST *)context); goto CheckLastOperation; DoAction: currActionDecl = PrtGetAction(context); PRT_UINT32 doFunIndex = currActionDecl->doFunIndex; context->lastOperation = ReturnStatement; if (doFunIndex == PRT_SPECIAL_ACTION_PUSH_OR_IGN) { PrtLog(PRT_STEP_IGNORE, context); } else { if (context->funStack.length == 0) { PrtLog(PRT_STEP_DO, context); PrtPushNewEventHandlerFrame(context, doFunIndex, NULL); } PRT_UINT32 funIndex = PrtBottomOfFunStack(context)->funIndex; context->process->program->machines[context->instanceOf].funs[funIndex].implementation((PRT_MACHINEINST *)context); } goto CheckLastOperation; CheckLastOperation: if (context->receive != NULL) { context->isRunning = PRT_FALSE; PrtUnlockMutex(context->stateMachineLock); return; } switch (context->lastOperation) { case PopStatement: PrtRunExitFunction(context, PrtGetCurrentStateDecl(context)->nTransitions); PrtPopState(context, PRT_TRUE); goto DoDequeue; case RaiseStatement: goto DoHandleEvent; case ReturnStatement: goto DoDequeue; default: PRT_DBG_ASSERT(0, "Unexpected case in switch"); break; } DoDequeue: if (!lockHeld) { lockHeld = PRT_TRUE; PrtLockMutex(context->stateMachineLock); } PrtAssert(context->receive == NULL, "Machine must not be blocked at a receive"); if (PrtDequeueEvent(context, NULL)) { lockHeld = PRT_FALSE; PrtUnlockMutex(context->stateMachineLock); goto DoHandleEvent; } else { context->isRunning = PRT_FALSE; PrtUnlockMutex(context->stateMachineLock); return; } DoHandleEvent: PrtAssert(context->receive == NULL, "Must not be blocked at a receive"); eventValue = PrtPrimGetEvent(PrtGetCurrentTrigger(context)); if (PrtIsPushTransition(context, eventValue)) { PrtTakeTransition(context, eventValue); goto DoEntry; } else if (PrtIsTransitionPresent(context, eventValue)) { PrtRunExitFunction(context, PrtFindTransition(context, eventValue)); PrtTakeTransition(context, eventValue); goto DoEntry; } else if (PrtIsActionInstalled(eventValue, context->currentActionSetCompact)) { goto DoAction; } else { PrtRunExitFunction(context, PrtGetCurrentStateDecl(context)->nTransitions); PrtPopState(context, PRT_FALSE); if (context->isHalted) return; goto DoHandleEvent; } PRT_DBG_ASSERT(PRT_FALSE, "Must not get here"); return; }
FORCEINLINE PRT_DODECL* PrtGetAction( _In_ PRT_MACHINEINST_PRIV *context ) { PRT_UINT32 currEvent = PrtPrimGetEvent(PrtGetCurrentTrigger(context)); PRT_BOOLEAN isActionInstalled = PRT_FALSE; PRT_UINT32 i, nActions; PRT_STATESTACK currStack; PRT_STATEDECL *stateTable; PRT_UINT32 topOfStackState; PRT_STATEDECL *stateDecl; PRT_DODECL *actionDecl = NULL; //check if action is defined for the current state isActionInstalled = PrtIsActionInstalled(currEvent, PrtGetActionsPacked(context, context->currentState)); if (isActionInstalled) { // // get action function // stateDecl = PrtGetCurrentStateDecl(context); nActions = stateDecl->nDos; for (i = 0; i < nActions; i++) { if (stateDecl->dos[i].triggerEventIndex == currEvent) { actionDecl = &stateDecl->dos[i]; return actionDecl; } } } // // Scan the parent states // currStack = context->callStack; stateTable = context->process->program->machines[context->instanceOf].states; for (i = currStack.length - 1; i >= 0; i--) { topOfStackState = currStack.stateStack[i].stateIndex; isActionInstalled = PrtIsActionInstalled(currEvent, PrtGetActionsPacked(context, topOfStackState)); if (isActionInstalled) { // // get action function // nActions = stateTable[topOfStackState].nDos; for (i = 0; i < nActions; i++) { if (stateTable[topOfStackState].dos[i].triggerEventIndex == currEvent) { actionDecl = &stateTable[topOfStackState].dos[i]; return actionDecl; } } } } PRT_DBG_ASSERT(actionDecl != NULL, "Action must not be NULL"); return actionDecl; }
static void PrtUserPrintStep(_In_ PRT_STEP step, PRT_MACHINEINST *sender, _In_ PRT_MACHINEINST *receiver, _In_ PRT_VALUE* event, _In_ PRT_VALUE* payload, _Inout_ char **buffer, _Inout_ PRT_UINT32 *bufferSize, _Inout_ PRT_UINT32 *numCharsWritten) { PRT_MACHINEINST_PRIV * c = (PRT_MACHINEINST_PRIV *)receiver; PRT_STRING machineName = c->process->program->machines[c->instanceOf]->name; PRT_UINT32 machineId = c->id->valueUnion.mid->machineId; PRT_STRING stateName = PrtGetCurrentStateDecl(c)->name; PRT_STRING eventName; switch (step) { case PRT_STEP_HALT: PrtUserPrintString("<HaltLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") halted in state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_ENQUEUE: eventName = c->process->program->events[PrtPrimGetEvent(event)].name; PrtUserPrintString("<EnqueueLog> Enqueued event ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(eventName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" with payload ", buffer, bufferSize, numCharsWritten); PrtUserPrintValue(payload, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" on Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(")\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_DEQUEUE: eventName = c->process->program->events[PrtPrimGetEvent(event)].name; PrtUserPrintString("<DequeueLog> Dequeued event ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(eventName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" with payload ", buffer, bufferSize, numCharsWritten); PrtUserPrintValue(payload, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" by Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(")\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_ENTRY: PrtUserPrintString("<StateLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") entered state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_CREATE: PrtUserPrintString("<CreateLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") is created\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_GOTO: { PRT_MACHINEINST_PRIV *context = (PRT_MACHINEINST_PRIV *)sender; PRT_STRING destStateName = c->process->program->machines[context->instanceOf]->states[context->destStateIndex].name; PrtUserPrintString("<GotoLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") goes to state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(destStateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" with payload ", buffer, bufferSize, numCharsWritten); PrtUserPrintValue(payload, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; } case PRT_STEP_RAISE: eventName = c->process->program->events[PrtPrimGetEvent(event)].name; PrtUserPrintString("<RaiseLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") raised event ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(eventName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" with payload ", buffer, bufferSize, numCharsWritten); PrtUserPrintValue(payload, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_POP: PrtUserPrintString("<PopLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") popped and reentered state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_PUSH: PrtUserPrintString("<PushLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") pushed\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_UNHANDLED: eventName = c->process->program->events[c->eventValue].name; PrtUserPrintString("<PopLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") popped with unhandled event ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(eventName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" and reentered state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_DO: PrtUserPrintString("<ActionLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") executed action in state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_EXIT: PrtUserPrintString("<ExitLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") exiting state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; case PRT_STEP_IGNORE: eventName = c->process->program->events[PrtPrimGetEvent(event)].name; PrtUserPrintString("<ActionLog> Machine ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(machineName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("(", buffer, bufferSize, numCharsWritten); PrtUserPrintUint32(machineId, buffer, bufferSize, numCharsWritten); PrtUserPrintString(") ignored event ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(eventName, buffer, bufferSize, numCharsWritten); PrtUserPrintString(" in state ", buffer, bufferSize, numCharsWritten); PrtUserPrintString(stateName, buffer, bufferSize, numCharsWritten); PrtUserPrintString("\n", buffer, bufferSize, numCharsWritten); break; default: PrtAssert(PRT_FALSE, "Illegal PRT_STEP value"); break; } }