source: trunk/src/quartz/sysclock.c@ 6952

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

Wine 20011004 resync

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