void P_SEND_Timer_IMPL(PRT_MACHINEINST *context, PRT_VALUE *evnt, PRT_VALUE *payload, PRT_BOOLEAN doTransfer) { printf("Entering P_SEND_Timer_IMPL\n"); PRT_VALUE *ev; BOOL success; TimerContext *timerContext = (TimerContext *)context->extContext; if (!inStart && evnt->valueUnion.ev == P_EVENT_START) { printf("Timer received START\n"); LARGE_INTEGER liDueTime; liDueTime.QuadPart = -10000 * payload->valueUnion.nt; success = SetWaitableTimer(timerContext->timer, &liDueTime, 0, Callback, context, FALSE); inStart = TRUE; PrtAssert(success, "SetWaitableTimer failed"); } else if (evnt->valueUnion.ev == P_EVENT_CANCEL) { printf("Timer received CANCEL\n"); inStart = FALSE; success = CancelWaitableTimer(timerContext->timer); if (success) { ev = PrtMkEventValue(P_EVENT_CANCEL_SUCCESS); PrtSend(context, PrtGetMachine(context->process, timerContext->client), ev, context->id, PRT_FALSE); } else { ev = PrtMkEventValue(P_EVENT_CANCEL_FAILURE); PrtSend(context, PrtGetMachine(context->process, timerContext->client), ev, context->id, PRT_FALSE); } PrtFreeValue(ev); } else { PrtAssert(FALSE, "Illegal event"); } }
PRT_VALUE *P_FUN_StartTimer_IMPL(PRT_MACHINEINST *context) { PRT_MACHINEINST_PRIV *p_tmp_mach_priv = (PRT_MACHINEINST_PRIV *)context; PRT_VALUE *p_tmp_ret = NULL; PRT_FUNSTACK_INFO p_tmp_frame; // pop frame PrtPopFrame(p_tmp_mach_priv, &p_tmp_frame); PRT_VALUE* timerMachineId = p_tmp_frame.locals[0]; PRT_MACHINEINST* timerMachine = PrtGetMachine(context->process, timerMachineId); TimerContext *timerContext = (TimerContext *)timerMachine->extContext; int timeout_value = p_tmp_frame.locals[1]->valueUnion.nt; SleepMs(timeout_value); PRT_VALUE *ev = PrtMkEventValue(P_EVENT_TIMEOUT); PRT_MACHINEINST* clientMachine = PrtGetMachine(context->process, timerContext->client); PrtSend(context, clientMachine, ev, context->id, PRT_FALSE); PrtFreeValue(ev); // free the frame PrtFreeLocals(p_tmp_mach_priv, &p_tmp_frame); return NULL; }
VOID CALLBACK Callback(LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue) { inStart = FALSE; PRT_MACHINEINST *context = (PRT_MACHINEINST *)arg; TimerContext *timerContext = (TimerContext *)context->extContext; PRT_VALUE *ev = PrtMkEventValue(P_EVENT_TIMEOUT); PrtSend(PrtGetMachine(context->process, timerContext->client), ev, context->id, PRT_FALSE); PrtFreeValue(ev); }
void PrtPop( _Inout_ PRT_MACHINEINST_PRIV *context ) { context->lastOperation = PopStatement; PrtFreeValue(context->currentTrigger); PrtFreeValue(context->currentPayload); context->currentTrigger = PrtMkEventValue(PRT_SPECIAL_EVENT_NULL); context->currentPayload = PrtMkNullValue(); // Actual pop happens in PrtPopState; the exit function must be executed first. // context->{currentTrigger,currentPayload} are set on for the benefit of the exit function. }
PRT_BOOLEAN PrtDequeueEvent( _Inout_ PRT_MACHINEINST_PRIV *context, _Inout_ PRT_FUNSTACK_INFO *frame ) { PRT_UINT32 queueLength; PRT_EVENTQUEUE *queue; PRT_UINT32* deferPacked; PRT_UINT32 i, head; queue = &context->eventQueue; queueLength = queue->eventsSize; deferPacked = PrtGetDeferredPacked(context, context->currentState); head = queue->headIndex; PRT_DBG_ASSERT(queue->size <= queueLength, "Check Failed"); PRT_DBG_ASSERT(queue->size >= 0, "Check Failed"); PRT_DBG_ASSERT(queue->headIndex >= 0, "Check Failed"); PRT_DBG_ASSERT(queue->tailIndex >= 0, "Check Failed"); // // Find the element to dequeue // for (i = 0; i < queue->size; i++) { PRT_UINT32 index = (head + i) % queueLength; PRT_EVENT e = queue->events[index]; PRT_UINT32 triggerIndex = PrtPrimGetEvent(e.trigger); if (context->receive == NULL) { if (!PrtIsEventDeferred(triggerIndex, context->currentDeferredSetCompact)) { PrtFreeValue(context->currentTrigger); PrtFreeValue(context->currentPayload); context->currentTrigger = e.trigger; context->currentPayload = e.payload; break; } } else { if (PrtIsEventReceivable(context, triggerIndex)) { PrtFreeValue(context->currentTrigger); PrtFreeValue(context->currentPayload); context->currentTrigger = e.trigger; context->currentPayload = e.payload; for (PRT_UINT32 i = 0; i < context->receive->nCases; i++) { PRT_CASEDECL *rcase = &context->receive->cases[i]; if (triggerIndex == rcase->triggerEventIndex) { frame->rcase = rcase; PrtPushNewEventHandlerFrame(context, rcase->funIndex, frame->locals); break; } } context->receive = NULL; break; } } } // // Check if not found // if (i == queue->size) { if (context->receive == NULL) { if (PrtStateHasDefaultTransitionOrAction(context)) { PrtFreeValue(context->currentTrigger); PrtFreeValue(context->currentPayload); context->currentTrigger = PrtMkEventValue(PRT_SPECIAL_EVENT_NULL); context->currentPayload = PrtMkNullValue(); return PRT_TRUE; } else { return PRT_FALSE; } } else { PRT_BOOLEAN hasDefaultCase = (context->process->program->eventSets[context->receive->caseSetIndex].packedEvents[0] & 0x1) == 1; if (hasDefaultCase) { PrtFreeValue(context->currentTrigger); PrtFreeValue(context->currentPayload); context->currentTrigger = PrtMkEventValue(PRT_SPECIAL_EVENT_NULL); context->currentPayload = PrtMkNullValue(); for (PRT_UINT32 i = 0; i < context->receive->nCases; i++) { PRT_CASEDECL *rcase = &context->receive->cases[i]; if (PRT_SPECIAL_EVENT_NULL == rcase->triggerEventIndex) { frame->rcase = rcase; PrtPushNewEventHandlerFrame(context, rcase->funIndex, frame->locals); break; } } context->receive = NULL; return PRT_TRUE; } else { return PRT_FALSE; } } } // // Collapse the event queue on the removed event // by moving the previous elements forward. // for (; i > 0; i--) { INT index = (head + i) % queueLength; INT prev = (index - 1 + queueLength) % queueLength; queue->events[index] = queue->events[prev]; } // // Adjust the queue size // queue->headIndex = (queue->headIndex + 1) % queueLength; queue->size--; PRT_DBG_ASSERT(queue->size <= queueLength, "Check Failed"); PRT_DBG_ASSERT(queue->size >= 0, "Check Failed"); PRT_DBG_ASSERT(queue->headIndex >= 0, "Check Failed"); PRT_DBG_ASSERT(queue->tailIndex >= 0, "Check Failed"); // //Log // PrtLog(PRT_STEP_DEQUEUE, context); return PRT_TRUE; }
PRT_MACHINEINST_PRIV * PrtMkMachinePrivate( _Inout_ PRT_PROCESS_PRIV *process, _In_ PRT_UINT32 instanceOf, _In_ PRT_VALUE *payload ) { PRT_UINT32 packSize; PRT_UINT32 nVars; PRT_UINT8 eQSize; PRT_MACHINEINST_PRIV *context; PRT_UINT32 i; PrtLockMutex(process->processLock); nVars = process->program->machines[instanceOf].nVars; eQSize = PRT_QUEUE_LEN_DEFAULT; // // Allocate memory for state machine context // context = (PRT_MACHINEINST_PRIV*)PrtMalloc(sizeof(PRT_MACHINEINST_PRIV)); // // Add it to the array of machines in the process // PRT_UINT32 numMachines = process->numMachines; PRT_UINT32 machineCount = process->machineCount; PRT_MACHINEINST **machines = process->machines; if (machineCount == 0) { machines = (PRT_MACHINEINST **)PrtCalloc(1, sizeof(PRT_MACHINEINST *)); process->machines = machines; process->machineCount = 1; } else if (machineCount == numMachines) { PRT_MACHINEINST **newMachines = (PRT_MACHINEINST **)PrtCalloc(2 * machineCount, sizeof(PRT_MACHINEINST *)); for (PRT_UINT32 i = 0; i < machineCount; i++) { newMachines[i] = machines[i]; } PrtFree(machines); machines = newMachines; process->machines = newMachines; process->machineCount = 2 * machineCount; } machines[numMachines] = (PRT_MACHINEINST *)context; process->numMachines++; // // Initialize Machine Identity // context->process = (PRT_PROCESS *)process; context->instanceOf = instanceOf; PRT_MACHINEID id; id.machineId = process->numMachines; // index begins with 1 since 0 is reserved id.processId = process->guid; context->id = PrtMkMachineValue(id); context->extContext = NULL; context->isModel = PRT_FALSE; // // Initialize the map used in PrtDist, map from sender to the last seqnumber received // PRT_TYPE *domType = PrtMkPrimitiveType(PRT_KIND_MACHINE); PRT_TYPE *codType = PrtMkPrimitiveType(PRT_KIND_INT); PRT_TYPE *recvMapType = PrtMkMapType(domType, codType); context->recvMap = PrtMkDefaultValue(recvMapType); PrtFreeType(domType); PrtFreeType(codType); PrtFreeType(recvMapType); // Initialize Machine Internal Variables // context->currentState = process->program->machines[context->instanceOf].initStateIndex; context->isRunning = PRT_FALSE; context->isHalted = PRT_FALSE; context->lastOperation = ReturnStatement; context->currentTrigger = PrtMkEventValue(PRT_SPECIAL_EVENT_NULL); context->currentPayload = PrtCloneValue(payload); // // Allocate memory for local variables and initialize them // context->varValues = NULL; if (nVars > 0) { context->varValues = PrtCalloc(nVars, sizeof(PRT_VALUE*)); for (i = 0; i < nVars; i++) { context->varValues[i] = PrtMkDefaultValue(process->program->machines[instanceOf].vars[i].type); } } context->receive = NULL; // // Initialize various stacks // context->callStack.length = 0; context->funStack.length = 0; // // Initialize event queue // context->eventQueue.eventsSize = eQSize; context->eventQueue.events = (PRT_EVENT*)PrtCalloc(eQSize, sizeof(PRT_EVENT)); context->eventQueue.headIndex = 0; context->eventQueue.tailIndex = 0; context->eventQueue.size = 0; packSize = PrtGetPackSize(context); // // Initialize Inherited Deferred Set // context->inheritedDeferredSetCompact = (PRT_UINT32*)PrtCalloc(packSize, sizeof(PRT_UINT32)); // // Initialize the current deferred set // context->currentDeferredSetCompact = (PRT_UINT32*)PrtCalloc(packSize, sizeof(PRT_UINT32)); // // Initialize actions // context->inheritedActionSetCompact = (PRT_UINT32*)PrtCalloc(packSize, sizeof(PRT_UINT32)); context->currentActionSetCompact = (PRT_UINT32*)PrtCalloc(packSize, sizeof(PRT_UINT32)); // //Initialize state machine lock // context->stateMachineLock = PrtCreateMutex(); // //Log // PrtLog(PRT_STEP_CREATE, context); // // Allocate external context Structure // process->program->machines[context->instanceOf].extCtorFun((PRT_MACHINEINST *)context, payload); PrtUnlockMutex(process->processLock); // // Run the state machine // PrtLockMutex(context->stateMachineLock); PrtRunStateMachine(context, PRT_FALSE); return context; }