Beispiel #1
0
BOOL __fastcall Interpreter::primitiveHookWindowCreate()
{
	Oop argPointer = stackTop();
	OTE* underConstruction = m_oteUnderConstruction;
	OTE* receiverPointer = reinterpret_cast<OTE*>(stackValue(1));

	if (!underConstruction->isNil() && underConstruction != receiverPointer)
	{
		// Hooked by another window - fail the primitive
		return primitiveFailureWith(1, underConstruction);
	}


	if (argPointer == Oop(Pointers.True))
	{
		// Hooking

		if (underConstruction != receiverPointer)
		{
			ASSERT(underConstruction->isNil());
			m_oteUnderConstruction= receiverPointer;
			receiverPointer->countUp();
		}
	}
	else
	{
		if (argPointer == Oop(Pointers.False))
		{
			// Unhooking
			if (underConstruction == receiverPointer)
			{
				tracelock lock(TRACESTREAM);
				TRACESTREAM << "WARNING: Unhooking create for " << hex << underConstruction << " before HCBT_CREATEWND" << endl;
				ObjectMemory::nilOutPointer(m_oteUnderConstruction);
			}
			else
				ASSERT(underConstruction->isNil());
		}
		else
			return primitiveFailureWith(0, argPointer);	// Invalid argument
	}

	popStack();
	return TRUE;
}
Beispiel #2
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);
}