void PrtEnqueueInOrder( _In_ PRT_VALUE *source, _In_ PRT_INT64 seqNum, _Inout_ PRT_MACHINEINST_PRIV *context, _In_ PRT_VALUE *event, _In_ PRT_VALUE *payload ) { // Check if the enqueued event is in order if (context->isHalted) return; PrtLockMutex(context->stateMachineLock); if (PrtMapExists(context->recvMap, source) && PrtMapGet(context->recvMap, source)->valueUnion.nt >= seqNum) { PrtUnlockMutex(context->stateMachineLock); // Drop the event return; } else { PrtMapUpdate(context->recvMap, source, PrtMkIntValue((PRT_INT32)seqNum)); } PrtUnlockMutex(context->stateMachineLock); PrtSendPrivate(context, event, payload); }
PRT_BOOLEAN PrtReceive( _Inout_ PRT_MACHINEINST_PRIV *context, _Inout_ PRT_FUNSTACK_INFO *funStackInfo, _In_ PRT_UINT16 receiveIndex ) { PRT_UINT32 funIndex = funStackInfo->funIndex; PRT_FUNDECL *funDecl = &context->process->program->machines[context->instanceOf].funs[funIndex]; for (PRT_UINT32 i = 0; i < funDecl->nReceives; i++) { if (funDecl->receives[i].receiveIndex == receiveIndex) { context->receive = &funDecl->receives[i]; break; } } PrtAssert(context->receive != NULL, "receiveIndex must correspond to a valid receive"); funStackInfo->returnTo = receiveIndex; PrtLockMutex(context->stateMachineLock); PrtAssert(context->isRunning, "Machine must be running"); if (PrtDequeueEvent(context, funStackInfo)) { PrtUnlockMutex(context->stateMachineLock); return PRT_TRUE; } else { PrtPushFrame(context, funStackInfo); return PRT_FALSE; } }
void PrtDistSMLogHandler(PRT_STEP step, void *vcontext) { static FILE *logfile = NULL; PRT_MACHINEINST_PRIV *c = (PRT_MACHINEINST_PRIV*)vcontext; PrtLockMutex(((PRT_PROCESS_PRIV*)ContainerProcess)->processLock); if (logfile == NULL) { PRT_CHAR fileName[100] = "PRT_CONTAINER_LOG_"; PRT_CHAR processId[100]; _itoa(ContainerProcess->guid.data1, processId, 10); strcat_s(fileName, 100, processId); strcat_s(fileName, 100, ".txt"); logfile = fopen(fileName, "a+"); } PRT_STRING log = NULL; if (step == PRT_STEP_COUNT) //special logging { log = (PRT_STRING)vcontext; } else { log = PrtToStringStep(step, vcontext); } fputs(log, logfile); fputs("\n", logfile); fflush(logfile); PrtUnlockMutex(((PRT_PROCESS_PRIV*)ContainerProcess)->processLock); }
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; }
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; }
void PrtSendPrivate( _Inout_ PRT_MACHINEINST_PRIV *context, _In_ PRT_VALUE *event, _In_ PRT_VALUE *payload ) { PRT_EVENTQUEUE *queue; PRT_UINT32 tail; PRT_UINT32 eventMaxInstances; PRT_UINT32 maxQueueSize; PRT_UINT32 eventIndex; PrtAssert(!PrtIsSpecialEvent(event), "Enqueued event must not be null"); PrtAssert(PrtInhabitsType(payload, PrtGetPayloadType(context, event)), "Payload must be member of event payload type"); if (context->isHalted) { // drop the event silently return; } eventIndex = PrtPrimGetEvent(event); eventMaxInstances = context->process->program->events[eventIndex].eventMaxInstances; maxQueueSize = context->process->program->machines[context->instanceOf].maxQueueSize; PrtLockMutex(context->stateMachineLock); queue = &context->eventQueue; // check if maximum allowed instances of event are already present in queue if (eventMaxInstances != 0xffffffff && PrtIsEventMaxInstanceExceeded(queue, eventIndex, eventMaxInstances)) { PrtUnlockMutex(context->stateMachineLock); PrtHandleError(PRT_STATUS_EVENT_OVERFLOW, context); return; } // if queue is full, resize the queue if possible if (queue->eventsSize == queue->size) { if (maxQueueSize != 0xffffffff && queue->size == maxQueueSize) { PrtUnlockMutex(context->stateMachineLock); PrtHandleError(PRT_STATUS_QUEUE_OVERFLOW, context); return; } PrtResizeEventQueue(context); } tail = queue->tailIndex; // // Add event to the queue // queue->events[tail].trigger = PrtCloneValue(event); queue->events[tail].payload = PrtCloneValue(payload); queue->size++; queue->tailIndex = (tail + 1) % queue->eventsSize; // //Log // PrtLog(PRT_STEP_ENQUEUE, context); // // Now try to run the machine if its not running already // if (context->isRunning) { PrtUnlockMutex(context->stateMachineLock); } else if (context->receive == NULL) { PrtRunStateMachine(context, PRT_TRUE); } else if (PrtIsEventReceivable(context, PrtPrimGetEvent(event))) { PrtRunStateMachine(context, PRT_FALSE); } else { PrtUnlockMutex(context->stateMachineLock); } return; }
void PrtDistSMExceptionHandler( __in PRT_STATUS exception, __in void* vcontext ) { PRT_MACHINEINST *context = (PRT_MACHINEINST*)vcontext; PRT_STRING MachineName = context->process->program->machines[context->instanceOf].name; PRT_UINT32 MachineId = context->id->valueUnion.mid->machineId; FILE *logFile; PRT_MACHINEINST_PRIV *c = (PRT_MACHINEINST_PRIV*)vcontext; PrtLockMutex(((PRT_PROCESS_PRIV*)c->process)->processLock); PRT_CHAR fileName[100] = "PRT_CONTAINER_LOG_"; PRT_CHAR processId[100]; _itoa(c->id->valueUnion.mid->processId.data1, processId, 10); strcat_s(fileName, 100, processId); strcat_s(fileName, 100, ".txt"); logFile = fopen(fileName, "a+"); PRT_CHAR log[100]; switch (exception) { case PRT_STATUS_EVENT_UNHANDLED: sprintf(log, "<EXCEPTION> Machine %s(%d) : Unhandled Event Exception\n", MachineName, MachineId); break; case PRT_STATUS_EVENT_OVERFLOW: sprintf(log, "<EXCEPTION> Machine %s(%d) : MaxInstance of Event Exceeded Exception\n", MachineName, MachineId); break; case PRT_STATUS_QUEUE_OVERFLOW: sprintf(log, "<EXCEPTION> Queue Size Exceeded Max Limits in Machine %s(%d)\n", MachineName, MachineId); break; case PRT_STATUS_ILLEGAL_SEND: sprintf(log, "<EXCEPTION> Machine %s(%d) : Illegal use of send for sending message across process (source and target machines are in different process) ", MachineName, MachineId); break; default: sprintf(log, "<EXCEPTION> Machine %s(%d) : Unknown Exception\n", MachineName, MachineId); break; } fputs(log, logFile); fflush(logFile); PrtUnlockMutex(((PRT_PROCESS_PRIV*)c->process)->processLock); #ifdef PRT_DEBUG int msgboxID = MessageBoxEx( NULL, log, fileName, MB_OK, LANG_NEUTRAL ); switch (msgboxID) { case IDOK: exit(0); default: exit(-1); } #endif exit(-1); }