/* * PROJECT: ReactOS Sound System "MME Buddy" Library * LICENSE: GPL - See COPYING in the top level directory * FILE: lib/drivers/sound/mmebuddy/thread.c * * PURPOSE: Multimedia thread management * * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) */ #include "precomp.h" DWORD WINAPI SoundThreadMain( IN LPVOID lpParameter OPTIONAL) { PSOUND_THREAD Thread = (PSOUND_THREAD) lpParameter; SND_TRACE(L"SoundThread running :)\n"); /* Callers will wait for us to be ready */ Thread->Running = TRUE; SetEvent(Thread->Events.Ready); while ( Thread->Running ) { DWORD WaitResult; /* Wait for a request, or an I/O completion */ WaitResult = WaitForSingleObjectEx(Thread->Events.Request, INFINITE, TRUE); SND_TRACE(L"SoundThread - Came out of waiting\n"); if ( WaitResult == WAIT_OBJECT_0 ) { SND_TRACE(L"SoundThread - Processing request\n"); if ( Thread->Request.Handler ) { Thread->Request.Result = Thread->Request.Handler(Thread->Request.SoundDeviceInstance, Thread->Request.Parameter); } else { Thread->Request.Result = MMSYSERR_ERROR; } /* Announce completion of the request */ SetEvent(Thread->Events.Done); /* Accept new requests */ SetEvent(Thread->Events.Ready); } else if ( WaitResult == WAIT_IO_COMPLETION ) { SND_TRACE(L"SoundThread - Processing IO completion\n"); /* TODO? What do we do here? Stream stuff? */ } else { /* This should not happen! */ SND_ASSERT(FALSE); } } SND_TRACE(L"Sound thread terminated\n"); return 0; } MMRESULT CallSoundThread( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN SOUND_THREAD_REQUEST_HANDLER RequestHandler, IN PVOID Parameter OPTIONAL) { PSOUND_THREAD Thread; VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); VALIDATE_MMSYS_PARAMETER( RequestHandler ); Thread = SoundDeviceInstance->Thread; SND_TRACE(L"Waiting for READY event\n"); WaitForSingleObject(Thread->Events.Ready, INFINITE); Thread->Request.Result = MMSYSERR_NOTSUPPORTED; Thread->Request.Handler = RequestHandler; Thread->Request.SoundDeviceInstance = SoundDeviceInstance; Thread->Request.Parameter = Parameter; /* Notify the thread it has work to do */ SND_TRACE(L"Setting REQUEST event\n"); SetEvent(Thread->Events.Request); /* Wait for the work to be done */ SND_TRACE(L"Waiting for DONE event\n"); WaitForSingleObject(Thread->Events.Done, INFINITE); return Thread->Request.Result; } MMRESULT SoundThreadTerminator( IN PSOUND_DEVICE_INSTANCE Instance, IN PVOID Parameter) { PSOUND_THREAD Thread = (PSOUND_THREAD) Parameter; SND_TRACE(L"Sound thread terminator routine called\n"); SND_ASSERT( Thread ); Thread->Running = FALSE; return MMSYSERR_NOERROR; } MMRESULT TerminateSoundThread( IN PSOUND_THREAD Thread) { DWORD WaitResult; SND_ASSERT( Thread ); SND_TRACE(L"Waiting for READY event\n"); WaitForSingleObject(Thread->Events.Ready, INFINITE); Thread->Request.Result = MMSYSERR_NOTSUPPORTED; Thread->Request.Handler = SoundThreadTerminator; Thread->Request.SoundDeviceInstance = NULL; Thread->Request.Parameter = (PVOID) Thread; /* Notify the thread it has work to do */ SND_TRACE(L"Setting REQUEST event\n"); SetEvent(Thread->Events.Request); /* Wait for the work to be done */ SND_TRACE(L"Waiting for DONE event\n"); WaitForSingleObject(Thread->Events.Done, INFINITE); /* Wait for the thread to actually end */ WaitResult = WaitForSingleObject(Thread->Handle, INFINITE); SND_ASSERT( WaitResult == WAIT_OBJECT_0 ); return MMSYSERR_NOERROR; } MMRESULT CreateSoundThreadEvents( OUT HANDLE* ReadyEvent, OUT HANDLE* RequestEvent, OUT HANDLE* DoneEvent) { BOOL ok; VALIDATE_MMSYS_PARAMETER( ReadyEvent ); VALIDATE_MMSYS_PARAMETER( RequestEvent ); VALIDATE_MMSYS_PARAMETER( DoneEvent ); SND_TRACE(L"Creating thread events\n"); /* Initialise these so we can identify them upon failure */ *ReadyEvent = *RequestEvent = *DoneEvent = INVALID_HANDLE_VALUE; ok = (*ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; ok &= (*RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; ok &= (*DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; /* If something went wrong, clean up */ if ( ! ok ) { if ( *ReadyEvent != INVALID_HANDLE_VALUE ) CloseHandle(*ReadyEvent); if ( *RequestEvent != INVALID_HANDLE_VALUE ) CloseHandle(*RequestEvent); if ( *DoneEvent != INVALID_HANDLE_VALUE ) CloseHandle(*DoneEvent); return MMSYSERR_NOMEM; } return MMSYSERR_NOERROR; } MMRESULT DestroySoundThreadEvents( IN HANDLE ReadyEvent, IN HANDLE RequestEvent, IN HANDLE DoneEvent) { VALIDATE_MMSYS_PARAMETER( ReadyEvent != INVALID_HANDLE_VALUE ); VALIDATE_MMSYS_PARAMETER( RequestEvent != INVALID_HANDLE_VALUE ); VALIDATE_MMSYS_PARAMETER( DoneEvent != INVALID_HANDLE_VALUE ); SND_TRACE(L"Destroying thread events\n"); CloseHandle(ReadyEvent); CloseHandle(RequestEvent); CloseHandle(DoneEvent); return MMSYSERR_NOERROR; } MMRESULT CreateSoundThread( OUT PSOUND_THREAD* Thread) { MMRESULT Result; PSOUND_THREAD NewThread; VALIDATE_MMSYS_PARAMETER( Thread ); NewThread = AllocateStruct(SOUND_THREAD); if ( ! NewThread ) return MMSYSERR_NOMEM; /* Prepare the events we'll be using to sync. everything */ Result = CreateSoundThreadEvents(&NewThread->Events.Ready, &NewThread->Events.Request, &NewThread->Events.Done); if ( ! MMSUCCESS(Result) ) { FreeMemory(NewThread); return TranslateInternalMmResult(Result); } SND_TRACE(L"Creating a sound thread\n"); NewThread->Handle = CreateThread(NULL, 0, &SoundThreadMain, (LPVOID) NewThread, CREATE_SUSPENDED, NULL); /* Something went wrong, bail out! */ if ( NewThread->Handle == INVALID_HANDLE_VALUE ) { SND_ERR(L"Sound thread creation failed!\n"); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* Wake the thread up */ if ( ResumeThread(NewThread->Handle) == -1 ) { SND_ERR(L"Failed to resume thread!\n"); CloseHandle(NewThread->Handle); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* If all is well we can now give the thread to the caller */ *Thread = NewThread; return MMSYSERR_NOERROR; } MMRESULT DestroySoundThread( IN PSOUND_THREAD Thread) { VALIDATE_MMSYS_PARAMETER( Thread ); SND_ASSERT( Thread->Handle != INVALID_HANDLE_VALUE ); SND_TRACE(L"Terminating sound thread\n"); /* Tell the thread to terminate itself */ TerminateSoundThread(Thread); SND_TRACE(L"Sound thread terminated, performing cleanup of thread resources\n"); CloseHandle(Thread->Handle); /* Is this needed? */ Thread->Handle = INVALID_HANDLE_VALUE; DestroySoundThreadEvents(Thread->Events.Ready, Thread->Events.Request, Thread->Events.Done); /* Wipe and free the memory used for the thread */ ZeroMemory(Thread, sizeof(SOUND_THREAD)); FreeMemory(Thread); SND_TRACE(L"Finished thread cleanup\n"); return MMSYSERR_NOERROR; }