Merge freeldr from amd64 branch:
[reactos.git] / reactos / lib / drivers / sound / mmebuddy / thread.c
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 <windows.h>
12 #include <mmsystem.h>
13 #include <mmddk.h>
14 #include <ntddsnd.h>
15 #include <mmebuddy.h>
16
17 DWORD WINAPI
18 SoundThreadMain(
19 IN LPVOID lpParameter OPTIONAL)
20 {
21 PSOUND_THREAD Thread = (PSOUND_THREAD) lpParameter;
22
23 SND_TRACE(L"SoundThread running :)\n");
24
25 /* Callers will wait for us to be ready */
26 Thread->Running = TRUE;
27 SetEvent(Thread->Events.Ready);
28
29 while ( Thread->Running )
30 {
31 DWORD WaitResult;
32
33 /* Wait for a request, or an I/O completion */
34 WaitResult = WaitForSingleObjectEx(Thread->Events.Request, INFINITE, TRUE);
35 SND_TRACE(L"SoundThread - Came out of waiting\n");
36
37 if ( WaitResult == WAIT_OBJECT_0 )
38 {
39 SND_TRACE(L"SoundThread - Processing request\n");
40
41 if ( Thread->Request.Handler )
42 {
43 Thread->Request.Result = Thread->Request.Handler(Thread->Request.SoundDeviceInstance,
44 Thread->Request.Parameter);
45 }
46 else
47 {
48 Thread->Request.Result = MMSYSERR_ERROR;
49 }
50
51 /* Announce completion of the request */
52 SetEvent(Thread->Events.Done);
53 /* Accept new requests */
54 SetEvent(Thread->Events.Ready);
55 }
56 else if ( WaitResult == WAIT_IO_COMPLETION )
57 {
58 SND_TRACE(L"SoundThread - Processing IO completion\n");
59 /* TODO */
60 }
61 else
62 {
63 /* This should not happen! */
64 SND_ASSERT(FALSE);
65 }
66
67 }
68
69 return 0;
70 }
71
72 MMRESULT
73 CreateSoundThreadEvents(
74 OUT HANDLE* ReadyEvent,
75 OUT HANDLE* RequestEvent,
76 OUT HANDLE* DoneEvent)
77 {
78 BOOL ok;
79
80 VALIDATE_MMSYS_PARAMETER( ReadyEvent );
81 VALIDATE_MMSYS_PARAMETER( RequestEvent );
82 VALIDATE_MMSYS_PARAMETER( DoneEvent );
83
84 SND_TRACE(L"Creating thread events\n");
85
86 /* Initialise these so we can identify them upon failure */
87 *ReadyEvent = *RequestEvent = *DoneEvent = INVALID_HANDLE_VALUE;
88
89 ok = (*ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
90 ok &= (*RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
91 ok &= (*DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
92
93 /* If something went wrong, clean up */
94 if ( ! ok )
95 {
96 if ( *ReadyEvent != INVALID_HANDLE_VALUE )
97 CloseHandle(*ReadyEvent);
98
99 if ( *RequestEvent != INVALID_HANDLE_VALUE )
100 CloseHandle(*RequestEvent);
101
102 if ( *DoneEvent != INVALID_HANDLE_VALUE )
103 CloseHandle(*DoneEvent);
104
105 return MMSYSERR_NOMEM;
106 }
107
108 return MMSYSERR_NOERROR;
109 }
110
111 MMRESULT
112 DestroySoundThreadEvents(
113 IN HANDLE ReadyEvent,
114 IN HANDLE RequestEvent,
115 IN HANDLE DoneEvent)
116 {
117 VALIDATE_MMSYS_PARAMETER( ReadyEvent != INVALID_HANDLE_VALUE );
118 VALIDATE_MMSYS_PARAMETER( RequestEvent != INVALID_HANDLE_VALUE );
119 VALIDATE_MMSYS_PARAMETER( DoneEvent != INVALID_HANDLE_VALUE );
120
121 SND_TRACE(L"Destroying thread events\n");
122
123 CloseHandle(ReadyEvent);
124 CloseHandle(RequestEvent);
125 CloseHandle(DoneEvent);
126
127 return MMSYSERR_NOERROR;
128 }
129
130 MMRESULT
131 CreateSoundThread(
132 OUT PSOUND_THREAD* Thread)
133 {
134 MMRESULT Result;
135 PSOUND_THREAD NewThread;
136
137 VALIDATE_MMSYS_PARAMETER( Thread );
138
139 NewThread = AllocateStruct(SOUND_THREAD);
140 if ( ! NewThread )
141 return MMSYSERR_NOMEM;
142
143 /* Prepare the events we'll be using to sync. everything */
144 Result = CreateSoundThreadEvents(&NewThread->Events.Ready,
145 &NewThread->Events.Request,
146 &NewThread->Events.Done);
147
148 if ( ! MMSUCCESS(Result) )
149 {
150 FreeMemory(NewThread);
151 return TranslateInternalMmResult(Result);
152 }
153
154 SND_TRACE(L"Creating a sound thread\n");
155 NewThread->Handle = CreateThread(NULL,
156 0,
157 &SoundThreadMain,
158 (LPVOID) NewThread,
159 CREATE_SUSPENDED,
160 NULL);
161
162 /* Something went wrong, bail out! */
163 if ( NewThread->Handle == INVALID_HANDLE_VALUE )
164 {
165 SND_ERR(L"Sound thread creation failed!\n");
166 DestroySoundThreadEvents(NewThread->Events.Ready,
167 NewThread->Events.Request,
168 NewThread->Events.Done);
169
170 FreeMemory(NewThread);
171
172 return Win32ErrorToMmResult(GetLastError());
173 }
174
175 /* Wake the thread up */
176 if ( ResumeThread(NewThread->Handle) == -1 )
177 {
178 SND_ERR(L"Failed to resume thread!\n");
179 CloseHandle(NewThread->Handle);
180 DestroySoundThreadEvents(NewThread->Events.Ready,
181 NewThread->Events.Request,
182 NewThread->Events.Done);
183
184 FreeMemory(NewThread);
185 return Win32ErrorToMmResult(GetLastError());
186 }
187
188 /* If all is well we can now give the thread to the caller */
189 *Thread = NewThread;
190 return MMSYSERR_NOERROR;
191 }
192
193 MMRESULT
194 DestroySoundThread(
195 IN PSOUND_THREAD Thread)
196 {
197 VALIDATE_MMSYS_PARAMETER( Thread );
198 SND_TRACE(L"Terminating sound thread\n");
199 Thread->Running = FALSE;
200 /* TODO: Implement me! Wait for thread to have finished? */
201 return MMSYSERR_NOTSUPPORTED;
202 }
203
204 MMRESULT
205 CallSoundThread(
206 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
207 IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
208 IN PVOID Parameter OPTIONAL)
209 {
210 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
211 VALIDATE_MMSYS_PARAMETER( RequestHandler );
212
213 /* TODO: Don't call this directly? */
214 PSOUND_THREAD Thread = SoundDeviceInstance->Thread;
215
216 SND_TRACE(L"Waiting for READY event\n");
217 WaitForSingleObject(Thread->Events.Ready, INFINITE);
218
219 Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
220 Thread->Request.Handler = RequestHandler;
221 Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
222 Thread->Request.Parameter = Parameter;
223
224 /* Notify the thread it has work to do */
225 SND_TRACE(L"Setting REQUEST event\n");
226 SetEvent(Thread->Events.Request);
227
228 /* Wait for the work to be done */
229 SND_TRACE(L"Waiting for DONE event\n");
230 WaitForSingleObject(Thread->Events.Done, INFINITE);
231
232 return Thread->Request.Result;
233 }