hxoptsc.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxcom.h"
  36. #include "hxtypes.h"
  37. #include "hxresult.h"
  38. #ifdef _WINDOWS
  39. #include <windows.h>
  40. #endif
  41. #include "timeval.h"
  42. #include "clientpq.h"
  43. #include "ihxpckts.h"
  44. #include "hxfiles.h"
  45. #include "hxengin.h"
  46. #include "hxcore.h"
  47. #include "hxprefs.h"
  48. #include "timeline.h"
  49. #include "hxtick.h"
  50. #include "hxthread.h"
  51. #include "hxoptsc.h"
  52. #include "hxheap.h"
  53. #ifdef _DEBUG
  54. #undef HX_THIS_FILE
  55. static const char HX_THIS_FILE[] = __FILE__;
  56. #endif
  57. #define MINIMUM_GRANULARITY   10
  58. #define MINIMUM_DIFFERENCE    1
  59. #define ALLFS                 0xFFFFFFFF
  60. void* ThreadRoutine(void * pArg);
  61. // HXOptimizedScheduler...
  62. HXOptimizedScheduler::HXOptimizedScheduler(IUnknown* pContext) :
  63.      m_lRefCount (0)
  64.     ,m_pPQ(0)
  65.     ,m_pID(NULL)
  66.     ,m_ulCurrentGranularity(MINIMUM_GRANULARITY)
  67.     ,m_pMutex(NULL)
  68.     ,m_pContext(pContext)
  69.     ,m_pThread(NULL)
  70.     ,m_pQuitEvent(NULL)
  71.     ,m_pSleepEvent(NULL)
  72.     ,m_pScheduler(NULL)
  73.     ,m_ulLastUpdateTime(0)
  74.     ,m_ulLastSyncTime(0)
  75.     ,m_bIsDone(FALSE)
  76. {
  77.     m_pID    = new CHXID(50);
  78.     m_pPQ    = new ClientPQ(m_pID);
  79. #ifdef THREADS_SUPPORTED
  80.     HXMutex::MakeMutex(m_pMutex);
  81. #else
  82.     HXMutex::MakeStubMutex(m_pMutex);
  83. #endif
  84.     gettimeofday((Timeval*)&m_CurrentTimeVal, 0);
  85.     m_ulLastSyncTime = m_ulLastUpdateTime = HX_GET_BETTERTICKCOUNT();
  86.     if (m_pContext)
  87.     {
  88. m_pContext->AddRef();
  89.     }
  90. }
  91. HXOptimizedScheduler::~HXOptimizedScheduler()
  92. {
  93.     StopScheduler();
  94.     HX_DELETE(m_pPQ);
  95.     HX_DELETE(m_pID);
  96.     HX_DELETE(m_pMutex);
  97.     HX_RELEASE(m_pContext);
  98.     HX_RELEASE(m_pScheduler);
  99. }
  100. /*
  101.  * IUnknown methods
  102.  */
  103. /////////////////////////////////////////////////////////////////////////
  104. // Method:
  105. // IUnknown::QueryInterface
  106. // Purpose:
  107. // Implement this to export the interfaces supported by your 
  108. // object.
  109. //
  110. STDMETHODIMP HXOptimizedScheduler::QueryInterface(REFIID riid, void** ppvObj)
  111. {
  112.     QInterfaceList qiList[] =
  113.         {
  114.             { GET_IIDHANDLE(IID_IHXOptimizedScheduler), (IHXOptimizedScheduler*)this },
  115.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXOptimizedScheduler*)this },
  116.         };
  117.     
  118.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  119. }
  120. /////////////////////////////////////////////////////////////////////////
  121. // Method:
  122. // IUnknown::AddRef
  123. // Purpose:
  124. // Everyone usually implements this the same... feel free to use
  125. // this implementation.
  126. //
  127. STDMETHODIMP_(ULONG32) HXOptimizedScheduler::AddRef()
  128. {
  129.     return InterlockedIncrement(&m_lRefCount);
  130. }
  131. /////////////////////////////////////////////////////////////////////////
  132. // Method:
  133. // IUnknown::Release
  134. // Purpose:
  135. // Everyone usually implements this the same... feel free to use
  136. // this implementation.
  137. //
  138. STDMETHODIMP_(ULONG32) HXOptimizedScheduler::Release()
  139. {
  140.     if (InterlockedDecrement(&m_lRefCount) > 0)
  141.     {
  142. return m_lRefCount;
  143.     }
  144.     delete this;
  145.     return 0;
  146. }
  147. /*
  148.  * HXOptimizedScheduler methods
  149.  */
  150. /************************************************************************
  151.  * Method:
  152.  * IHXOptimizedScheduler::Enter
  153.  * Purpose:
  154.  * enter objects in the service queue
  155.  */
  156. STDMETHODIMP_(CallbackHandle)
  157. HXOptimizedScheduler::RelativeEnter(IHXCallback* pCallback, ULONG32 ulTime)
  158. {
  159.     /*
  160.      * A RelativeEnter() of 0 ms is a special case that needs to be
  161.      * AbsoluteEnter() of 0
  162.      */
  163.     if (ulTime == 0)
  164.     {
  165. HXTimeval rVal;
  166. rVal.tv_sec = rVal.tv_usec = 0;
  167. return AbsoluteEnter(pCallback, rVal);
  168.     }
  169.     if (m_pScheduler)
  170.     {
  171. return m_pScheduler->RelativeEnter(pCallback, ulTime);
  172.     }
  173.     UINT32  usecs = 0;
  174.     UINT32  secs = 0;
  175.     Timeval lTime;
  176.     // handle the possible overflow of UINT32 when
  177.     // converting from milli-second to micro-second
  178.     if (ulTime > 4000000)
  179.     {
  180. secs = ulTime / 1000;
  181. usecs = (ulTime % 1000) * 1000;
  182.     }
  183.     else
  184.     {
  185. secs = 0;
  186. usecs = ulTime * 1000;
  187. if (usecs >= 1000000)
  188. {
  189.     secs = usecs / 1000000;
  190.     usecs = usecs % 1000000;
  191. }
  192.     }
  193.     lTime.tv_sec    = secs;
  194.     lTime.tv_usec   = usecs;
  195.     Timeval now;
  196.     now.tv_sec = m_CurrentTimeVal.tv_sec;
  197.     now.tv_usec = m_CurrentTimeVal.tv_usec;
  198.     now += lTime;
  199.     
  200.     m_pMutex->Lock();
  201.     CallbackHandle handle = m_pPQ->enter(now, pCallback);
  202.     UINT32 ulNumMs = 0;
  203.     if (GetNextEventDueTime(ulNumMs))
  204.     {
  205. m_ulCurrentGranularity = ulNumMs;
  206.     }
  207.     else
  208.     {
  209. m_ulCurrentGranularity = 0xFFFFFFFF;
  210.     }
  211.     m_pSleepEvent->SignalEvent();
  212.     m_pMutex->Unlock();
  213.     return handle;
  214. }
  215. /************************************************************************
  216.  * Method:
  217.  *     IHXOptimizedScheduler::AbsoluteEnter
  218.  * Purpose:
  219.  *     enter objects in the service queue at absolute time
  220.  */
  221. STDMETHODIMP_(CallbackHandle)
  222. HXOptimizedScheduler::AbsoluteEnter(IHXCallback* pCallback, HXTimeval tVal)
  223. {
  224.     if (m_pScheduler)
  225.     {
  226. return m_pScheduler->AbsoluteEnter(pCallback, tVal);
  227.     }
  228.     Timeval lTime;
  229.     lTime.tv_sec    = tVal.tv_sec;
  230.     lTime.tv_usec   = tVal.tv_usec;
  231.     m_pMutex->Lock();
  232.     CallbackHandle handle = m_pPQ->enter(lTime, pCallback);
  233.     UINT32 ulNumMs = 0;
  234.     if (GetNextEventDueTime(ulNumMs))
  235.     {
  236. m_ulCurrentGranularity = ulNumMs;
  237.     }
  238.     else
  239.     {
  240. m_ulCurrentGranularity = 0xFFFFFFFF;
  241.     }
  242.     m_pSleepEvent->SignalEvent();
  243.     m_pMutex->Unlock();
  244.     return handle;
  245. }
  246. /************************************************************************
  247.  * Method:
  248.  * IHXOptimizedScheduler::Remove
  249.  * Purpose:
  250.  * remove objects from the service queue
  251.  */
  252. STDMETHODIMP HXOptimizedScheduler::Remove(CallbackHandle Handle)
  253. {
  254.     if (m_pScheduler)
  255.     {
  256. return m_pScheduler->Remove(Handle);
  257.     }
  258.     m_pMutex->Lock();
  259.     m_pPQ->remove(Handle);
  260.     m_pMutex->Unlock();
  261.     return HXR_OK;
  262. }
  263. /************************************************************************
  264.  * Method:
  265.  *     IHXOptimizedScheduler::GetCurrentSchedulerTime
  266.  * Purpose:
  267.  *     gives the current time in the timeline of the scheduler...
  268.  */
  269. STDMETHODIMP_(HXTimeval) HXOptimizedScheduler::GetCurrentSchedulerTime(void)
  270. {
  271.     if (m_pScheduler)
  272.     {
  273. return m_pScheduler->GetCurrentSchedulerTime();
  274.     }
  275.     return m_CurrentTimeVal;
  276. }
  277. HX_RESULT HXOptimizedScheduler::ExecuteCurrentFunctions(void)
  278. {
  279.     Timeval now;
  280.     UpdateCurrentTime(&now);
  281.     m_pPQ->execute(now);
  282.     
  283.     m_pMutex->Lock();
  284.     /*
  285.      * Don't execute more then 100 immediate elements.  We don't wanna
  286.      * hold on too long and spin here.
  287.      */
  288.     int count = 0;
  289.     // Keep executing until there are no more zero time elements
  290.     while (m_pPQ->immediate() && count < 100)
  291.     {
  292.         m_pMutex->Unlock();
  293. count += m_pPQ->execute(now);
  294.         m_pMutex->Lock();
  295.     }
  296.     UINT32 ulNumMs = 0;
  297.     if (GetNextEventDueTime(ulNumMs))
  298.     {
  299. m_ulCurrentGranularity = ulNumMs;
  300.     }
  301.     else
  302.     {
  303. m_ulCurrentGranularity = 0xFFFFFFFF;
  304.     }
  305.     m_pMutex->Unlock();
  306.     return HXR_OK;
  307. }
  308. BOOL
  309. HXOptimizedScheduler::GetNextEventDueTime(UINT32& ulNumMs)
  310. {
  311.     if (m_pPQ->empty())
  312.     {
  313. return FALSE;
  314.     }
  315.     else
  316.     {
  317. Timeval now;
  318. now.tv_sec = m_CurrentTimeVal.tv_sec;
  319. now.tv_usec = m_CurrentTimeVal.tv_usec;
  320. Timeval timeout   = m_pPQ->head_time();
  321. if (timeout > now)
  322. {
  323.     timeout = timeout - now;
  324.     ulNumMs = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
  325. }
  326. else
  327. {
  328.     ulNumMs = 0;
  329. }
  330. return TRUE;
  331.     }
  332. }
  333. HX_RESULT    HXOptimizedScheduler::StartScheduler()
  334. {
  335. #ifndef THREADS_SUPPORTED
  336.     if (!m_pScheduler)
  337.     {
  338. m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  339.     }
  340. #endif
  341.     if (m_pScheduler)
  342.     {
  343. return HXR_OK;
  344.     }
  345.     HX_RESULT theErr = HXR_OK;
  346.     /* Stop any already running scheduler*/
  347.     StopScheduler();
  348.     gettimeofday((Timeval*)&m_CurrentTimeVal, 0);
  349.     m_ulLastSyncTime = m_ulLastUpdateTime = HX_GET_BETTERTICKCOUNT();
  350. #ifdef THREADS_SUPPORTED
  351.     theErr = HXThread::MakeThread(m_pThread);
  352.     HXEvent::MakeEvent(m_pQuitEvent, NULL);
  353.     HXEvent::MakeEvent(m_pSleepEvent, NULL, FALSE);
  354. #else
  355.     theErr = HXThread::MakeStubThread(m_pThread);
  356.     HXEvent::MakeStubEvent(m_pQuitEvent, NULL);
  357.     HXEvent::MakeStubEvent(m_pSleepEvent, NULL, FALSE);
  358. #endif
  359.     m_bIsDone = FALSE;
  360.     if (!theErr)
  361.     {
  362. theErr = m_pThread->CreateThread(ThreadRoutine, (void*) this);
  363.     }
  364.     if (!theErr)
  365.     {
  366. #ifdef _WIN32
  367. /* We should abstract priority level in thread class */ 
  368. theErr = m_pThread->SetPriority(THREAD_PRIORITY_HIGHEST);//THREAD_PRIORITY_TIME_CRITICAL);
  369. #endif /*_WIN32*/
  370.     }
  371.     return theErr;
  372. }
  373. void HXOptimizedScheduler::StopScheduler()
  374. {
  375.     if (m_pScheduler)
  376.     {
  377. return;
  378.     }
  379.     if (m_pThread)
  380.     {
  381. m_bIsDone = TRUE;
  382. m_pSleepEvent->SignalEvent();
  383. m_pQuitEvent->Wait(ALLFS);
  384. m_pThread->Exit(0);
  385. delete m_pThread;
  386. m_pThread = 0;
  387.     }
  388.     HX_DELETE(m_pQuitEvent);
  389.     HX_DELETE(m_pSleepEvent);
  390. }
  391. void
  392. HXOptimizedScheduler::UpdateCurrentTime(Timeval* pNow)
  393. {
  394. #if defined(_WINDOWS) || defined(_WIN32)
  395. #define MINIMUM_SYNC_TIME   5000
  396.     UINT32 ulCurrentTime = HX_GET_BETTERTICKCOUNT();
  397.     if (CALCULATE_ELAPSED_TICKS(m_ulLastSyncTime, ulCurrentTime) > MINIMUM_SYNC_TIME)
  398.     {
  399. gettimeofday(pNow, 0);
  400. m_CurrentTimeVal.tv_sec = pNow->tv_sec;
  401. m_CurrentTimeVal.tv_usec = pNow->tv_usec;
  402. m_ulLastSyncTime = m_ulLastUpdateTime = ulCurrentTime;
  403. return;
  404.     }
  405.     UINT32 ulElapsedTime = 1000 * CALCULATE_ELAPSED_TICKS(m_ulLastUpdateTime, ulCurrentTime);
  406.     pNow->tv_sec    = m_CurrentTimeVal.tv_sec;
  407.     pNow->tv_usec   = m_CurrentTimeVal.tv_usec;
  408.     (*pNow) += ulElapsedTime;
  409.     m_CurrentTimeVal.tv_sec = pNow->tv_sec;
  410.     m_CurrentTimeVal.tv_usec = pNow->tv_usec;
  411.     m_ulLastUpdateTime = ulCurrentTime;
  412. #else
  413.     gettimeofday(pNow, 0);
  414.     m_CurrentTimeVal.tv_sec = pNow->tv_sec;
  415.     m_CurrentTimeVal.tv_usec = pNow->tv_usec;
  416. #endif
  417. }
  418. void* ThreadRoutine(void * pArg)
  419. {
  420.     HXOptimizedScheduler* pOptimizedScheduler = 
  421.     (HXOptimizedScheduler*) pArg;
  422.     HXEvent* pSleepEvent = pOptimizedScheduler->m_pSleepEvent;
  423.     HXThread* pThread     = pOptimizedScheduler->m_pThread;
  424.     while (!pOptimizedScheduler->m_bIsDone)
  425.     {
  426. pOptimizedScheduler->ExecuteCurrentFunctions();
  427. pSleepEvent->Wait(pOptimizedScheduler->m_ulCurrentGranularity);
  428.     }
  429.     pOptimizedScheduler->m_pQuitEvent->SignalEvent();
  430.     return (void*) 0;
  431. }