Пример #1
0
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);
}
Пример #2
0
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;
	}
}
Пример #3
0
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);
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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);

}