1 /* 2 * PROJECT: ReactOS Sound System "MME Buddy" Library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: lib/drivers/sound/mmebuddy/thread.c 5 * 6 * PURPOSE: Multimedia thread management 7 * 8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) 9 */ 10 11 #include "precomp.h" 12 13 DWORD WINAPI 14 SoundThreadMain( 15 IN LPVOID lpParameter OPTIONAL) 16 { 17 PSOUND_THREAD Thread = (PSOUND_THREAD) lpParameter; 18 19 SND_TRACE(L"SoundThread running :)\n"); 20 21 /* Callers will wait for us to be ready */ 22 Thread->Running = TRUE; 23 SetEvent(Thread->Events.Ready); 24 25 while ( Thread->Running ) 26 { 27 DWORD WaitResult; 28 29 /* Wait for a request, or an I/O completion */ 30 WaitResult = WaitForSingleObjectEx(Thread->Events.Request, INFINITE, TRUE); 31 SND_TRACE(L"SoundThread - Came out of waiting\n"); 32 33 if ( WaitResult == WAIT_OBJECT_0 ) 34 { 35 SND_TRACE(L"SoundThread - Processing request\n"); 36 37 if ( Thread->Request.Handler ) 38 { 39 Thread->Request.Result = Thread->Request.Handler(Thread->Request.SoundDeviceInstance, 40 Thread->Request.Parameter); 41 } 42 else 43 { 44 Thread->Request.Result = MMSYSERR_ERROR; 45 } 46 47 /* Announce completion of the request */ 48 SetEvent(Thread->Events.Done); 49 /* Accept new requests */ 50 SetEvent(Thread->Events.Ready); 51 } 52 else if ( WaitResult == WAIT_IO_COMPLETION ) 53 { 54 SND_TRACE(L"SoundThread - Processing IO completion\n"); 55 /* TODO? What do we do here? Stream stuff? */ 56 } 57 else 58 { 59 /* This should not happen! */ 60 SND_ASSERT(FALSE); 61 } 62 63 } 64 65 SND_TRACE(L"Sound thread terminated\n"); 66 67 return 0; 68 } 69 70 MMRESULT 71 CallSoundThread( 72 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 73 IN SOUND_THREAD_REQUEST_HANDLER RequestHandler, 74 IN PVOID Parameter OPTIONAL) 75 { 76 PSOUND_THREAD Thread; 77 78 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 79 VALIDATE_MMSYS_PARAMETER( RequestHandler ); 80 81 Thread = SoundDeviceInstance->Thread; 82 83 SND_TRACE(L"Waiting for READY event\n"); 84 WaitForSingleObject(Thread->Events.Ready, INFINITE); 85 86 Thread->Request.Result = MMSYSERR_NOTSUPPORTED; 87 Thread->Request.Handler = RequestHandler; 88 Thread->Request.SoundDeviceInstance = SoundDeviceInstance; 89 Thread->Request.Parameter = Parameter; 90 91 /* Notify the thread it has work to do */ 92 SND_TRACE(L"Setting REQUEST event\n"); 93 SetEvent(Thread->Events.Request); 94 95 /* Wait for the work to be done */ 96 SND_TRACE(L"Waiting for DONE event\n"); 97 WaitForSingleObject(Thread->Events.Done, INFINITE); 98 99 return Thread->Request.Result; 100 } 101 102 103 MMRESULT 104 SoundThreadTerminator( 105 IN PSOUND_DEVICE_INSTANCE Instance, 106 IN PVOID Parameter) 107 { 108 PSOUND_THREAD Thread = (PSOUND_THREAD) Parameter; 109 110 SND_TRACE(L"Sound thread terminator routine called\n"); 111 SND_ASSERT( Thread ); 112 113 Thread->Running = FALSE; 114 115 return MMSYSERR_NOERROR; 116 } 117 118 MMRESULT 119 TerminateSoundThread( 120 IN PSOUND_THREAD Thread) 121 { 122 DWORD WaitResult; 123 124 SND_ASSERT( Thread ); 125 126 SND_TRACE(L"Waiting for READY event\n"); 127 WaitForSingleObject(Thread->Events.Ready, INFINITE); 128 129 Thread->Request.Result = MMSYSERR_NOTSUPPORTED; 130 Thread->Request.Handler = SoundThreadTerminator; 131 Thread->Request.SoundDeviceInstance = NULL; 132 Thread->Request.Parameter = (PVOID) Thread; 133 134 /* Notify the thread it has work to do */ 135 SND_TRACE(L"Setting REQUEST event\n"); 136 SetEvent(Thread->Events.Request); 137 138 /* Wait for the work to be done */ 139 SND_TRACE(L"Waiting for DONE event\n"); 140 WaitForSingleObject(Thread->Events.Done, INFINITE); 141 142 /* Wait for the thread to actually end */ 143 WaitResult = WaitForSingleObject(Thread->Handle, INFINITE); 144 SND_ASSERT( WaitResult == WAIT_OBJECT_0 ); 145 146 return MMSYSERR_NOERROR; 147 } 148 149 150 MMRESULT 151 CreateSoundThreadEvents( 152 OUT HANDLE* ReadyEvent, 153 OUT HANDLE* RequestEvent, 154 OUT HANDLE* DoneEvent) 155 { 156 BOOL ok; 157 158 VALIDATE_MMSYS_PARAMETER( ReadyEvent ); 159 VALIDATE_MMSYS_PARAMETER( RequestEvent ); 160 VALIDATE_MMSYS_PARAMETER( DoneEvent ); 161 162 SND_TRACE(L"Creating thread events\n"); 163 164 /* Initialise these so we can identify them upon failure */ 165 *ReadyEvent = *RequestEvent = *DoneEvent = INVALID_HANDLE_VALUE; 166 167 ok = (*ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; 168 ok &= (*RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; 169 ok &= (*DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE; 170 171 /* If something went wrong, clean up */ 172 if ( ! ok ) 173 { 174 if ( *ReadyEvent != INVALID_HANDLE_VALUE ) 175 CloseHandle(*ReadyEvent); 176 177 if ( *RequestEvent != INVALID_HANDLE_VALUE ) 178 CloseHandle(*RequestEvent); 179 180 if ( *DoneEvent != INVALID_HANDLE_VALUE ) 181 CloseHandle(*DoneEvent); 182 183 return MMSYSERR_NOMEM; 184 } 185 186 return MMSYSERR_NOERROR; 187 } 188 189 MMRESULT 190 DestroySoundThreadEvents( 191 IN HANDLE ReadyEvent, 192 IN HANDLE RequestEvent, 193 IN HANDLE DoneEvent) 194 { 195 VALIDATE_MMSYS_PARAMETER( ReadyEvent != INVALID_HANDLE_VALUE ); 196 VALIDATE_MMSYS_PARAMETER( RequestEvent != INVALID_HANDLE_VALUE ); 197 VALIDATE_MMSYS_PARAMETER( DoneEvent != INVALID_HANDLE_VALUE ); 198 199 SND_TRACE(L"Destroying thread events\n"); 200 201 CloseHandle(ReadyEvent); 202 CloseHandle(RequestEvent); 203 CloseHandle(DoneEvent); 204 205 return MMSYSERR_NOERROR; 206 } 207 208 MMRESULT 209 CreateSoundThread( 210 OUT PSOUND_THREAD* Thread) 211 { 212 MMRESULT Result; 213 PSOUND_THREAD NewThread; 214 215 VALIDATE_MMSYS_PARAMETER( Thread ); 216 217 NewThread = AllocateStruct(SOUND_THREAD); 218 if ( ! NewThread ) 219 return MMSYSERR_NOMEM; 220 221 /* Prepare the events we'll be using to sync. everything */ 222 Result = CreateSoundThreadEvents(&NewThread->Events.Ready, 223 &NewThread->Events.Request, 224 &NewThread->Events.Done); 225 226 if ( ! MMSUCCESS(Result) ) 227 { 228 FreeMemory(NewThread); 229 return TranslateInternalMmResult(Result); 230 } 231 232 SND_TRACE(L"Creating a sound thread\n"); 233 NewThread->Handle = CreateThread(NULL, 234 0, 235 &SoundThreadMain, 236 (LPVOID) NewThread, 237 CREATE_SUSPENDED, 238 NULL); 239 240 /* Something went wrong, bail out! */ 241 if ( NewThread->Handle == INVALID_HANDLE_VALUE ) 242 { 243 SND_ERR(L"Sound thread creation failed!\n"); 244 DestroySoundThreadEvents(NewThread->Events.Ready, 245 NewThread->Events.Request, 246 NewThread->Events.Done); 247 248 FreeMemory(NewThread); 249 250 return Win32ErrorToMmResult(GetLastError()); 251 } 252 253 /* Wake the thread up */ 254 if ( ResumeThread(NewThread->Handle) == -1 ) 255 { 256 SND_ERR(L"Failed to resume thread!\n"); 257 CloseHandle(NewThread->Handle); 258 DestroySoundThreadEvents(NewThread->Events.Ready, 259 NewThread->Events.Request, 260 NewThread->Events.Done); 261 262 FreeMemory(NewThread); 263 return Win32ErrorToMmResult(GetLastError()); 264 } 265 266 /* If all is well we can now give the thread to the caller */ 267 *Thread = NewThread; 268 return MMSYSERR_NOERROR; 269 } 270 271 MMRESULT 272 DestroySoundThread( 273 IN PSOUND_THREAD Thread) 274 { 275 VALIDATE_MMSYS_PARAMETER( Thread ); 276 SND_ASSERT( Thread->Handle != INVALID_HANDLE_VALUE ); 277 278 SND_TRACE(L"Terminating sound thread\n"); 279 280 /* Tell the thread to terminate itself */ 281 TerminateSoundThread(Thread); 282 283 SND_TRACE(L"Sound thread terminated, performing cleanup of thread resources\n"); 284 285 CloseHandle(Thread->Handle); /* Is this needed? */ 286 Thread->Handle = INVALID_HANDLE_VALUE; 287 288 DestroySoundThreadEvents(Thread->Events.Ready, 289 Thread->Events.Request, 290 Thread->Events.Done); 291 292 /* Wipe and free the memory used for the thread */ 293 ZeroMemory(Thread, sizeof(SOUND_THREAD)); 294 FreeMemory(Thread); 295 296 SND_TRACE(L"Finished thread cleanup\n"); 297 298 return MMSYSERR_NOERROR; 299 } 300 301