hxoptsc.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:13k
源码类别:

Symbian

开发平台:

Visual C++

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