xref: /reactos/dll/directx/wine/quartz/systemclock.c (revision 83d28845)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Implementation of IReferenceClock
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2004 Raphael Junqueira
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21c2c66affSColin Finck #include "quartz_private.h"
22c2c66affSColin Finck 
23*83d28845SAmine Khaldi #include "wine/debug.h"
24*83d28845SAmine Khaldi #include "wine/unicode.h"
25*83d28845SAmine Khaldi #include <assert.h>
26*83d28845SAmine Khaldi 
27*83d28845SAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28*83d28845SAmine Khaldi 
29c2c66affSColin Finck typedef struct SystemClockAdviseEntry SystemClockAdviseEntry;
30c2c66affSColin Finck struct SystemClockAdviseEntry {
31c2c66affSColin Finck   SystemClockAdviseEntry* next;
32c2c66affSColin Finck   SystemClockAdviseEntry* prev;
33c2c66affSColin Finck 
34c2c66affSColin Finck   HANDLE           hEvent;
35c2c66affSColin Finck   REFERENCE_TIME   rtBaseTime;
36c2c66affSColin Finck   REFERENCE_TIME   rtIntervalTime;
37c2c66affSColin Finck };
38c2c66affSColin Finck 
39c2c66affSColin Finck typedef struct SystemClockImpl {
40c2c66affSColin Finck   IReferenceClock IReferenceClock_iface;
41c2c66affSColin Finck   LONG ref;
42c2c66affSColin Finck 
43c2c66affSColin Finck   /** IReferenceClock */
44c2c66affSColin Finck   HANDLE         adviseThread;
45c2c66affSColin Finck   DWORD          adviseThreadId;
46c2c66affSColin Finck   BOOL           adviseThreadActive;
47c2c66affSColin Finck   REFERENCE_TIME lastRefTime;
48c2c66affSColin Finck   DWORD	         lastTimeTickCount;
49c2c66affSColin Finck   CRITICAL_SECTION safe;
50c2c66affSColin Finck 
51c2c66affSColin Finck   SystemClockAdviseEntry* pSingleShotAdvise;
52c2c66affSColin Finck   SystemClockAdviseEntry* pPeriodicAdvise;
53c2c66affSColin Finck } SystemClockImpl;
54c2c66affSColin Finck 
impl_from_IReferenceClock(IReferenceClock * iface)55c2c66affSColin Finck static inline SystemClockImpl *impl_from_IReferenceClock(IReferenceClock *iface)
56c2c66affSColin Finck {
57c2c66affSColin Finck     return CONTAINING_RECORD(iface, SystemClockImpl, IReferenceClock_iface);
58c2c66affSColin Finck }
59c2c66affSColin Finck 
60c2c66affSColin Finck 
QUARTZ_RemoveAviseEntryFromQueue(SystemClockImpl * This,SystemClockAdviseEntry * pEntry)61c2c66affSColin Finck static void QUARTZ_RemoveAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry) {
62c2c66affSColin Finck   if (pEntry->prev) pEntry->prev->next = pEntry->next;
63c2c66affSColin Finck   if (pEntry->next) pEntry->next->prev = pEntry->prev;
64c2c66affSColin Finck   if (This->pSingleShotAdvise == pEntry) This->pSingleShotAdvise = pEntry->next;
65c2c66affSColin Finck   if (This->pPeriodicAdvise == pEntry)    This->pPeriodicAdvise = pEntry->next;
66c2c66affSColin Finck }
67c2c66affSColin Finck 
QUARTZ_InsertAviseEntryFromQueue(SystemClockImpl * This,SystemClockAdviseEntry * pEntry,SystemClockAdviseEntry ** pQueue)68c2c66affSColin Finck static void QUARTZ_InsertAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry, SystemClockAdviseEntry** pQueue) {
69c2c66affSColin Finck   SystemClockAdviseEntry* prev_it = NULL;
70c2c66affSColin Finck   SystemClockAdviseEntry* it = NULL;
71c2c66affSColin Finck   REFERENCE_TIME bornTime =  pEntry->rtBaseTime + pEntry->rtIntervalTime;
72c2c66affSColin Finck 
73c2c66affSColin Finck   for (it = *pQueue; NULL != it && (it->rtBaseTime + it->rtIntervalTime) < bornTime; it = it->next) {
74c2c66affSColin Finck     prev_it = it;
75c2c66affSColin Finck   }
76c2c66affSColin Finck   if (NULL == prev_it) {
77c2c66affSColin Finck     pEntry->prev = NULL;
78c2c66affSColin Finck     if (NULL != (*pQueue)) pEntry->next = (*pQueue)->next;
79c2c66affSColin Finck     /*assert( NULL == pEntry->next->prev );*/
80c2c66affSColin Finck     if (NULL != pEntry->next) pEntry->next->prev = pEntry;
81c2c66affSColin Finck     (*pQueue) = pEntry;
82c2c66affSColin Finck   } else {
83c2c66affSColin Finck     pEntry->prev = prev_it;
84c2c66affSColin Finck     pEntry->next = prev_it->next;
85c2c66affSColin Finck     prev_it->next = pEntry;
86c2c66affSColin Finck     if (NULL != pEntry->next) pEntry->next->prev = pEntry;
87c2c66affSColin Finck   }
88c2c66affSColin Finck }
89c2c66affSColin Finck 
90c2c66affSColin Finck #define MAX_REFTIME            (REFERENCE_TIME)(0x7FFFFFFFFFFFFFFF)
91c2c66affSColin Finck #define ADVISE_EXIT            (WM_APP + 0)
92c2c66affSColin Finck #define ADVISE_REMOVE          (WM_APP + 2)
93c2c66affSColin Finck #define ADVISE_ADD_SINGLESHOT  (WM_APP + 4)
94c2c66affSColin Finck #define ADVISE_ADD_PERIODIC    (WM_APP + 8)
95c2c66affSColin Finck 
SystemClockAdviseThread(LPVOID lpParam)96c2c66affSColin Finck static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) {
97c2c66affSColin Finck   SystemClockImpl* This = lpParam;
98c2c66affSColin Finck   DWORD timeOut = INFINITE;
99c2c66affSColin Finck   DWORD tmpTimeOut;
100c2c66affSColin Finck   MSG msg;
101c2c66affSColin Finck   HRESULT hr;
102c2c66affSColin Finck   REFERENCE_TIME curTime;
103c2c66affSColin Finck   SystemClockAdviseEntry* it = NULL;
104c2c66affSColin Finck 
105c2c66affSColin Finck   TRACE("(%p): Main Loop\n", This);
106c2c66affSColin Finck 
107c2c66affSColin Finck   while (TRUE) {
108c2c66affSColin Finck     if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
109c2c66affSColin Finck 
110c2c66affSColin Finck     EnterCriticalSection(&This->safe);
111c2c66affSColin Finck     /*timeOut = IReferenceClock_OnTimerUpdated(This); */
112c2c66affSColin Finck     hr = IReferenceClock_GetTime(&This->IReferenceClock_iface, &curTime);
113c2c66affSColin Finck     if (FAILED(hr)) {
114c2c66affSColin Finck       timeOut = INFINITE;
115c2c66affSColin Finck       goto outrefresh;
116c2c66affSColin Finck     }
117c2c66affSColin Finck 
118c2c66affSColin Finck     /** First SingleShots Advice: sorted list */
119c2c66affSColin Finck     it = This->pSingleShotAdvise;
120c2c66affSColin Finck     while ((NULL != it) && (it->rtBaseTime + it->rtIntervalTime) <= curTime) {
121c2c66affSColin Finck       SystemClockAdviseEntry* nextit = it->next;
122c2c66affSColin Finck       /** send event ... */
123c2c66affSColin Finck       SetEvent(it->hEvent);
124c2c66affSColin Finck       /** ... and Release it */
125c2c66affSColin Finck       QUARTZ_RemoveAviseEntryFromQueue(This, it);
126c2c66affSColin Finck       CoTaskMemFree(it);
127c2c66affSColin Finck       it = nextit;
128c2c66affSColin Finck     }
129c2c66affSColin Finck     if (NULL != it) timeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000;
130c2c66affSColin Finck     else timeOut = INFINITE;
131c2c66affSColin Finck 
132c2c66affSColin Finck     /** Now Periodics Advice: semi sorted list (sort cannot be used) */
133c2c66affSColin Finck     for (it = This->pPeriodicAdvise; NULL != it; it = it->next) {
134c2c66affSColin Finck       if (it->rtBaseTime <= curTime) {
135c2c66affSColin Finck 	DWORD nPeriods = (DWORD) ((curTime - it->rtBaseTime) / it->rtIntervalTime);
136c2c66affSColin Finck 	/** Release the semaphore ... */
137c2c66affSColin Finck 	ReleaseSemaphore(it->hEvent, nPeriods, NULL);
138c2c66affSColin Finck 	/** ... and refresh time */
139c2c66affSColin Finck 	it->rtBaseTime += nPeriods * it->rtIntervalTime;
140c2c66affSColin Finck 	/*assert( it->rtBaseTime + it->rtIntervalTime < curTime );*/
141c2c66affSColin Finck       }
142c2c66affSColin Finck       tmpTimeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000;
143c2c66affSColin Finck       if (timeOut > tmpTimeOut) timeOut = tmpTimeOut;
144c2c66affSColin Finck     }
145c2c66affSColin Finck 
146c2c66affSColin Finck outrefresh:
147c2c66affSColin Finck     LeaveCriticalSection(&This->safe);
148c2c66affSColin Finck 
149c2c66affSColin Finck     while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
150c2c66affSColin Finck       /** if hwnd we suppose that is a windows event ... */
151c2c66affSColin Finck       if  (NULL != msg.hwnd) {
152c2c66affSColin Finck 	TranslateMessage(&msg);
153c2c66affSColin Finck 	DispatchMessageW(&msg);
154c2c66affSColin Finck       } else {
155c2c66affSColin Finck 	switch (msg.message) {
156c2c66affSColin Finck 	case WM_QUIT:
157c2c66affSColin Finck 	case ADVISE_EXIT:
158c2c66affSColin Finck 	  goto outofthread;
159c2c66affSColin Finck 	case ADVISE_ADD_SINGLESHOT:
160c2c66affSColin Finck 	case ADVISE_ADD_PERIODIC:
161c2c66affSColin Finck 	  /** set timeout to 0 to do a rescan now */
162c2c66affSColin Finck 	  timeOut = 0;
163c2c66affSColin Finck 	  break;
164c2c66affSColin Finck 	case ADVISE_REMOVE:
165c2c66affSColin Finck 	  /** hmmmm what we can do here ... */
166c2c66affSColin Finck 	  timeOut = INFINITE;
167c2c66affSColin Finck 	  break;
168c2c66affSColin Finck 	default:
169c2c66affSColin Finck 	  ERR("Unhandled message %u. Critical Path\n", msg.message);
170c2c66affSColin Finck 	  break;
171c2c66affSColin Finck 	}
172c2c66affSColin Finck       }
173c2c66affSColin Finck     }
174c2c66affSColin Finck   }
175c2c66affSColin Finck 
176c2c66affSColin Finck outofthread:
177c2c66affSColin Finck   TRACE("(%p): Exiting\n", This);
178c2c66affSColin Finck   return 0;
179c2c66affSColin Finck }
180c2c66affSColin Finck /*static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) { */
181c2c66affSColin Finck 
SystemClockPostMessageToAdviseThread(SystemClockImpl * This,UINT iMsg)182c2c66affSColin Finck static BOOL SystemClockPostMessageToAdviseThread(SystemClockImpl* This, UINT iMsg) {
183c2c66affSColin Finck   if (FALSE == This->adviseThreadActive) {
184c2c66affSColin Finck     BOOL res;
185c2c66affSColin Finck     This->adviseThread = CreateThread(NULL, 0, SystemClockAdviseThread, This, 0, &This->adviseThreadId);
186c2c66affSColin Finck     if (NULL == This->adviseThread) return FALSE;
187c2c66affSColin Finck     SetThreadPriority(This->adviseThread, THREAD_PRIORITY_TIME_CRITICAL);
188c2c66affSColin Finck     This->adviseThreadActive = TRUE;
189c2c66affSColin Finck     while(1) {
190c2c66affSColin Finck       res = PostThreadMessageW(This->adviseThreadId, iMsg, 0, 0);
191c2c66affSColin Finck       /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */
192c2c66affSColin Finck       if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID))
193c2c66affSColin Finck 	Sleep(0);
194c2c66affSColin Finck       else
195c2c66affSColin Finck 	break;
196c2c66affSColin Finck     }
197c2c66affSColin Finck     return res;
198c2c66affSColin Finck   }
199c2c66affSColin Finck   return PostThreadMessageW(This->adviseThreadId, iMsg, 0, 0);
200c2c66affSColin Finck }
201c2c66affSColin Finck 
SystemClockImpl_AddRef(IReferenceClock * iface)202c2c66affSColin Finck static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock* iface) {
203c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
204c2c66affSColin Finck   ULONG ref = InterlockedIncrement(&This->ref);
205c2c66affSColin Finck 
206c2c66affSColin Finck   TRACE("(%p): AddRef from %d\n", This, ref - 1);
207c2c66affSColin Finck 
208c2c66affSColin Finck   return ref;
209c2c66affSColin Finck }
210c2c66affSColin Finck 
SystemClockImpl_QueryInterface(IReferenceClock * iface,REFIID riid,void ** ppobj)211c2c66affSColin Finck static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock* iface, REFIID riid, void** ppobj) {
212c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
213c2c66affSColin Finck   TRACE("(%p, %s,%p)\n", This, debugstr_guid(riid), ppobj);
214c2c66affSColin Finck 
215c2c66affSColin Finck   if (IsEqualIID (riid, &IID_IUnknown) ||
216c2c66affSColin Finck       IsEqualIID (riid, &IID_IReferenceClock)) {
217c2c66affSColin Finck     SystemClockImpl_AddRef(iface);
218c2c66affSColin Finck     *ppobj = &This->IReferenceClock_iface;
219c2c66affSColin Finck     return S_OK;
220c2c66affSColin Finck   }
221c2c66affSColin Finck 
222c2c66affSColin Finck   *ppobj = NULL;
223c2c66affSColin Finck   WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppobj);
224c2c66affSColin Finck   return E_NOINTERFACE;
225c2c66affSColin Finck }
226c2c66affSColin Finck 
SystemClockImpl_Release(IReferenceClock * iface)227c2c66affSColin Finck static ULONG WINAPI SystemClockImpl_Release(IReferenceClock* iface) {
228c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
229c2c66affSColin Finck   ULONG ref = InterlockedDecrement(&This->ref);
230c2c66affSColin Finck   TRACE("(%p): ReleaseRef to %d\n", This, ref);
231c2c66affSColin Finck   if (ref == 0) {
232*83d28845SAmine Khaldi     if (This->adviseThreadActive && SystemClockPostMessageToAdviseThread(This, ADVISE_EXIT)) {
233c2c66affSColin Finck       WaitForSingleObject(This->adviseThread, INFINITE);
234c2c66affSColin Finck       CloseHandle(This->adviseThread);
235c2c66affSColin Finck     }
236c2c66affSColin Finck     This->safe.DebugInfo->Spare[0] = 0;
237c2c66affSColin Finck     DeleteCriticalSection(&This->safe);
238c2c66affSColin Finck     CoTaskMemFree(This);
239c2c66affSColin Finck   }
240c2c66affSColin Finck   return ref;
241c2c66affSColin Finck }
242c2c66affSColin Finck 
SystemClockImpl_GetTime(IReferenceClock * iface,REFERENCE_TIME * pTime)243c2c66affSColin Finck static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock* iface, REFERENCE_TIME* pTime) {
244c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
245c2c66affSColin Finck   DWORD curTimeTickCount;
246c2c66affSColin Finck   HRESULT hr = S_OK;
247c2c66affSColin Finck 
248c2c66affSColin Finck   TRACE("(%p, %p)\n", This, pTime);
249c2c66affSColin Finck 
250c2c66affSColin Finck   if (NULL == pTime) {
251c2c66affSColin Finck     return E_POINTER;
252c2c66affSColin Finck   }
253c2c66affSColin Finck 
254c2c66affSColin Finck   curTimeTickCount = GetTickCount();
255c2c66affSColin Finck 
256c2c66affSColin Finck   EnterCriticalSection(&This->safe);
257c2c66affSColin Finck   if (This->lastTimeTickCount == curTimeTickCount) hr = S_FALSE;
258c2c66affSColin Finck   This->lastRefTime += (REFERENCE_TIME) (DWORD) (curTimeTickCount - This->lastTimeTickCount) * (REFERENCE_TIME) 10000;
259c2c66affSColin Finck   This->lastTimeTickCount = curTimeTickCount;
260c2c66affSColin Finck   *pTime = This->lastRefTime;
261c2c66affSColin Finck   LeaveCriticalSection(&This->safe);
262c2c66affSColin Finck   return hr;
263c2c66affSColin Finck }
264c2c66affSColin Finck 
SystemClockImpl_AdviseTime(IReferenceClock * iface,REFERENCE_TIME rtBaseTime,REFERENCE_TIME rtStreamTime,HEVENT hEvent,DWORD_PTR * pdwAdviseCookie)265c2c66affSColin Finck static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock* iface, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HEVENT hEvent, DWORD_PTR* pdwAdviseCookie) {
266c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
267c2c66affSColin Finck   SystemClockAdviseEntry* pEntry = NULL;
268c2c66affSColin Finck 
269c2c66affSColin Finck   TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtBaseTime),
270c2c66affSColin Finck       wine_dbgstr_longlong(rtStreamTime), hEvent, pdwAdviseCookie);
271c2c66affSColin Finck 
272c2c66affSColin Finck   if (!hEvent) {
273c2c66affSColin Finck     return E_INVALIDARG;
274c2c66affSColin Finck   }
275c2c66affSColin Finck   if (0 >= rtBaseTime + rtStreamTime) {
276c2c66affSColin Finck     return E_INVALIDARG;
277c2c66affSColin Finck   }
278c2c66affSColin Finck   if (NULL == pdwAdviseCookie) {
279c2c66affSColin Finck     return E_POINTER;
280c2c66affSColin Finck   }
281c2c66affSColin Finck   pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry));
282c2c66affSColin Finck   if (NULL == pEntry) {
283c2c66affSColin Finck     return E_OUTOFMEMORY;
284c2c66affSColin Finck   }
285c2c66affSColin Finck   ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry));
286c2c66affSColin Finck 
287c2c66affSColin Finck   pEntry->hEvent = (HANDLE) hEvent;
288c2c66affSColin Finck   pEntry->rtBaseTime = rtBaseTime + rtStreamTime;
289c2c66affSColin Finck   pEntry->rtIntervalTime = 0;
290c2c66affSColin Finck 
291c2c66affSColin Finck   EnterCriticalSection(&This->safe);
292c2c66affSColin Finck   QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pSingleShotAdvise);
293c2c66affSColin Finck   LeaveCriticalSection(&This->safe);
294c2c66affSColin Finck 
295c2c66affSColin Finck   SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_SINGLESHOT);
296c2c66affSColin Finck 
297c2c66affSColin Finck   *pdwAdviseCookie = (DWORD_PTR) (pEntry);
298c2c66affSColin Finck   return S_OK;
299c2c66affSColin Finck }
300c2c66affSColin Finck 
SystemClockImpl_AdvisePeriodic(IReferenceClock * iface,REFERENCE_TIME rtStartTime,REFERENCE_TIME rtPeriodTime,HSEMAPHORE hSemaphore,DWORD_PTR * pdwAdviseCookie)301c2c66affSColin Finck static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock* iface, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HSEMAPHORE hSemaphore, DWORD_PTR* pdwAdviseCookie) {
302c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
303c2c66affSColin Finck   SystemClockAdviseEntry* pEntry = NULL;
304c2c66affSColin Finck 
305c2c66affSColin Finck   TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtStartTime),
306c2c66affSColin Finck       wine_dbgstr_longlong(rtPeriodTime), hSemaphore, pdwAdviseCookie);
307c2c66affSColin Finck 
308c2c66affSColin Finck   if (!hSemaphore) {
309c2c66affSColin Finck     return E_INVALIDARG;
310c2c66affSColin Finck   }
311c2c66affSColin Finck   if (0 >= rtStartTime || 0 >= rtPeriodTime) {
312c2c66affSColin Finck     return E_INVALIDARG;
313c2c66affSColin Finck   }
314c2c66affSColin Finck   if (NULL == pdwAdviseCookie) {
315c2c66affSColin Finck     return E_POINTER;
316c2c66affSColin Finck   }
317c2c66affSColin Finck   pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry));
318c2c66affSColin Finck   if (NULL == pEntry) {
319c2c66affSColin Finck     return E_OUTOFMEMORY;
320c2c66affSColin Finck   }
321c2c66affSColin Finck   ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry));
322c2c66affSColin Finck 
323c2c66affSColin Finck   pEntry->hEvent = (HANDLE) hSemaphore;
324c2c66affSColin Finck   pEntry->rtBaseTime = rtStartTime;
325c2c66affSColin Finck   pEntry->rtIntervalTime = rtPeriodTime;
326c2c66affSColin Finck 
327c2c66affSColin Finck   EnterCriticalSection(&This->safe);
328c2c66affSColin Finck   QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pPeriodicAdvise);
329c2c66affSColin Finck   LeaveCriticalSection(&This->safe);
330c2c66affSColin Finck 
331c2c66affSColin Finck   SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_PERIODIC);
332c2c66affSColin Finck 
333c2c66affSColin Finck   *pdwAdviseCookie = (DWORD_PTR) (pEntry);
334c2c66affSColin Finck   return S_OK;
335c2c66affSColin Finck }
336c2c66affSColin Finck 
SystemClockImpl_Unadvise(IReferenceClock * iface,DWORD_PTR dwAdviseCookie)337c2c66affSColin Finck static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock* iface, DWORD_PTR dwAdviseCookie) {
338c2c66affSColin Finck   SystemClockImpl *This = impl_from_IReferenceClock(iface);
339c2c66affSColin Finck   SystemClockAdviseEntry* pEntry = NULL;
340c2c66affSColin Finck   SystemClockAdviseEntry* it = NULL;
341c2c66affSColin Finck   HRESULT ret = S_OK;
342c2c66affSColin Finck   TRACE("(%p, %lu)\n", This, dwAdviseCookie);
343c2c66affSColin Finck 
344c2c66affSColin Finck   pEntry = (SystemClockAdviseEntry*) dwAdviseCookie;
345c2c66affSColin Finck 
346c2c66affSColin Finck   EnterCriticalSection(&This->safe);
347c2c66affSColin Finck   for (it = This->pPeriodicAdvise; NULL != it && it != pEntry; it = it->next) ;
348c2c66affSColin Finck   if (it != pEntry) {
349c2c66affSColin Finck     for (it = This->pSingleShotAdvise; NULL != it && it != pEntry; it = it->next) ;
350c2c66affSColin Finck     if (it != pEntry) {
351c2c66affSColin Finck       ret = S_FALSE;
352c2c66affSColin Finck       goto out;
353c2c66affSColin Finck     }
354c2c66affSColin Finck   }
355c2c66affSColin Finck 
356c2c66affSColin Finck   QUARTZ_RemoveAviseEntryFromQueue(This, pEntry);
357c2c66affSColin Finck   CoTaskMemFree(pEntry);
358c2c66affSColin Finck 
359c2c66affSColin Finck   SystemClockPostMessageToAdviseThread(This, ADVISE_REMOVE);
360c2c66affSColin Finck 
361c2c66affSColin Finck out:
362c2c66affSColin Finck   LeaveCriticalSection(&This->safe);
363c2c66affSColin Finck   return ret;
364c2c66affSColin Finck }
365c2c66affSColin Finck 
366c2c66affSColin Finck static const IReferenceClockVtbl SystemClock_Vtbl =
367c2c66affSColin Finck {
368c2c66affSColin Finck     SystemClockImpl_QueryInterface,
369c2c66affSColin Finck     SystemClockImpl_AddRef,
370c2c66affSColin Finck     SystemClockImpl_Release,
371c2c66affSColin Finck     SystemClockImpl_GetTime,
372c2c66affSColin Finck     SystemClockImpl_AdviseTime,
373c2c66affSColin Finck     SystemClockImpl_AdvisePeriodic,
374c2c66affSColin Finck     SystemClockImpl_Unadvise
375c2c66affSColin Finck };
376c2c66affSColin Finck 
QUARTZ_CreateSystemClock(IUnknown * pUnkOuter,LPVOID * ppv)377c2c66affSColin Finck HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) {
378c2c66affSColin Finck   SystemClockImpl* obj = NULL;
379c2c66affSColin Finck 
380c2c66affSColin Finck   TRACE("(%p,%p)\n", ppv, pUnkOuter);
381c2c66affSColin Finck 
382c2c66affSColin Finck   obj = CoTaskMemAlloc(sizeof(SystemClockImpl));
383c2c66affSColin Finck   if (NULL == obj) 	{
384c2c66affSColin Finck     *ppv = NULL;
385c2c66affSColin Finck     return E_OUTOFMEMORY;
386c2c66affSColin Finck   }
387c2c66affSColin Finck   ZeroMemory(obj, sizeof(SystemClockImpl));
388c2c66affSColin Finck 
389c2c66affSColin Finck   obj->IReferenceClock_iface.lpVtbl = &SystemClock_Vtbl;
390c2c66affSColin Finck   obj->ref = 0;  /* will be inited by QueryInterface */
391c2c66affSColin Finck 
392c2c66affSColin Finck   obj->lastTimeTickCount = GetTickCount();
393c2c66affSColin Finck   InitializeCriticalSection(&obj->safe);
394c2c66affSColin Finck   obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.safe");
395c2c66affSColin Finck 
396c2c66affSColin Finck   return SystemClockImpl_QueryInterface(&obj->IReferenceClock_iface, &IID_IReferenceClock, ppv);
397c2c66affSColin Finck }
398