Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensystemclock.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of IReferenceClock 00003 * 00004 * Copyright 2004 Raphael Junqueira 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "quartz_private.h" 00022 00023 #include "wine/debug.h" 00024 #include "wine/unicode.h" 00025 #include <assert.h> 00026 00027 WINE_DEFAULT_DEBUG_CHANNEL(quartz); 00028 00029 typedef struct SystemClockAdviseEntry SystemClockAdviseEntry; 00030 struct SystemClockAdviseEntry { 00031 SystemClockAdviseEntry* next; 00032 SystemClockAdviseEntry* prev; 00033 00034 HANDLE hEvent; 00035 REFERENCE_TIME rtBaseTime; 00036 REFERENCE_TIME rtIntervalTime; 00037 }; 00038 00039 typedef struct SystemClockImpl { 00040 const IReferenceClockVtbl *lpVtbl; 00041 LONG ref; 00042 00044 HANDLE adviseThread; 00045 DWORD adviseThreadId; 00046 BOOL adviseThreadActive; 00047 REFERENCE_TIME lastRefTime; 00048 DWORD lastTimeTickCount; 00049 CRITICAL_SECTION safe; 00050 00051 SystemClockAdviseEntry* pSingleShotAdvise; 00052 SystemClockAdviseEntry* pPeriodicAdvise; 00053 } SystemClockImpl; 00054 00055 00056 static void QUARTZ_RemoveAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry) { 00057 if (pEntry->prev) pEntry->prev->next = pEntry->next; 00058 if (pEntry->next) pEntry->next->prev = pEntry->prev; 00059 if (This->pSingleShotAdvise == pEntry) This->pSingleShotAdvise = pEntry->next; 00060 if (This->pPeriodicAdvise == pEntry) This->pPeriodicAdvise = pEntry->next; 00061 } 00062 00063 static void QUARTZ_InsertAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry, SystemClockAdviseEntry** pQueue) { 00064 SystemClockAdviseEntry* prev_it = NULL; 00065 SystemClockAdviseEntry* it = NULL; 00066 REFERENCE_TIME bornTime = pEntry->rtBaseTime + pEntry->rtIntervalTime; 00067 00068 for (it = *pQueue; NULL != it && (it->rtBaseTime + it->rtIntervalTime) < bornTime; it = it->next) { 00069 prev_it = it; 00070 } 00071 if (NULL == prev_it) { 00072 pEntry->prev = NULL; 00073 if (NULL != (*pQueue)) pEntry->next = (*pQueue)->next; 00074 /*assert( NULL == pEntry->next->prev );*/ 00075 if (NULL != pEntry->next) pEntry->next->prev = pEntry; 00076 (*pQueue) = pEntry; 00077 } else { 00078 pEntry->prev = prev_it; 00079 pEntry->next = prev_it->next; 00080 prev_it->next = pEntry; 00081 if (NULL != pEntry->next) pEntry->next->prev = pEntry; 00082 } 00083 } 00084 00085 #define MAX_REFTIME (REFERENCE_TIME)(0x7FFFFFFFFFFFFFFF) 00086 #define ADVISE_EXIT (WM_APP + 0) 00087 #define ADVISE_REMOVE (WM_APP + 2) 00088 #define ADVISE_ADD_SINGLESHOT (WM_APP + 4) 00089 #define ADVISE_ADD_PERIODIC (WM_APP + 8) 00090 00091 static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) { 00092 SystemClockImpl* This = lpParam; 00093 DWORD timeOut = INFINITE; 00094 DWORD tmpTimeOut; 00095 MSG msg; 00096 HRESULT hr; 00097 REFERENCE_TIME curTime; 00098 SystemClockAdviseEntry* it = NULL; 00099 00100 TRACE("(%p): Main Loop\n", This); 00101 00102 while (TRUE) { 00103 if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER); 00104 00105 EnterCriticalSection(&This->safe); 00106 /*timeOut = IReferenceClock_OnTimerUpdated(This); */ 00107 hr = IReferenceClock_GetTime((IReferenceClock*) This, &curTime); 00108 if (FAILED(hr)) { 00109 timeOut = INFINITE; 00110 goto outrefresh; 00111 } 00112 00114 for (it = This->pSingleShotAdvise; NULL != it && (it->rtBaseTime + it->rtIntervalTime) <= curTime; it = it->next) { 00116 SetEvent(it->hEvent); 00118 QUARTZ_RemoveAviseEntryFromQueue(This, it); 00119 CoTaskMemFree(it); 00120 } 00121 if (NULL != it) timeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000; 00122 00124 for (it = This->pPeriodicAdvise; NULL != it; it = it->next) { 00125 if (it->rtBaseTime <= curTime) { 00126 DWORD nPeriods = (DWORD) ((curTime - it->rtBaseTime) / it->rtIntervalTime); 00128 ReleaseSemaphore(it->hEvent, nPeriods, NULL); 00130 it->rtBaseTime += nPeriods * it->rtIntervalTime; 00131 /*assert( it->rtBaseTime + it->rtIntervalTime < curTime );*/ 00132 } 00133 tmpTimeOut = (DWORD) ((it->rtBaseTime + it->rtIntervalTime) - curTime) / (REFERENCE_TIME)10000; 00134 if (timeOut > tmpTimeOut) timeOut = tmpTimeOut; 00135 } 00136 00137 outrefresh: 00138 LeaveCriticalSection(&This->safe); 00139 00140 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { 00142 if (NULL != msg.hwnd) { 00143 TranslateMessage(&msg); 00144 DispatchMessageA(&msg); 00145 } else { 00146 switch (msg.message) { 00147 case WM_QUIT: 00148 case ADVISE_EXIT: 00149 goto outofthread; 00150 case ADVISE_ADD_SINGLESHOT: 00151 case ADVISE_ADD_PERIODIC: 00153 timeOut = 0; 00154 break; 00155 case ADVISE_REMOVE: 00157 timeOut = INFINITE; 00158 break; 00159 default: 00160 ERR("Unhandled message %u. Critical Path\n", msg.message); 00161 break; 00162 } 00163 } 00164 } 00165 } 00166 00167 outofthread: 00168 TRACE("(%p): Exiting\n", This); 00169 return 0; 00170 } 00171 /*static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) { */ 00172 00173 static BOOL SystemClockPostMessageToAdviseThread(SystemClockImpl* This, UINT iMsg) { 00174 if (FALSE == This->adviseThreadActive) { 00175 BOOL res; 00176 This->adviseThread = CreateThread(NULL, 0, SystemClockAdviseThread, This, 0, &This->adviseThreadId); 00177 if (NULL == This->adviseThread) return FALSE; 00178 SetThreadPriority(This->adviseThread, THREAD_PRIORITY_TIME_CRITICAL); 00179 This->adviseThreadActive = TRUE; 00180 while(1) { 00181 res = PostThreadMessageA(This->adviseThreadId, iMsg, 0, 0); 00182 /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */ 00183 if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID)) 00184 Sleep(0); 00185 else 00186 break; 00187 } 00188 return res; 00189 } 00190 return PostThreadMessageA(This->adviseThreadId, iMsg, 0, 0); 00191 } 00192 00193 static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock* iface) { 00194 SystemClockImpl *This = (SystemClockImpl *)iface; 00195 ULONG ref = InterlockedIncrement(&This->ref); 00196 00197 TRACE("(%p): AddRef from %d\n", This, ref - 1); 00198 00199 return ref; 00200 } 00201 00202 static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock* iface, REFIID riid, void** ppobj) { 00203 SystemClockImpl *This = (SystemClockImpl *)iface; 00204 TRACE("(%p, %s,%p)\n", This, debugstr_guid(riid), ppobj); 00205 00206 if (IsEqualIID (riid, &IID_IUnknown) || 00207 IsEqualIID (riid, &IID_IReferenceClock)) { 00208 SystemClockImpl_AddRef(iface); 00209 *ppobj = This; 00210 return S_OK; 00211 } 00212 00213 *ppobj = NULL; 00214 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppobj); 00215 return E_NOINTERFACE; 00216 } 00217 00218 static ULONG WINAPI SystemClockImpl_Release(IReferenceClock* iface) { 00219 SystemClockImpl *This = (SystemClockImpl *)iface; 00220 ULONG ref = InterlockedDecrement(&This->ref); 00221 TRACE("(%p): ReleaseRef to %d\n", This, ref); 00222 if (ref == 0) { 00223 if (SystemClockPostMessageToAdviseThread(This, ADVISE_EXIT)) { 00224 WaitForSingleObject(This->adviseThread, INFINITE); 00225 CloseHandle(This->adviseThread); 00226 } 00227 This->safe.DebugInfo->Spare[0] = 0; 00228 DeleteCriticalSection(&This->safe); 00229 CoTaskMemFree(This); 00230 } 00231 return ref; 00232 } 00233 00234 static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock* iface, REFERENCE_TIME* pTime) { 00235 SystemClockImpl *This = (SystemClockImpl *)iface; 00236 DWORD curTimeTickCount; 00237 HRESULT hr = S_OK; 00238 00239 TRACE("(%p, %p)\n", This, pTime); 00240 00241 if (NULL == pTime) { 00242 return E_POINTER; 00243 } 00244 00245 curTimeTickCount = GetTickCount(); 00246 00247 EnterCriticalSection(&This->safe); 00248 if (This->lastTimeTickCount == curTimeTickCount) hr = S_FALSE; 00249 This->lastRefTime += (REFERENCE_TIME) (DWORD) (curTimeTickCount - This->lastTimeTickCount) * (REFERENCE_TIME) 10000; 00250 This->lastTimeTickCount = curTimeTickCount; 00251 *pTime = This->lastRefTime; 00252 LeaveCriticalSection(&This->safe); 00253 return hr; 00254 } 00255 00256 static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock* iface, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HEVENT hEvent, DWORD_PTR* pdwAdviseCookie) { 00257 SystemClockImpl *This = (SystemClockImpl *)iface; 00258 SystemClockAdviseEntry* pEntry = NULL; 00259 00260 TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtBaseTime), 00261 wine_dbgstr_longlong(rtStreamTime), hEvent, pdwAdviseCookie); 00262 00263 if (!hEvent) { 00264 return E_INVALIDARG; 00265 } 00266 if (0 >= rtBaseTime + rtStreamTime) { 00267 return E_INVALIDARG; 00268 } 00269 if (NULL == pdwAdviseCookie) { 00270 return E_POINTER; 00271 } 00272 pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry)); 00273 if (NULL == pEntry) { 00274 return E_OUTOFMEMORY; 00275 } 00276 ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry)); 00277 00278 pEntry->hEvent = (HANDLE) hEvent; 00279 pEntry->rtBaseTime = rtBaseTime + rtStreamTime; 00280 pEntry->rtIntervalTime = 0; 00281 00282 EnterCriticalSection(&This->safe); 00283 QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pSingleShotAdvise); 00284 LeaveCriticalSection(&This->safe); 00285 00286 SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_SINGLESHOT); 00287 00288 *pdwAdviseCookie = (DWORD_PTR) (pEntry); 00289 return S_OK; 00290 } 00291 00292 static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock* iface, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HSEMAPHORE hSemaphore, DWORD_PTR* pdwAdviseCookie) { 00293 SystemClockImpl *This = (SystemClockImpl *)iface; 00294 SystemClockAdviseEntry* pEntry = NULL; 00295 00296 TRACE("(%p, 0x%s, 0x%s, %ld, %p)\n", This, wine_dbgstr_longlong(rtStartTime), 00297 wine_dbgstr_longlong(rtPeriodTime), hSemaphore, pdwAdviseCookie); 00298 00299 if (!hSemaphore) { 00300 return E_INVALIDARG; 00301 } 00302 if (0 >= rtStartTime || 0 >= rtPeriodTime) { 00303 return E_INVALIDARG; 00304 } 00305 if (NULL == pdwAdviseCookie) { 00306 return E_POINTER; 00307 } 00308 pEntry = CoTaskMemAlloc(sizeof(SystemClockAdviseEntry)); 00309 if (NULL == pEntry) { 00310 return E_OUTOFMEMORY; 00311 } 00312 ZeroMemory(pEntry, sizeof(SystemClockAdviseEntry)); 00313 00314 pEntry->hEvent = (HANDLE) hSemaphore; 00315 pEntry->rtBaseTime = rtStartTime; 00316 pEntry->rtIntervalTime = rtPeriodTime; 00317 00318 EnterCriticalSection(&This->safe); 00319 QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pPeriodicAdvise); 00320 LeaveCriticalSection(&This->safe); 00321 00322 SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_PERIODIC); 00323 00324 *pdwAdviseCookie = (DWORD_PTR) (pEntry); 00325 return S_OK; 00326 } 00327 00328 static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock* iface, DWORD_PTR dwAdviseCookie) { 00329 SystemClockImpl *This = (SystemClockImpl *)iface; 00330 SystemClockAdviseEntry* pEntry = NULL; 00331 SystemClockAdviseEntry* it = NULL; 00332 HRESULT ret = S_OK; 00333 TRACE("(%p, %lu)\n", This, dwAdviseCookie); 00334 00335 pEntry = (SystemClockAdviseEntry*) dwAdviseCookie; 00336 00337 EnterCriticalSection(&This->safe); 00338 for (it = This->pPeriodicAdvise; NULL != it && it != pEntry; it = it->next) ; 00339 if (it != pEntry) { 00340 for (it = This->pSingleShotAdvise; NULL != it && it != pEntry; it = it->next) ; 00341 if (it != pEntry) { 00342 ret = S_FALSE; 00343 goto out; 00344 } 00345 } 00346 00347 QUARTZ_RemoveAviseEntryFromQueue(This, pEntry); 00348 CoTaskMemFree(pEntry); 00349 00350 SystemClockPostMessageToAdviseThread(This, ADVISE_REMOVE); 00351 00352 out: 00353 LeaveCriticalSection(&This->safe); 00354 return ret; 00355 } 00356 00357 static const IReferenceClockVtbl SystemClock_Vtbl = 00358 { 00359 SystemClockImpl_QueryInterface, 00360 SystemClockImpl_AddRef, 00361 SystemClockImpl_Release, 00362 SystemClockImpl_GetTime, 00363 SystemClockImpl_AdviseTime, 00364 SystemClockImpl_AdvisePeriodic, 00365 SystemClockImpl_Unadvise 00366 }; 00367 00368 HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) { 00369 SystemClockImpl* obj = NULL; 00370 00371 TRACE("(%p,%p)\n", ppv, pUnkOuter); 00372 00373 obj = CoTaskMemAlloc(sizeof(SystemClockImpl)); 00374 if (NULL == obj) { 00375 *ppv = NULL; 00376 return E_OUTOFMEMORY; 00377 } 00378 ZeroMemory(obj, sizeof(SystemClockImpl)); 00379 00380 obj->lpVtbl = &SystemClock_Vtbl; 00381 obj->ref = 0; /* will be inited by QueryInterface */ 00382 00383 obj->lastTimeTickCount = GetTickCount(); 00384 InitializeCriticalSection(&obj->safe); 00385 obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.safe"); 00386 00387 return SystemClockImpl_QueryInterface((IReferenceClock*) obj, &IID_IReferenceClock, ppv); 00388 } Generated on Sat May 26 2012 04:20:33 for ReactOS by
1.7.6.1
|