ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

systemclock.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.