ReactOS  0.4.13-dev-100-gc8611ae
systemclock.c
Go to the documentation of this file.
1 /*
2  * Implementation of IReferenceClock
3  *
4  * Copyright 2004 Raphael Junqueira
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "quartz_private.h"
22 
23 #include "wine/debug.h"
24 #include "wine/unicode.h"
25 #include <assert.h>
26 
28 
33 
37 };
38 
39 typedef struct SystemClockImpl {
42 
50 
54 
56 {
57  return CONTAINING_RECORD(iface, SystemClockImpl, IReferenceClock_iface);
58 }
59 
60 
62  if (pEntry->prev) pEntry->prev->next = pEntry->next;
63  if (pEntry->next) pEntry->next->prev = pEntry->prev;
64  if (This->pSingleShotAdvise == pEntry) This->pSingleShotAdvise = pEntry->next;
65  if (This->pPeriodicAdvise == pEntry) This->pPeriodicAdvise = pEntry->next;
66 }
67 
69  SystemClockAdviseEntry* prev_it = NULL;
71  REFERENCE_TIME bornTime = pEntry->rtBaseTime + pEntry->rtIntervalTime;
72 
73  for (it = *pQueue; NULL != it && (it->rtBaseTime + it->rtIntervalTime) < bornTime; it = it->next) {
74  prev_it = it;
75  }
76  if (NULL == prev_it) {
77  pEntry->prev = NULL;
78  if (NULL != (*pQueue)) pEntry->next = (*pQueue)->next;
79  /*assert( NULL == pEntry->next->prev );*/
80  if (NULL != pEntry->next) pEntry->next->prev = pEntry;
81  (*pQueue) = pEntry;
82  } else {
83  pEntry->prev = prev_it;
84  pEntry->next = prev_it->next;
85  prev_it->next = pEntry;
86  if (NULL != pEntry->next) pEntry->next->prev = pEntry;
87  }
88 }
89 
90 #define MAX_REFTIME (REFERENCE_TIME)(0x7FFFFFFFFFFFFFFF)
91 #define ADVISE_EXIT (WM_APP + 0)
92 #define ADVISE_REMOVE (WM_APP + 2)
93 #define ADVISE_ADD_SINGLESHOT (WM_APP + 4)
94 #define ADVISE_ADD_PERIODIC (WM_APP + 8)
95 
97  SystemClockImpl* This = lpParam;
98  DWORD timeOut = INFINITE;
99  DWORD tmpTimeOut;
100  MSG msg;
101  HRESULT hr;
102  REFERENCE_TIME curTime;
104 
105  TRACE("(%p): Main Loop\n", This);
106 
107  while (TRUE) {
109 
110  EnterCriticalSection(&This->safe);
111  /*timeOut = IReferenceClock_OnTimerUpdated(This); */
112  hr = IReferenceClock_GetTime(&This->IReferenceClock_iface, &curTime);
113  if (FAILED(hr)) {
114  timeOut = INFINITE;
115  goto outrefresh;
116  }
117 
119  it = This->pSingleShotAdvise;
120  while ((NULL != it) && (it->rtBaseTime + it->rtIntervalTime) <= curTime) {
121  SystemClockAdviseEntry* nextit = it->next;
123  SetEvent(it->hEvent);
126  CoTaskMemFree(it);
127  it = nextit;
128  }
129  if (NULL != it) timeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000;
130  else timeOut = INFINITE;
131 
133  for (it = This->pPeriodicAdvise; NULL != it; it = it->next) {
134  if (it->rtBaseTime <= curTime) {
135  DWORD nPeriods = (DWORD) ((curTime - it->rtBaseTime) / it->rtIntervalTime);
137  ReleaseSemaphore(it->hEvent, nPeriods, NULL);
139  it->rtBaseTime += nPeriods * it->rtIntervalTime;
140  /*assert( it->rtBaseTime + it->rtIntervalTime < curTime );*/
141  }
142  tmpTimeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000;
143  if (timeOut > tmpTimeOut) timeOut = tmpTimeOut;
144  }
145 
146 outrefresh:
147  LeaveCriticalSection(&This->safe);
148 
149  while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
151  if (NULL != msg.hwnd) {
154  } else {
155  switch (msg.message) {
156  case WM_QUIT:
157  case ADVISE_EXIT:
158  goto outofthread;
160  case ADVISE_ADD_PERIODIC:
162  timeOut = 0;
163  break;
164  case ADVISE_REMOVE:
166  timeOut = INFINITE;
167  break;
168  default:
169  ERR("Unhandled message %u. Critical Path\n", msg.message);
170  break;
171  }
172  }
173  }
174  }
175 
176 outofthread:
177  TRACE("(%p): Exiting\n", This);
178  return 0;
179 }
180 /*static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) { */
181 
183  if (FALSE == This->adviseThreadActive) {
184  BOOL res;
185  This->adviseThread = CreateThread(NULL, 0, SystemClockAdviseThread, This, 0, &This->adviseThreadId);
186  if (NULL == This->adviseThread) return FALSE;
188  This->adviseThreadActive = TRUE;
189  while(1) {
190  res = PostThreadMessageW(This->adviseThreadId, iMsg, 0, 0);
191  /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */
193  Sleep(0);
194  else
195  break;
196  }
197  return res;
198  }
199  return PostThreadMessageW(This->adviseThreadId, iMsg, 0, 0);
200 }
201 
205 
206  TRACE("(%p): AddRef from %d\n", This, ref - 1);
207 
208  return ref;
209 }
210 
213  TRACE("(%p, %s,%p)\n", This, debugstr_guid(riid), ppobj);
214 
215  if (IsEqualIID (riid, &IID_IUnknown) ||
216  IsEqualIID (riid, &IID_IReferenceClock)) {
217  SystemClockImpl_AddRef(iface);
218  *ppobj = &This->IReferenceClock_iface;
219  return S_OK;
220  }
221 
222  *ppobj = NULL;
223  WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppobj);
224  return E_NOINTERFACE;
225 }
226 
230  TRACE("(%p): ReleaseRef to %d\n", This, ref);
231  if (ref == 0) {
232  if (This->adviseThreadActive && SystemClockPostMessageToAdviseThread(This, ADVISE_EXIT)) {
233  WaitForSingleObject(This->adviseThread, INFINITE);
234  CloseHandle(This->adviseThread);
235  }
236  This->safe.DebugInfo->Spare[0] = 0;
237  DeleteCriticalSection(&This->safe);
239  }
240  return ref;
241 }
242 
245  DWORD curTimeTickCount;
246  HRESULT hr = S_OK;
247 
248  TRACE("(%p, %p)\n", This, pTime);
249 
250  if (NULL == pTime) {
251  return E_POINTER;
252  }
253 
254  curTimeTickCount = GetTickCount();
255 
256  EnterCriticalSection(&This->safe);
257  if (This->lastTimeTickCount == curTimeTickCount) hr = S_FALSE;
258  This->lastRefTime += (REFERENCE_TIME) (DWORD) (curTimeTickCount - This->lastTimeTickCount) * (REFERENCE_TIME) 10000;
259  This->lastTimeTickCount = curTimeTickCount;
260  *pTime = This->lastRefTime;
261  LeaveCriticalSection(&This->safe);
262  return hr;
263 }
264 
265 static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock* iface, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HEVENT hEvent, DWORD_PTR* pdwAdviseCookie) {
267  SystemClockAdviseEntry* pEntry = NULL;
268 
269  TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtBaseTime),
270  wine_dbgstr_longlong(rtStreamTime), hEvent, pdwAdviseCookie);
271 
272  if (!hEvent) {
273  return E_INVALIDARG;
274  }
275  if (0 >= rtBaseTime + rtStreamTime) {
276  return E_INVALIDARG;
277  }
278  if (NULL == pdwAdviseCookie) {
279  return E_POINTER;
280  }
281  pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry));
282  if (NULL == pEntry) {
283  return E_OUTOFMEMORY;
284  }
285  ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry));
286 
287  pEntry->hEvent = (HANDLE) hEvent;
288  pEntry->rtBaseTime = rtBaseTime + rtStreamTime;
289  pEntry->rtIntervalTime = 0;
290 
291  EnterCriticalSection(&This->safe);
292  QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pSingleShotAdvise);
293  LeaveCriticalSection(&This->safe);
294 
296 
297  *pdwAdviseCookie = (DWORD_PTR) (pEntry);
298  return S_OK;
299 }
300 
301 static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock* iface, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HSEMAPHORE hSemaphore, DWORD_PTR* pdwAdviseCookie) {
303  SystemClockAdviseEntry* pEntry = NULL;
304 
305  TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtStartTime),
306  wine_dbgstr_longlong(rtPeriodTime), hSemaphore, pdwAdviseCookie);
307 
308  if (!hSemaphore) {
309  return E_INVALIDARG;
310  }
311  if (0 >= rtStartTime || 0 >= rtPeriodTime) {
312  return E_INVALIDARG;
313  }
314  if (NULL == pdwAdviseCookie) {
315  return E_POINTER;
316  }
317  pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry));
318  if (NULL == pEntry) {
319  return E_OUTOFMEMORY;
320  }
321  ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry));
322 
323  pEntry->hEvent = (HANDLE) hSemaphore;
324  pEntry->rtBaseTime = rtStartTime;
325  pEntry->rtIntervalTime = rtPeriodTime;
326 
327  EnterCriticalSection(&This->safe);
328  QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pPeriodicAdvise);
329  LeaveCriticalSection(&This->safe);
330 
332 
333  *pdwAdviseCookie = (DWORD_PTR) (pEntry);
334  return S_OK;
335 }
336 
339  SystemClockAdviseEntry* pEntry = NULL;
341  HRESULT ret = S_OK;
342  TRACE("(%p, %lu)\n", This, dwAdviseCookie);
343 
344  pEntry = (SystemClockAdviseEntry*) dwAdviseCookie;
345 
346  EnterCriticalSection(&This->safe);
347  for (it = This->pPeriodicAdvise; NULL != it && it != pEntry; it = it->next) ;
348  if (it != pEntry) {
349  for (it = This->pSingleShotAdvise; NULL != it && it != pEntry; it = it->next) ;
350  if (it != pEntry) {
351  ret = S_FALSE;
352  goto out;
353  }
354  }
355 
357  CoTaskMemFree(pEntry);
358 
360 
361 out:
362  LeaveCriticalSection(&This->safe);
363  return ret;
364 }
365 
366 static const IReferenceClockVtbl SystemClock_Vtbl =
367 {
375 };
376 
379 
380  TRACE("(%p,%p)\n", ppv, pUnkOuter);
381 
383  if (NULL == obj) {
384  *ppv = NULL;
385  return E_OUTOFMEMORY;
386  }
387  ZeroMemory(obj, sizeof(SystemClockImpl));
388 
389  obj->IReferenceClock_iface.lpVtbl = &SystemClock_Vtbl;
390  obj->ref = 0; /* will be inited by QueryInterface */
391 
392  obj->lastTimeTickCount = GetTickCount();
394  obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.safe");
395 
396  return SystemClockImpl_QueryInterface(&obj->IReferenceClock_iface, &IID_IReferenceClock, ppv);
397 }
static const IReferenceClockVtbl SystemClock_Vtbl
Definition: systemclock.c:366
SystemClockAdviseEntry * prev
Definition: systemclock.c:32
BOOL WINAPI TranslateMessage(_In_ const MSG *)
SystemClockAdviseEntry * pPeriodicAdvise
Definition: systemclock.c:52
#define REFIID
Definition: guiddef.h:113
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
BOOL adviseThreadActive
Definition: systemclock.c:46
static void QUARTZ_RemoveAviseEntryFromQueue(SystemClockImpl *This, SystemClockAdviseEntry *pEntry)
Definition: systemclock.c:61
#define E_NOINTERFACE
Definition: winerror.h:2364
#define ADVISE_ADD_SINGLESHOT
Definition: systemclock.c:93
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
#define DWORD_PTR
Definition: treelist.c:76
HRESULT hr
Definition: shlfolder.c:183
REFIID riid
Definition: precomp.h:44
SystemClockAdviseEntry * next
Definition: systemclock.c:31
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
#define WARN(fmt,...)
Definition: debug.h:111
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define WM_QUIT
Definition: winuser.h:1605
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define ERROR_INVALID_THREAD_ID
Definition: winerror.h:925
#define QS_TIMER
Definition: winuser.h:893
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock *iface, REFERENCE_TIME *pTime)
Definition: systemclock.c:243
CRITICAL_SECTION safe
Definition: systemclock.c:49
#define ADVISE_EXIT
Definition: systemclock.c:91
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
REFERENCE_TIME lastRefTime
Definition: systemclock.c:47
#define DWORD
Definition: nt_native.h:44
Definition: send.c:47
static HANDLE hEvent
Definition: comm.c:54
IReferenceClock IReferenceClock_iface
Definition: systemclock.c:40
#define ADVISE_ADD_PERIODIC
Definition: systemclock.c:94
static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam)
Definition: systemclock.c:96
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie)
Definition: systemclock.c:301
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
GLenum GLint ref
Definition: glext.h:6028
static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface)
Definition: systemclock.c:227
_In_ PCCERT_CONTEXT _In_opt_ LPFILETIME pTime
Definition: wincrypt.h:4840
#define S_FALSE
Definition: winerror.h:2357
#define E_INVALIDARG
Definition: ddrawi.h:101
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:112
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:697
smooth NULL
Definition: ftsmooth.c:416
#define QS_SENDMESSAGE
Definition: winuser.h:892
HRESULT QUARTZ_CreateSystemClock(IUnknown *pUnkOuter, LPVOID *ppv)
Definition: systemclock.c:377
HANDLE adviseThread
Definition: systemclock.c:44
#define debugstr_guid
Definition: kernel32.h:35
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
BOOL WINAPI SetThreadPriority(IN HANDLE hThread, IN int nPriority)
Definition: thread.c:662
static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock *iface, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HEVENT hEvent, DWORD_PTR *pdwAdviseCookie)
Definition: systemclock.c:265
SystemClockAdviseEntry * pSingleShotAdvise
Definition: systemclock.c:51
static BOOL SystemClockPostMessageToAdviseThread(SystemClockImpl *This, UINT iMsg)
Definition: systemclock.c:182
#define TRACE(s)
Definition: solgame.cpp:4
struct SystemClockImpl SystemClockImpl
DWORD_PTR HSEMAPHORE
Definition: axcore.idl:60
if(!(yy_init))
Definition: macro.lex.yy.c:714
LONGLONG REFERENCE_TIME
Definition: dmusicks.h:9
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
LONG HRESULT
Definition: typedefs.h:77
const GUID IID_IUnknown
REFERENCE_TIME rtBaseTime
Definition: systemclock.c:35
#define WINAPI
Definition: msvc.h:8
static FILE * out
Definition: regtests2xml.c:44
PVOID HANDLE
Definition: typedefs.h:71
unsigned long DWORD
Definition: ntddk_ex.h:95
static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock *iface, REFIID riid, void **ppobj)
Definition: systemclock.c:211
DWORD WINAPI MsgWaitForMultipleObjects(_In_ DWORD nCount, _In_reads_opt_(nCount) CONST HANDLE *pHandles, _In_ BOOL fWaitAll, _In_ DWORD dwMilliseconds, _In_ DWORD dwWakeMask)
#define THREAD_PRIORITY_TIME_CRITICAL
Definition: winbase.h:278
int ret
#define ADVISE_REMOVE
Definition: systemclock.c:92
#define InterlockedDecrement
Definition: armddk.h:52
#define IReferenceClock_GetTime(p, a)
Definition: dmusicc.h:754
static SystemClockImpl * impl_from_IReferenceClock(IReferenceClock *iface)
Definition: systemclock.c:55
DWORD lastTimeTickCount
Definition: systemclock.c:48
uint32_t DWORD_PTR
Definition: typedefs.h:63
#define ERR(fmt,...)
Definition: debug.h:109
#define S_OK
Definition: intsafe.h:59
#define InterlockedIncrement
Definition: armddk.h:53
#define QS_POSTMESSAGE
Definition: winuser.h:888
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseSemaphore(IN HANDLE hSemaphore, IN LONG lReleaseCount, IN LPLONG lpPreviousCount)
Definition: synch.c:488
static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock *iface, DWORD_PTR dwAdviseCookie)
Definition: systemclock.c:337
#define msg(x)
Definition: auth_time.c:54
GLuint res
Definition: glext.h:9613
unsigned int ULONG
Definition: retypes.h:1
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:41
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define PM_REMOVE
Definition: winuser.h:1182
REFERENCE_TIME rtIntervalTime
Definition: systemclock.c:36
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface)
Definition: systemclock.c:202
#define E_POINTER
Definition: winerror.h:2365
#define INFINITE
Definition: serial.h:102
static void QUARTZ_InsertAviseEntryFromQueue(SystemClockImpl *This, SystemClockAdviseEntry *pEntry, SystemClockAdviseEntry **pQueue)
Definition: systemclock.c:68
BOOL WINAPI PostThreadMessageW(_In_ DWORD, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:406
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:90
WINE_DEFAULT_DEBUG_CHANNEL(quartz)
DWORD adviseThreadId
Definition: systemclock.c:45
DWORD_PTR HEVENT
Definition: axcore.idl:61