Esempio n. 1
0
void *runPA() {
    produce('A');
    signalSemaphore(&siA);
    signalSemaphore(&siii);
    while (1) {
        produce('A');
        signalSemaphore(&siii);
    }
}
Esempio n. 2
0
void *runPB() {
    waitSemaphore(&siii);
    produce('B');
    signalSemaphore(&siB);
    signalSemaphore(&siiC);
    while (1) {
        waitSemaphore(&siiB);
        waitSemaphore(&siii);
        produce('B');
        signalSemaphore(&siiC);
    }
}
Esempio n. 3
0
void *runC() {
    while (1) {
        waitSemaphore(&sC);
        putchar(buf[ri++]);
        ri %= BUF_SIZE;
        signalSemaphore(&sP);
    }
}
Esempio n. 4
0
void produce(char ch) {
    pthread_mutex_lock(&mutexP);
    waitSemaphore(&sP);
    buf[wi++] = ch;
    wi %= BUF_SIZE;
    signalSemaphore(&sC);
    pthread_mutex_unlock(&mutexP);
}
Esempio n. 5
0
// Signal a specified semaphore after the specified milliseconds duration (the argument). 
// NOTE: NOT ABSOLUTE VALUE!
// If the specified time has already passed, then the TimingSemaphore is signalled immediately. 
Oop* __fastcall Interpreter::primitiveSignalAtTick(CompiledMethod&, unsigned argumentCount)
{
	Oop tickPointer = stackTop();
	SMALLINTEGER nDelay;

	if (ObjectMemoryIsIntegerObject(tickPointer))
		nDelay = ObjectMemoryIntegerValueOf(tickPointer);
	else
	{
		OTE* oteArg = reinterpret_cast<OTE*>(tickPointer);
		return primitiveFailureWith(PrimitiveFailureNonInteger, oteArg);	// ticks must be SmallInteger
	}

	// To avoid any race conditions against the global timerID value (it is quite
	// common for the timer to fire, for example, before the timeSetEvent() call
	// has actually returned in the duration is very short because the timer thread
	// is operating at a very high priority), we use an interlocked operation

	UINT outstandingID = InterlockedExchange(reinterpret_cast<SHAREDLONG*>(&timerID), 0);
	// If outstanding timer now fires, it will do nothing. We'll end up killing something which is already
	// dead of course, but that should be OK
	if (outstandingID)
	{
#ifdef OAD
		TRACESTREAM << "Killing existing timer with id " << outstandingID << endl;
#endif
		UINT kill = ::timeKillEvent(outstandingID);
		if (kill != TIMERR_NOERROR)
			trace("Failed to kill timer %u (%d,%d)!\n\r", outstandingID, kill, GetLastError());
	}

	if (nDelay > 0)
	{
		// Temporarily handle old image code that passes timer semaphore as an argument
		if (argumentCount > 1 && (POTE)Pointers.TimingSemaphore == Pointers.Nil)
		{
			ObjectMemory::ProtectConstSpace(PAGE_READWRITE);
			_Pointers.TimingSemaphore = (SemaphoreOTE*)stackValue(1);
			ObjectMemory::ProtectConstSpace(PAGE_READONLY);
		}

		// Clamp the requested delay to the maximum if it is too large. This simplifies the Delay code in the image a little.
		if (nDelay > SMALLINTEGER(wTimerMax))
		{
			nDelay = wTimerMax;
		}

		// Set the timerID to a non-zero value just in case the timer fires before timeSetEvent() returns.
		// This allows the TimerProc to recognise the timer as valid (it doesn't really care about the 
		// timerID anyway, just that we're interested in it).
		// N.B. We shouldn't need an interlocked operation here because, assuming no bugs in the Win32 MM
		// timers, we've killed any outstanding timer, and the timer thread should be dormant
		timerID = UINT(-1);		// -1 is not used as a timer ID.

		UINT newTimerID = ::timeSetEvent(nDelay, 0, TimeProc, 0, TIME_ONESHOT);
		if (newTimerID && newTimerID != UINT(-1))
		{
			// Unless timer has already fired, record the timer id so can cancel if necessary
			_InterlockedCompareExchange(reinterpret_cast<SHAREDLONG*>(&timerID), newTimerID, -1);
			pop(argumentCount);		// No ref. counting required
		}
		else
		{
			// System refused to set timer for some reason
			DWORD error = GetLastError();
			trace("Oh no, failed to set a timer for %d mS (%d)!\n\r", nDelay, error);
			return primitiveFailureWithInt(PrimitiveFailureSystemError, error);
		}
	}
	else if (nDelay == 0)
	{
#ifdef _DEBUG
		TRACESTREAM << "Requested delay " << dec << nDelay << " passed, signalling immediately" << endl;
#endif
		// The request time has already passed, or does not fall within the
		// available timer resolution (i.e. it will happen too soon), so signal
		// it immediately
		// We must adjust stack before signalling, as may change Process (and therefore stack!)
		pop(argumentCount);

		// N.B. Signalling may detect a process switch, but does not actually perform it
		signalSemaphore(Pointers.TimingSemaphore);
	}
	// else requested delay was negative - we allow this to clear down the existing timer

#ifdef _DEBUG
	if (newProcessWaiting())
	{
		ASSERT(m_oteNewProcess->m_oteClass == Pointers.ClassProcess);
		ProcessOTE* activeProcess = scheduler()->m_activeProcess;

		TRACESTREAM << "signalAtTick: Caused process switch to " << m_oteNewProcess
			<< endl << "\t\tfrom " << activeProcess << endl
			<< "\tasync signals " << m_qAsyncSignals.isEmpty() << ')' << endl;
	}
#endif

	// Delay could already have fired
	CheckProcessSwitch();

	return primitiveSuccess(0);
}