source: trunk/src/quartz/irclock.c@ 6710

Last change on this file since 6710 was 6710, checked in by sandervl, 24 years ago

wine update

File size: 9.0 KB
Line 
1/*
2 * Implementation of CLSID_SystemClock.
3 *
4 * FIXME - not tested yet.
5 *
6 * hidenori@a2.ctktv.ne.jp
7 */
8
9#include "config.h"
10
11#include "windef.h"
12#include "winbase.h"
13#include "wingdi.h"
14#include "winuser.h"
15#include "winerror.h"
16#include "wine/obj_base.h"
17#include "strmif.h"
18#include "uuids.h"
19
20#include "debugtools.h"
21DEFAULT_DEBUG_CHANNEL(quartz);
22
23#include "quartz_private.h"
24#include "sysclock.h"
25
26
27#define QUARTZ_MSG_ADDTIMER (WM_APP+0)
28#define QUARTZ_MSG_REMOVETIMER (WM_APP+1)
29#define QUARTZ_MSG_EXITTHREAD (WM_APP+2)
30
31
32/****************************************************************************/
33
34static QUARTZ_TimerEntry* IReferenceClock_AllocTimerEntry(CSystemClock* This)
35{
36 QUARTZ_TimerEntry* pEntry;
37 DWORD dw;
38
39 pEntry = &This->m_timerEntries[0];
40 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
41 {
42 if ( pEntry->hEvent == (HANDLE)NULL )
43 return pEntry;
44 pEntry ++;
45 }
46
47 return NULL;
48}
49
50static QUARTZ_TimerEntry* IReferenceClock_SearchTimer(CSystemClock* This, DWORD dwAdvCookie)
51{
52 QUARTZ_TimerEntry* pEntry;
53 DWORD dw;
54
55 pEntry = &This->m_timerEntries[0];
56 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
57 {
58 if ( pEntry->hEvent != (HANDLE)NULL &&
59 pEntry->dwAdvCookie == dwAdvCookie )
60 return pEntry;
61 pEntry ++;
62 }
63
64 return NULL;
65}
66
67static void IReferenceClock_OnTimerUpdated(CSystemClock* This)
68{
69 QUARTZ_TimerEntry* pEntry;
70 REFERENCE_TIME rtCur;
71 REFERENCE_TIME rtSignal;
72 REFERENCE_TIME rtCount;
73 HRESULT hr;
74 LONG lCount;
75 DWORD dw;
76
77 hr = IReferenceClock_GetTime((IReferenceClock*)(&This->refclk),&rtCur);
78 if ( hr != NOERROR )
79 return;
80
81 pEntry = &This->m_timerEntries[0];
82 for ( dw = 0; dw < WINE_QUARTZ_SYSCLOCK_TIMER_MAX; dw++ )
83 {
84 if ( pEntry->hEvent != (HANDLE)NULL )
85 {
86 rtSignal = pEntry->rtStart + pEntry->rtInterval;
87 if ( rtCur >= rtSignal )
88 {
89 if ( pEntry->fPeriodic )
90 {
91 rtCount = ((rtCur - pEntry->rtStart) / pEntry->rtInterval);
92 lCount = ( rtCount > (REFERENCE_TIME)0x7fffffff ) ?
93 (LONG)0x7fffffff : (LONG)rtCount;
94 if ( !ReleaseSemaphore( pEntry->hEvent, lCount, NULL ) )
95 {
96 while ( lCount > 0 )
97 {
98 if ( !ReleaseSemaphore( pEntry->hEvent, 1, NULL ) )
99 break;
100 }
101 }
102 }
103 else
104 {
105 SetEvent( pEntry->hEvent );
106 pEntry->hEvent = (HANDLE)NULL;
107 }
108 }
109 }
110 pEntry ++;
111 }
112}
113
114static
115DWORD WINAPI IReferenceClock_TimerEntry( LPVOID lpvParam )
116{
117 CSystemClock* This = (CSystemClock*)lpvParam;
118 MSG msg;
119 DWORD dwRes;
120
121 /* initialize the message queue. */
122 PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE );
123 /* resume the owner thread. */
124 SetEvent( This->m_hEventInit );
125
126 /* message loop. */
127 while ( 1 )
128 {
129 dwRes = MsgWaitForMultipleObjects(
130 0, NULL, FALSE,
131 INFINITE, /* FIXME */
132 QS_ALLEVENTS );
133
134 EnterCriticalSection( &This->m_csClock );
135 IReferenceClock_OnTimerUpdated(This);
136 LeaveCriticalSection( &This->m_csClock );
137
138 while ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) )
139 {
140 if ( msg.message == WM_QUIT )
141 goto quitthread;
142
143 if ( msg.hwnd != (HWND)NULL )
144 {
145 TranslateMessage( &msg );
146 DispatchMessageA( &msg );
147 }
148 else
149 {
150 switch ( msg.message )
151 {
152 case QUARTZ_MSG_ADDTIMER:
153 case QUARTZ_MSG_REMOVETIMER:
154 break;
155 case QUARTZ_MSG_EXITTHREAD:
156 PostQuitMessage(0);
157 break;
158 default:
159 FIXME( "invalid message %04u\n", (unsigned)msg.message );
160 break;
161 }
162 }
163 }
164 }
165
166quitthread:
167 return 0;
168}
169
170/****************************************************************************/
171
172static HRESULT WINAPI
173IReferenceClock_fnQueryInterface(IReferenceClock* iface,REFIID riid,void** ppobj)
174{
175 CSystemClock_THIS(iface,refclk);
176
177 TRACE("(%p)->()\n",This);
178
179 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
180}
181
182static ULONG WINAPI
183IReferenceClock_fnAddRef(IReferenceClock* iface)
184{
185 CSystemClock_THIS(iface,refclk);
186
187 TRACE("(%p)->()\n",This);
188
189 return IUnknown_AddRef(This->unk.punkControl);
190}
191
192static ULONG WINAPI
193IReferenceClock_fnRelease(IReferenceClock* iface)
194{
195 CSystemClock_THIS(iface,refclk);
196
197 TRACE("(%p)->()\n",This);
198
199 return IUnknown_Release(This->unk.punkControl);
200}
201
202static HRESULT WINAPI
203IReferenceClock_fnGetTime(IReferenceClock* iface,REFERENCE_TIME* prtTime)
204{
205 CSystemClock_THIS(iface,refclk);
206 DWORD dwTimeCur;
207
208 TRACE( "(%p)->(%p)\n", This, prtTime );
209
210 if ( prtTime == NULL )
211 return E_POINTER;
212
213 EnterCriticalSection( &This->m_csClock );
214
215 dwTimeCur = GetTickCount();
216 This->m_rtLast += (REFERENCE_TIME)(DWORD)(dwTimeCur - This->m_dwTimeLast);
217
218 This->m_dwTimeLast = dwTimeCur;
219
220 *prtTime = This->m_dwTimeLast;
221
222 LeaveCriticalSection( &This->m_csClock );
223
224 return NOERROR;
225}
226
227static HRESULT WINAPI
228IReferenceClock_fnAdviseTime(IReferenceClock* iface,REFERENCE_TIME rtBase,REFERENCE_TIME rtStream,HEVENT hEvent,DWORD_PTR* pdwAdvCookie)
229{
230 CSystemClock_THIS(iface,refclk);
231 QUARTZ_TimerEntry* pEntry;
232 HRESULT hr;
233 REFERENCE_TIME rtCur;
234
235 TRACE( "(%p)->()\n", This );
236
237 if ( pdwAdvCookie == NULL )
238 return E_POINTER;
239 if ( hEvent == (HANDLE)NULL )
240 return E_INVALIDARG;
241
242 EnterCriticalSection( &This->m_csClock );
243
244 *pdwAdvCookie = (DWORD_PTR)(This->m_dwAdvCookieNext ++);
245
246 hr = IReferenceClock_GetTime(iface,&rtCur);
247 if ( hr != NOERROR )
248 goto err;
249 if ( rtCur >= (rtBase+rtStream) )
250 {
251 SetEvent(hEvent);
252 hr = NOERROR;
253 goto err;
254 }
255
256 pEntry = IReferenceClock_AllocTimerEntry(This);
257 if ( pEntry == NULL )
258 {
259 hr = E_FAIL;
260 goto err;
261 }
262
263 if ( !PostThreadMessageA(
264 This->m_idThreadTimer,
265 QUARTZ_MSG_ADDTIMER,
266 0, 0 ) )
267 {
268 hr = E_FAIL;
269 goto err;
270 }
271
272 pEntry->dwAdvCookie = *pdwAdvCookie;
273 pEntry->fPeriodic = FALSE;
274 pEntry->hEvent = hEvent;
275 pEntry->rtStart = rtBase;
276 pEntry->rtInterval = rtStream;
277
278 hr = NOERROR;
279err:
280 LeaveCriticalSection( &This->m_csClock );
281
282 return hr;
283}
284
285static HRESULT WINAPI
286IReferenceClock_fnAdvisePeriodic(IReferenceClock* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtPeriod,HSEMAPHORE hSemaphore,DWORD_PTR* pdwAdvCookie)
287{
288 CSystemClock_THIS(iface,refclk);
289 QUARTZ_TimerEntry* pEntry;
290 HRESULT hr;
291
292 TRACE( "(%p)->()\n", This );
293
294 if ( pdwAdvCookie == NULL )
295 return E_POINTER;
296 if ( hSemaphore == (HSEMAPHORE)NULL )
297 return E_INVALIDARG;
298
299 EnterCriticalSection( &This->m_csClock );
300
301 *pdwAdvCookie = (DWORD_PTR)(This->m_dwAdvCookieNext ++);
302
303 pEntry = IReferenceClock_AllocTimerEntry(This);
304 if ( pEntry == NULL )
305 {
306 hr = E_FAIL;
307 goto err;
308 }
309
310 if ( !PostThreadMessageA(
311 This->m_idThreadTimer,
312 QUARTZ_MSG_ADDTIMER,
313 0, 0 ) )
314 {
315 hr = E_FAIL;
316 goto err;
317 }
318
319 pEntry->dwAdvCookie = *pdwAdvCookie;
320 pEntry->fPeriodic = TRUE;
321 pEntry->hEvent = (HANDLE)hSemaphore;
322 pEntry->rtStart = rtStart;
323 pEntry->rtInterval = rtPeriod;
324
325 hr = NOERROR;
326err:
327 LeaveCriticalSection( &This->m_csClock );
328
329 return hr;
330}
331
332static HRESULT WINAPI
333IReferenceClock_fnUnadvise(IReferenceClock* iface,DWORD_PTR dwAdvCookie)
334{
335 CSystemClock_THIS(iface,refclk);
336 QUARTZ_TimerEntry* pEntry;
337
338 TRACE( "(%p)->(%lu)\n", This, (DWORD)dwAdvCookie );
339
340 EnterCriticalSection( &This->m_csClock );
341
342 pEntry = IReferenceClock_SearchTimer(This,(DWORD)dwAdvCookie);
343 if ( pEntry != NULL )
344 {
345 pEntry->hEvent = (HANDLE)NULL;
346 }
347
348 LeaveCriticalSection( &This->m_csClock );
349
350 return NOERROR;
351}
352
353static ICOM_VTABLE(IReferenceClock) irefclk =
354{
355 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
356 /* IUnknown fields */
357 IReferenceClock_fnQueryInterface,
358 IReferenceClock_fnAddRef,
359 IReferenceClock_fnRelease,
360 /* IReferenceClock fields */
361 IReferenceClock_fnGetTime,
362 IReferenceClock_fnAdviseTime,
363 IReferenceClock_fnAdvisePeriodic,
364 IReferenceClock_fnUnadvise,
365};
366
367
368HRESULT CSystemClock_InitIReferenceClock( CSystemClock* psc )
369{
370 HANDLE hEvents[2];
371
372 TRACE("(%p)\n",psc);
373 ICOM_VTBL(&psc->refclk) = &irefclk;
374
375 InitializeCriticalSection( &psc->m_csClock );
376 psc->m_dwTimeLast = GetTickCount();
377 psc->m_rtLast = (REFERENCE_TIME)0;
378 psc->m_hThreadTimer = (HANDLE)NULL;
379 psc->m_hEventInit = (HANDLE)NULL;
380 psc->m_idThreadTimer = 0;
381 psc->m_dwAdvCookieNext = 1;
382 ZeroMemory( psc->m_timerEntries, sizeof(psc->m_timerEntries) );
383
384 psc->m_hEventInit = CreateEventA( NULL, TRUE, FALSE, NULL );
385 if ( psc->m_hEventInit == (HANDLE)NULL )
386 goto err;
387
388 psc->m_hThreadTimer = CreateThread(
389 NULL, 0,
390 IReferenceClock_TimerEntry,
391 psc, 0, &psc->m_idThreadTimer );
392
393 if ( psc->m_hThreadTimer == (HANDLE)NULL )
394 {
395 CloseHandle( psc->m_hEventInit );
396 psc->m_hEventInit = (HANDLE)NULL;
397 goto err;
398 }
399
400 hEvents[0] = psc->m_hEventInit;
401 hEvents[1] = psc->m_hThreadTimer;
402 if ( WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE )
403 != WAIT_OBJECT_0 )
404 {
405 CloseHandle( psc->m_hEventInit );
406 psc->m_hEventInit = (HANDLE)NULL;
407 CloseHandle( psc->m_hThreadTimer );
408 psc->m_hThreadTimer = (HANDLE)NULL;
409 goto err;
410 }
411
412 return NOERROR;
413
414err:
415 DeleteCriticalSection( &psc->m_csClock );
416 return E_FAIL;
417}
418
419void CSystemClock_UninitIReferenceClock( CSystemClock* psc )
420{
421 TRACE("(%p)\n",psc);
422
423 if ( psc->m_hThreadTimer != (HANDLE)NULL )
424 {
425 if ( PostThreadMessageA(
426 psc->m_idThreadTimer,
427 QUARTZ_MSG_EXITTHREAD,
428 0, 0 ) )
429 {
430 WaitForSingleObject( psc->m_hThreadTimer, INFINITE );
431 }
432 CloseHandle( psc->m_hThreadTimer );
433 psc->m_hThreadTimer = (HANDLE)NULL;
434 }
435
436 DeleteCriticalSection( &psc->m_csClock );
437}
Note: See TracBrowser for help on using the repository browser.