Ejemplo n.º 1
0
// Callback proc for MM timers
// N.B. This routine is called from a separate thread (in Win32), rather than in
// interrupt time, but careful coding is still important. The recommended 
// list of routines is limited to:
//		EnterCriticalSection	ReleaseSemaphore
//		LeaveCriticalSection	SetEvent
//		timeGetSystemTime		timeGetTime
//		OutputDebugString		timeKillEvent
//		PostMessage				timeSetEvent
//
// "If a Win32 low-level audio callback [we are using mm timers here] shares data 
// with other code, a Critical Section or similar mutual exclusion mechanism should 
// be used to protect the integrity of the data".
// Access to the asynchronous semaphore array is protected by a critical section
// in the asynchronousSignal and CheckProcessSwitch routines. We don't really care
// that much about the timerID
void CALLBACK Interpreter::TimeProc(UINT uID, UINT /*uMsg*/, DWORD /*dwUser*/, DWORD /*dw1*/, DWORD /*dw2*/)
{
	// Avoid firing a timer which has been cancelled (or is about to be cancelled!)
	// We use an InterlockedExchange() to set the value to 0 so that the main thread
	// can recognise that the timer has fired without race conditions

	if (_InterlockedExchange(reinterpret_cast<SHAREDLONG*>(&timerID), 0) != 0)
	{
		// If not previously killed (which is very unlikely except in certain exceptional
		// circumstances where the timer is killed at the exact moment it is about to fire)
		// then go ahead and signal the semaphore and the wakeup event

		// We mustn't access Pointers from an async thread when object memory is compacting
		// as the Pointer will be wrong
		GrabAsyncProtect();

		SemaphoreOTE* timerSemaphore = Pointers.TimingSemaphore;
		HARDASSERT(!ObjectMemoryIsIntegerObject(timerSemaphore));
		HARDASSERT(!timerSemaphore->isFree());
		HARDASSERT(timerSemaphore->m_oteClass == Pointers.ClassSemaphore);

		// Asynchronously signal the required semaphore asynchronously, which will be detected
		// in sync. with the dispatching of byte codes, and properly signalled
		asynchronousSignalNoProtect(timerSemaphore);
		// Signal the timing Event, in case the idle process has put the VM to sleep
		SetWakeupEvent();

		RelinquishAsyncProtect();
	}
	else
		// An old timer (which should have been cancelled) has fired
		trace("Old timer %d fired, current %d\n", uID, timerID);
}
Ejemplo n.º 2
0
// Queue an APC to the main interpreter thread
bool Interpreter::QueueAPC(PAPCFUNC pfnAPC, DWORD dwClosure)
{
	HANDLE hMain = MainThreadHandle();
	if (hMain && ::QueueUserAPC(pfnAPC, hMain, dwClosure))
	{
		InterlockedIncrement(&m_nAPCsPending);

		// The async pending flag is modified in a thread safe manner
		NotifyAsyncPending();

		if (!bIsNT)
			SetWakeupEvent();

		return true;
	}
	else
		return false;
}
Ejemplo n.º 3
0
bool CWaveDevice::InternalOpen()
//------------------------------
{
	MPT_TRACE();
	if(m_Settings.InputChannels > 0)
	{
		return false;
	}
	WAVEFORMATEXTENSIBLE wfext;
	if(!FillWaveFormatExtensible(wfext, m_Settings))
	{
		return false;
	}
	WAVEFORMATEX *pwfx = &wfext.Format;
	UINT nWaveDev = GetDeviceIndex();
	nWaveDev = (nWaveDev > 0) ? nWaveDev - 1 : WAVE_MAPPER;
	m_ThreadWakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if(m_ThreadWakeupEvent == INVALID_HANDLE_VALUE)
	{
		InternalClose();
		return false;
	}
	m_Failed = false;
	m_DriverBugs = 0;
	m_hWaveOut = NULL;
	if(waveOutOpen(&m_hWaveOut, nWaveDev, pwfx, (DWORD_PTR)WaveOutCallBack, (DWORD_PTR)this, CALLBACK_FUNCTION | (m_Settings.ExclusiveMode ? WAVE_FORMAT_DIRECT : 0)) != MMSYSERR_NOERROR)
	{
		InternalClose();
		return false;
	}
	if(waveOutPause(m_hWaveOut) != MMSYSERR_NOERROR)
	{
		InternalClose();
		return false;
	}
	m_nWaveBufferSize = Util::Round<int32>(m_Settings.UpdateInterval * pwfx->nAvgBytesPerSec);
	m_nWaveBufferSize = Util::AlignUp<uint32>(m_nWaveBufferSize, pwfx->nBlockAlign);
	m_nWaveBufferSize = mpt::clamp(m_nWaveBufferSize, static_cast<uint32>(WAVEOUT_MINBUFFERFRAMECOUNT * pwfx->nBlockAlign), static_cast<uint32>(Util::AlignDown<uint32>(WAVEOUT_MAXBUFFERSIZE, pwfx->nBlockAlign)));
	std::size_t numBuffers = Util::Round<int32>(m_Settings.Latency * pwfx->nAvgBytesPerSec / m_nWaveBufferSize);
	numBuffers = mpt::clamp(numBuffers, WAVEOUT_MINBUFFERS, WAVEOUT_MAXBUFFERS);
	m_nPreparedHeaders = 0;
	m_WaveBuffers.resize(numBuffers);
	m_WaveBuffersData.resize(numBuffers);
	for(std::size_t buf = 0; buf < numBuffers; ++buf)
	{
		MemsetZero(m_WaveBuffers[buf]);
		m_WaveBuffersData[buf].resize(m_nWaveBufferSize);
		m_WaveBuffers[buf].dwFlags = 0;
		m_WaveBuffers[buf].lpData = &m_WaveBuffersData[buf][0];
		m_WaveBuffers[buf].dwBufferLength = m_nWaveBufferSize;
		if(waveOutPrepareHeader(m_hWaveOut, &m_WaveBuffers[buf], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
		{
			break;
		}
		m_WaveBuffers[buf].dwFlags |= WHDR_DONE;
		m_nPreparedHeaders++;
	}
	if(!m_nPreparedHeaders)
	{
		InternalClose();
		return false;
	}
	m_nBuffersPending = 0;
	m_nWriteBuffer = 0;
	m_nDoneBuffer = 0;
	{
		MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
		MemsetZero(m_PositionLast);
		m_PositionWrappedCount = 0;
	}
	SetWakeupEvent(m_ThreadWakeupEvent);
	SetWakeupInterval(m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond());
	m_Flags.NeedsClippedFloat = GetSysInfo().WindowsVersion.IsAtLeast(mpt::Windows::Version::WinVista);
	return true;
}