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

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 "hlxclib/stdio.h"
  37. #include "hxresult.h"
  38. #include "hxassert.h"
  39. #include "hxtypes.h"
  40. #include "ihxpckts.h"
  41. #include "hxengin.h"
  42. #include "hxfiles.h"
  43. #include "hxcore.h"
  44. #include "hxprefs.h"
  45. #include "hxausvc.h"
  46. #include "timeval.h"
  47. #include "hxtick.h"
  48. #include "hxsched.h"
  49. #include "hxmap.h"
  50. #include "hxstat.h"
  51. #include "timeline.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 LOG_MULTIPLE_DEFERRED_TASKS 1
  58. // static initializations..
  59. #if !defined(HELIX_CONFIG_NOSTATICS)
  60. #if defined(_WINDOWS) || defined(_SYMBIAN)
  61. CHXMapLongToObj Timeline::m_zTimerMap;
  62. #elif defined(_UNIX) || defined (_MACINTOSH) || defined(__TCS__) || defined(_OPENWAVE)
  63. CHXMapPtrToPtr Timeline::m_zTimerMap;
  64. #endif
  65. #else /* #if !defined(HELIX_CONFIG_NOSTATICS) */
  66. #include "globals/hxglobals.h"
  67. #if defined(_WINDOWS) || defined(_SYMBIAN)
  68. typedef CHXMapLongToObj      TimelineMapType;
  69. typedef HXGlobalMapLongToObj GlobalTimelineMapType;
  70. #elif defined(_UNIX) || defined (_MACINTOSH)
  71. typedef CHXMapPtrToPtr      TimelineMapType;
  72. typedef HXGlobalMapPtrToPtr GlobalTimelineMapType;
  73. #endif
  74. const TimelineMapType* const Timeline::m_zTimerMap = NULL;
  75. #endif /* #if !defined(HELIX_CONFIG_NOSTATICS) */
  76. #if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
  77. #define MINIMUM_GRANULARITY 55
  78. #elif defined(_MACINTOSH)
  79. #define MINIMUM_GRANULARITY 20
  80. #elif defined(_UNIX) 
  81. #define MINIMUM_GRANULARITY 20
  82. #else
  83. #define MINIMUM_GRANULARITY 20
  84. #endif
  85. #ifdef _MACINTOSH
  86. #include "hxmm.h" //for checking if VM
  87. ULONG32    gTIMELINE_MUTEX=NULL;
  88. #define CLOCKSET(c) (c.qType & kTMTaskActive)
  89. #endif
  90. #ifdef _MACINTOSH
  91. #ifdef _CARBON
  92. typedef pascal Handle (*NewHandleSysProcPtr)(Size);
  93. CFragConnectionID gInterfaceLibConnID = kInvalidID;
  94. NewHandleSysProcPtr gNewHandleSysProc = nil;
  95. bool gTriedToInitialize = false;
  96. void InitInterfaceLibProcPtrs()
  97. {
  98. if (gTriedToInitialize) return;
  99. gTriedToInitialize = true;
  100. if (gInterfaceLibConnID == kInvalidID)
  101. {
  102. GetSharedLibrary("pInterfaceLib", kCompiledCFragArch, kReferenceCFrag,
  103. &gInterfaceLibConnID, nil, nil);
  104. }
  105. if (gInterfaceLibConnID != kInvalidID)
  106. {
  107. OSErr err = noErr;
  108. err = FindSymbol(gInterfaceLibConnID, "pNewHandleSys", (Ptr*)&gNewHandleSysProc, nil);
  109. }
  110. }
  111. #endif
  112. #endif
  113. /*
  114.  * This class was originally written to keep track of time and report the
  115.  * *current* time to the user. This was the reason that pause, seek and 
  116.  * stuff were implemented. For this it needs to know the user (HXPlayer). 
  117.  * If we wanna use it from other object, the only way would be to pass it 
  118.  * a generic callback. But since IHXCallback's func does not take any 
  119.  * parameter, we cannot pass the *current* time back.
  120.  * 
  121.  * Since this class will eventually go away, I have made it to work so that
  122.  * it can be used by HXPlayer and HXScheduler by passing IUnknown.
  123.  *
  124.  */
  125. Timeline::Timeline(void)
  126.     : m_ulGranularity (MINIMUM_GRANULARITY)
  127.     , m_bIsTimerPending (FALSE)
  128.     , m_bPaused (FALSE)
  129.     , m_pPlayer (0)
  130.     , m_pScheduler (0)
  131.     , m_ulLastCallbackTime (0)
  132.     , m_bTimerFixup (FALSE)
  133. #if defined(_WINDOWS) || defined(_SYMBIAN)
  134.     , m_uiTimerID (0)
  135.     , m_uiTimerIDFixup (0)
  136. #endif    
  137. #ifdef _MACINTOSH
  138.     , m_uppTask(NULL)
  139.     , m_bUseDeferredTasks(TRUE)
  140.     , m_pInterruptState(NULL)
  141.     , m_bAnyCallbackPending(0)
  142.     , m_bIsQuitting (FALSE)
  143. #ifdef THREADS_SUPPORTED
  144.     , m_pCoreMutex(NULL)
  145. #endif
  146. #endif
  147. {
  148. #ifdef _MACINTOSH
  149.     memset( &m_DeferredTaskStruct, 0, sizeof(m_DeferredTaskStruct) );
  150.     memset( &m_tmInfo, 0, sizeof(m_tmInfo) );
  151. #endif
  152. };
  153. Timeline::~Timeline()
  154. {
  155.     if (m_bIsTimerPending)
  156.     {
  157. Pause();
  158.     }
  159.     m_bIsTimerPending = FALSE;
  160.     Done();
  161.     
  162. #ifdef _MACINTOSH
  163.     if (m_uppTask) 
  164.     {
  165. #ifdef _CARBON
  166. DisposeTimerUPP(m_uppTask);
  167. #else
  168. DisposeRoutineDescriptor(m_uppTask);
  169. #endif
  170. m_uppTask = NULL;
  171.     }
  172.     if (m_DeferredTaskStruct.dtAddr != NULL)
  173.     {
  174. // first ensure that the Gestalt handle doesn't think it's
  175. // here any more.
  176. Handle dtGestaltHandle = nil;
  177. Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle );
  178. if ( dtGestaltHandle )
  179. {
  180.     // XXXNH: only look at tasks for this process
  181.     ProcessSerialNumber psn;
  182.     GetCurrentProcess(&psn);
  183.     // zip through and if an entry equals this deferred task,
  184.     // simply zero it out. We won't worry about shuffling
  185.     // the handle size at this juncture.
  186.     long hSize = GetHandleSize( dtGestaltHandle );
  187.     GestaltDeferredStruct* currentPtr = (GestaltDeferredStruct*)*dtGestaltHandle;
  188.     for ( int i = 0; i < hSize / sizeof(GestaltDeferredStruct); i++ )
  189.     {
  190.         unsigned char bSameProcess = FALSE;
  191.         SameProcess(&(currentPtr[i].psn), &psn, &bSameProcess);
  192.         
  193. if (bSameProcess && 
  194.     currentPtr[i].quitting == &m_bIsQuitting && 
  195.     currentPtr[i].pending == &m_bAnyCallbackPending )
  196. {
  197.     currentPtr[i].quitting = NULL;
  198.     currentPtr[i].pending = NULL;
  199. }
  200.     }    
  201. }
  202. #ifdef _CARBON
  203. DisposeDeferredTaskUPP(m_DeferredTaskStruct.dtAddr);
  204. #else
  205. DisposeRoutineDescriptor(m_DeferredTaskStruct.dtAddr);
  206. #endif
  207. m_DeferredTaskStruct.dtAddr = NULL;
  208.     }
  209.     HX_RELEASE(m_pInterruptState);
  210. #endif
  211. }
  212. HX_RESULT
  213. Timeline::Init(IUnknown* pUnknown, BOOL bUseDeferredTask)
  214. {
  215.     if (!pUnknown)
  216.     {
  217. return HXR_INVALID_PARAMETER;
  218.     }
  219. #ifdef _MACINTOSH
  220.     m_bUseDeferredTasks = bUseDeferredTask;
  221.     if (m_bUseDeferredTasks)
  222.     {
  223. #ifdef _CARBON
  224. m_uppTask = NewTimerUPP((TimerProcPtr)MacTimerProc);
  225. #else
  226. m_uppTask = NewTimerProc(MacTimerProc);
  227. #endif
  228. m_tmInfo.tmTask.tmAddr = m_uppTask;
  229. m_tmInfo.tmRefCon = (long) this;
  230. m_tmInfo.tmTask.tmWakeUp = 0L;
  231. m_tmInfo.tmTask.tmReserved = 0L;
  232. m_DeferredTaskStruct.dtReserved = 0;
  233. m_DeferredTaskStruct.dtFlags = 0;
  234. #ifdef _CARBON
  235. m_DeferredTaskStruct.dtAddr = NewDeferredTaskUPP(Timeline::DeferredTaskProc);
  236. #else
  237. m_DeferredTaskStruct.dtAddr = NewDeferredTaskProc(Timeline::DeferredTaskProc);
  238. #endif
  239. m_DeferredTaskStruct.dtParam = (long) this;
  240. m_DeferredTaskStruct.qType = dtQType;
  241. // Gestalt-based code that remembers potential deferred tasks for emergency removal
  242. Handle dtGestaltHandle = nil;
  243. OSErr err = Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle );
  244. if ( err != noErr )
  245. {
  246. #ifdef _CARBON
  247.     InitInterfaceLibProcPtrs();
  248.     if (gNewHandleSysProc)
  249.     {
  250. dtGestaltHandle = (*gNewHandleSysProc)( 0 );
  251.     }
  252.     if (!dtGestaltHandle)
  253.     {
  254. dtGestaltHandle = NewHandle( 0 );
  255.     }
  256. #else
  257.     dtGestaltHandle = NewHandleSys( 0 );
  258. #endif
  259.     if ( dtGestaltHandle )
  260.     {
  261. NewGestaltValue( kLetInterruptsFinishBeforeQuittingGestalt, (long)dtGestaltHandle );
  262.     }
  263. }
  264. if ( dtGestaltHandle )
  265. {
  266.     GestaltDeferredStruct gds;
  267.     gds.quitting = &m_bIsQuitting;
  268.     gds.pending = &m_bAnyCallbackPending;
  269.     GetCurrentProcess(&(gds.psn));
  270.     PtrAndHand( &gds, dtGestaltHandle, sizeof(gds) );
  271. }
  272.     }
  273. #endif /* _MACINTOSH */
  274.     HX_RELEASE(m_pScheduler);
  275.     // Just get the interface for the scheduler; audio services will provide the
  276.     // player OnTimeSync interface.
  277.     if (!SUCCEEDED(pUnknown->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler)))
  278.     {
  279. return HXR_INVALID_PARAMETER;  //HX_INVALID_OBJECT;
  280.     }
  281.     else
  282.     {
  283. #if defined (_MACINTOSH)
  284. HX_RELEASE(m_pInterruptState);
  285. m_pScheduler->QueryInterface(IID_IHXInterruptState, 
  286.     (void**)&m_pInterruptState);
  287. #endif /* _MACINTOSH */
  288.     }
  289.     return HXR_OK;
  290. }
  291. HX_RESULT
  292. Timeline::Pause(void)
  293. {
  294. #if defined(HELIX_CONFIG_NOSTATICS)
  295.     TimelineMapType& m_zTimerMap =
  296. GlobalTimelineMapType::Get(&Timeline::m_zTimerMap);
  297. #endif
  298.     
  299.     m_bPaused = TRUE;
  300.     if (!m_bIsTimerPending)
  301.     {
  302. return HXR_OK;
  303.     }
  304.     m_bIsTimerPending = FALSE;
  305.     // Kill the timer for this timeline
  306. #if defined(_WINDOWS) || defined(_SYMBIAN)
  307.     if (!m_bTimerFixup) 
  308.     {
  309. // This is the "old code".  Execute it just as before the
  310. // timerfixup functionality was introduced.
  311. HXAsyncTimer::KillTimer( m_uiTimerID );    
  312.         TimerObjects*   pTimerObject = 0;
  313. if (m_zTimerMap.Lookup((LONG32) m_uiTimerID, (void*&) pTimerObject))    
  314.         {
  315.     if (pTimerObject->m_uiTimer == m_uiTimerID)
  316.     {
  317. m_zTimerMap.RemoveKey((LONG32) m_uiTimerID);     
  318. delete pTimerObject;
  319.     }
  320. }
  321.     }
  322.     else
  323.     {
  324.         TimerObjects*   pTimerObject = 0;
  325. BOOL deletedFlag = FALSE;
  326. if (m_uiTimerID)
  327. {
  328.     HXAsyncTimer::KillTimer(m_uiTimerID);    
  329.     if (m_zTimerMap.Lookup((LONG32) m_uiTimerID, (void*&) pTimerObject))
  330.     {
  331. m_zTimerMap.RemoveKey((LONG32) m_uiTimerID);     
  332. delete pTimerObject;
  333. pTimerObject = NULL;
  334. deletedFlag = TRUE;
  335.     }
  336. }
  337. if (m_uiTimerIDFixup)
  338. {
  339.     HXAsyncTimer::KillTimer(m_uiTimerIDFixup);    
  340.     if (m_zTimerMap.Lookup((LONG32) m_uiTimerIDFixup, (void*&) pTimerObject))
  341.     {
  342.         m_zTimerMap.RemoveKey((LONG32) m_uiTimerIDFixup);
  343. if (deletedFlag == FALSE)
  344.     delete pTimerObject;
  345. pTimerObject = NULL;
  346.     }
  347. }
  348.     }
  349.     m_uiTimerID = 0;
  350.     m_uiTimerIDFixup = 0;
  351. #elif defined (_UNIX) || defined(_MACINTOSH) || defined(__TCS__)
  352. #ifdef _MACINTOSH
  353.     if ( m_bUseDeferredTasks && CLOCKSET(m_tmInfo.tmTask) )
  354.     {
  355. ::RmvTime( (QElemPtr)&m_tmInfo );
  356. m_bAnyCallbackPending = 0;
  357.     }
  358. #endif
  359.     Timeline* pTimeline;
  360.     if (m_zTimerMap.Lookup(this, (void*&) pTimeline))
  361.     {
  362. HX_ASSERT(pTimeline == this);
  363. if (pTimeline == this)
  364. {
  365.     m_zTimerMap.RemoveKey(this);
  366. }
  367.     }
  368. #endif /* _UNIX || _MACINTOSH */
  369.     return HXR_OK;
  370. }
  371. void Timeline::Done(void)
  372. {
  373.     HX_RELEASE(m_pScheduler);
  374. #if defined (_MACINTOSH)
  375. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  376.     BOOL bBetterWaitForCallbacks = FALSE;
  377.     if ( m_uiDeferredTaskDepth > 0 )
  378.     {
  379. char tmpStr[255]; /* Flawfinder: ignore */
  380. sprintf(tmpStr, "m_uiDeferredTaskDepth = %u;g", m_uiDeferredTaskDepth); /* Flawfinder: ignore */
  381. // DebugStr(c2pstr(tmpStr));
  382. // don't spoil the timing by hitting MacsBug
  383. bBetterWaitForCallbacks = TRUE;
  384.     }
  385. #endif
  386.     m_bIsQuitting = TRUE;
  387.     // sit-n-spin awaiting interrupts to finish.
  388.     for ( int i = 0; i < 50; i++ )
  389.     {
  390. unsigned long dummyTix;
  391. Delay( 6, &dummyTix );
  392. if ( !m_bAnyCallbackPending )
  393. {
  394.     i = 50;
  395. }
  396.     }
  397. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  398.     if ( bBetterWaitForCallbacks )
  399.     {
  400. if ( m_uiDeferredTaskDepth > 0 )
  401. {
  402.     DebugStr( "pOops! After several seconds the deferred task didn't fire off;g" );
  403. }
  404. else
  405. {
  406.     DebugStr( "pNice... the deferred task fired off and we're good to go;g" );
  407. }
  408.     }
  409. #endif
  410.     m_bIsQuitting = FALSE;
  411. #endif
  412. }
  413. HX_RESULT Timeline::Resume(void)
  414. {
  415. #if defined(HELIX_CONFIG_NOSTATICS)
  416.     TimelineMapType& m_zTimerMap =
  417. GlobalTimelineMapType::Get(&Timeline::m_zTimerMap);
  418. #endif
  419.     m_bPaused = FALSE;
  420.     if (m_bIsTimerPending)
  421.     {
  422. return HXR_OK;  
  423.     }
  424.     
  425.     m_ulLastCallbackTime    = HX_GET_TICKCOUNT();
  426.     // Set a timer
  427. #if defined(_WINDOWS) || defined(_SYMBIAN)
  428.     m_uiTimerID = HXAsyncTimer::SetTimer(m_ulGranularity, (TIMERPROC)NonMMTimerProc);
  429.     if( m_bTimerFixup )
  430.         m_uiTimerIDFixup = HXAsyncTimer::SetTimer(m_ulGranularity,
  431.                                                    (TIMERPROC)NonMMTimerProc);
  432.     
  433. //     m_uiTimerID = SetTimer( NULL, NULL, (UINT) m_ulGranularity, 
  434. //      (TIMERPROC) NonMMTimerProc );
  435. //     if (m_bTimerFixup)
  436. //  m_uiTimerIDFixup = SetTimer( NULL, NULL, (UINT) m_ulGranularity, 
  437. //      (TIMERPROC) NonMMTimerProc );
  438. #elif defined(_MACINTOSH)
  439.     if (m_bUseDeferredTasks)
  440.     {
  441. OSErr e = noErr;
  442. if (CLOCKSET(m_tmInfo.tmTask))
  443. {
  444.     ::RmvTime((QElemPtr) &m_tmInfo);
  445.     
  446.     m_bAnyCallbackPending = 0;
  447. }
  448. m_tmInfo.tmTask.tmAddr = m_uppTask;
  449. m_tmInfo.tmRefCon = (long) this;
  450. m_tmInfo.tmTask.tmWakeUp = 0L;
  451. m_tmInfo.tmTask.tmReserved = 0L;
  452. ::InsTime((QElemPtr) &m_tmInfo);
  453. ::PrimeTime((QElemPtr) &m_tmInfo, m_ulGranularity);
  454. m_bAnyCallbackPending = 1;
  455.     }
  456. #endif
  457.     // add this timer to the static timer map
  458. #if defined(_WINDOWS) || defined(_SYMBIAN)
  459.     TimerObjects*   pTimerObject    = new TimerObjects;
  460.     if (!pTimerObject)
  461.     {
  462. if (!m_bTimerFixup)
  463.     // This is the "old code".  Execute it just as before the
  464.     // timerfixup functionality was introduced.
  465.             HXAsyncTimer::KillTimer(m_uiTimerID);
  466. else 
  467. {
  468.     if (m_uiTimerID)
  469. HXAsyncTimer::KillTimer(m_uiTimerID);
  470.     if (m_uiTimerIDFixup)
  471.         HXAsyncTimer::KillTimer(m_uiTimerIDFixup);
  472. }
  473. return HXR_OUTOFMEMORY;
  474.     }
  475.     pTimerObject->m_pTimeline     = this;
  476.     pTimerObject->m_uiTimer     = m_uiTimerID;
  477.     m_zTimerMap.SetAt((LONG32) m_uiTimerID, (void*) pTimerObject);
  478.     if (m_bTimerFixup)
  479.         m_zTimerMap.SetAt((LONG32) m_uiTimerIDFixup, (void*) pTimerObject);
  480. #elif defined(_UNIX) || defined(_MACINTOSH) || defined(__TCS__) || defined(_OPENWAVE)
  481.     m_zTimerMap.SetAt(this, this);
  482. #endif
  483. #if defined(_MACINTOSH) && defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  484.     if ( m_bIsTimerPending )
  485.     {
  486. DebugStr( "pTimeLine::Resume -- m_bIsTimerPending already true!;g" );
  487.     }
  488. #endif
  489.     m_bIsTimerPending = TRUE;
  490.     return HXR_OK;
  491. }
  492. HX_RESULT
  493. Timeline::Seek(ULONG32 ulSeekTime)
  494. {
  495.     if (!m_bPaused)
  496.     {
  497. Pause();
  498. Resume();
  499.     }
  500.     return HXR_OK;
  501. }
  502. HX_RESULT
  503. Timeline::SetStartTime(ULONG32 ulTime)
  504. {
  505.     return HXR_OK;
  506. }
  507. HX_RESULT
  508. Timeline::SetGranularity(ULONG32 ulNumMillisecs)
  509. {
  510.     m_ulGranularity = ulNumMillisecs;
  511.     return HXR_OK;
  512. }
  513. HX_RESULT
  514. Timeline::OnTimeSync(BOOL bAtInterrupt)
  515. {
  516. #ifdef _MACINTOSH
  517.     if ((InterlockedIncrement(&gTIMELINE_MUTEX) > 1) && bAtInterrupt)
  518.     {
  519.         InterlockedDecrement(&gTIMELINE_MUTEX);
  520. return HXR_OK;
  521.     }
  522. #endif
  523. //{FILE* f1 = ::fopen("d:\temp\timeline.txt", "a+"); ::fprintf(f1, "%p: %lu n", this, HX_GET_TICKCOUNT());::fclose(f1);}
  524.     if (!m_bPaused)
  525.     {
  526.         if (m_pScheduler)
  527. {
  528.     HXScheduler* pScheduler = m_pScheduler;
  529.     pScheduler->AddRef();
  530.     pScheduler->OnTimeSync(bAtInterrupt);
  531.     pScheduler->Release();
  532. }
  533.     }
  534. #ifdef _MACINTOSH
  535.     InterlockedDecrement(&gTIMELINE_MUTEX);
  536. #endif
  537.     return HXR_OK;
  538. }
  539. /*
  540.  *  ********* WINDOWS ONLY *****************
  541.  */
  542. #if defined(_WINDOWS) || defined(_SYMBIAN)
  543. /*
  544.  *  This is a Windows Timer callback proc
  545.  */
  546. void CALLBACK Timeline::NonMMTimerProc( 
  547.     void*   hwnd, // handle of window for timer messages 
  548.     UINT32  uMsg, // WM_TIMER message
  549.     UINT32  idTimer, // timer identifier
  550.     ULONG32 dwTime  // current system time
  551. )
  552. {
  553. #if defined(HELIX_CONFIG_NOSTATICS)
  554.     TimelineMapType& m_zTimerMap =
  555. GlobalTimelineMapType::Get(&Timeline::m_zTimerMap);
  556. #endif
  557.     TimerObjects*   pTimerObject = NULL;
  558.     if (m_zTimerMap.Lookup((LONG32) idTimer, (void*&) pTimerObject))
  559.     {
  560.         // MUST call this BEFORE OnTimeSync, because OnTimeSync could
  561.         // delete the object
  562. KillTimerFixup(idTimer, pTimerObject);
  563.         HX_ASSERT( pTimerObject);
  564.         HX_ASSERT( pTimerObject->m_pTimeline );
  565. pTimerObject->m_pTimeline->OnTimeSync();
  566.     }
  567.     return;
  568. }
  569. void Timeline::KillTimerFixup(UINT  idTimer, struct TimerObjects*  pTimerObject)
  570. {
  571. #if defined(HELIX_CONFIG_NOSTATICS)
  572.     TimelineMapType& m_zTimerMap =
  573. GlobalTimelineMapType::Get(&Timeline::m_zTimerMap);
  574. #endif
  575.     if (pTimerObject->m_pTimeline->m_bTimerFixup == FALSE)
  576. return;
  577.     if (pTimerObject->m_pTimeline->m_uiTimerIDFixup == 0)
  578. return;
  579.     if (pTimerObject->m_pTimeline->m_uiTimerID == 0)
  580. return;
  581.     if (pTimerObject->m_pTimeline->m_uiTimerID == idTimer)
  582.     {
  583. HXAsyncTimer::KillTimer(pTimerObject->m_pTimeline->m_uiTimerIDFixup);
  584. m_zTimerMap.RemoveKey((LONG32) pTimerObject->m_pTimeline->m_uiTimerIDFixup);
  585. pTimerObject->m_pTimeline->m_uiTimerIDFixup = 0;
  586.     }
  587.     else if (pTimerObject->m_pTimeline->m_uiTimerIDFixup == idTimer)
  588.     {
  589. HXAsyncTimer::KillTimer(pTimerObject->m_pTimeline->m_uiTimerID);
  590. m_zTimerMap.RemoveKey((LONG32) pTimerObject->m_pTimeline->m_uiTimerID);
  591. pTimerObject->m_pTimeline->m_uiTimerID = 0;
  592.     }
  593.     return;
  594. }
  595. #endif
  596. /*
  597.  *  ********* MAC ONLY *****************
  598.  */
  599. #ifdef _MACINTOSH
  600. /*
  601.  *  This is the Mac Timer callback proc (deferred task)
  602.  */
  603. pascal void 
  604. Timeline::MacTimerProc(TMInfoPtr task)
  605. {
  606.     HXMM_INTERRUPTON();
  607.     /*
  608.      * Setup and then install a deferred task 
  609.      */
  610.     if (task != NULL && task->tmRefCon != NULL)
  611.     {
  612. Timeline* pTheTimeline = (Timeline*)task->tmRefCon;
  613. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  614. // m_bIsTimerPending better be true right now
  615. if ( !pTheTimeline->m_bIsTimerPending )
  616. {
  617.     DebugStr( "pMacTimerProc -- m_bIsTimerPending is FALSE!;g" );
  618. }
  619. #endif
  620. if (pTheTimeline->m_DeferredTaskStruct.dtAddr != NULL)
  621. {
  622. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  623.     if ( pTheTimeline->m_uiDeferredTaskDepth > 0 )
  624.     {
  625. char tmpStr[255]; /* Flawfinder: ignore */
  626. sprintf(tmpStr, "m_uiDeferredTaskDepth = %u;g", pTheTimeline->m_uiDeferredTaskDepth); /* Flawfinder: ignore */
  627. DebugStr(c2pstr(tmpStr));
  628.     }
  629. #endif
  630.     if ( pTheTimeline->m_bIsQuitting )
  631.     {
  632. // short-circuit and don't install deferred task
  633. pTheTimeline->m_bAnyCallbackPending = 0;
  634. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  635.      DebugStr( "pIt's quitting so we don't install deferred task;g" );
  636. #endif
  637.     }
  638.     else
  639.     {
  640. // now that we're running on OS X, call the "deferred task" immediately.
  641. // Using a deferred thread is an artifact of OS 9: using deferred time
  642. // because it's not quite as nasty as hard interrupt time, plus there were
  643. // things that assumed they could only be interrupted "once". Those should
  644. // now all be THREAD safe (i.e. OS X) and calling deferred time oughtn't
  645. // be necessary.
  646. Timeline::DeferredTaskProc((long)pTheTimeline);
  647.     }
  648. }
  649.     }
  650.     
  651.     HXMM_INTERRUPTOFF();
  652. }
  653. pascal void Timeline::DeferredTaskProc(long param)
  654. {
  655.     HXMM_INTERRUPTON();
  656.     Timeline* pTheTimeline = (Timeline*)param;
  657.      
  658.     if (pTheTimeline)
  659.     {
  660. #ifdef THREADS_SUPPORTED
  661. if (pTheTimeline->m_pCoreMutex) pTheTimeline->m_pCoreMutex->Lock();
  662. #endif
  663. pTheTimeline->m_bAnyCallbackPending = 0;
  664. if ( !pTheTimeline->m_bIsQuitting )
  665. {
  666.     pTheTimeline->InterruptTimeSync();
  667. }
  668. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  669. else
  670. {
  671.     DebugStr( "pIn DeferredTaskProc, short-circuiting because we're quitting;g" );
  672. }
  673. #endif
  674. #ifdef THREADS_SUPPORTED
  675. if (pTheTimeline->m_pCoreMutex) pTheTimeline->m_pCoreMutex->Unlock();
  676. #endif
  677.     }
  678. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  679.     if ( pTheTimeline )
  680.     {
  681. if ( pTheTimeline->m_uiDeferredTaskDepth != 0 )
  682. {
  683.     char tmpStr[255]; /* Flawfinder: ignore */
  684.     sprintf(tmpStr, "m_uiDeferredTaskDepth = %u;g", pTheTimeline->m_uiDeferredTaskDepth); /* Flawfinder: ignore */
  685.     DebugStr(c2pstr(tmpStr));
  686. }
  687.     }
  688. #endif
  689.     HXMM_INTERRUPTOFF();
  690. }
  691. void 
  692. Timeline::InterruptTimeSync(void)
  693.     if (!m_bUseDeferredTasks)
  694.     {
  695.      ULONG32 ulCurTime = HX_GET_TICKCOUNT();
  696.      if ( ulCurTime > (m_ulLastCallbackTime + m_ulGranularity) )
  697.      {
  698.     OnTimeSync(FALSE);
  699.      }
  700.     }
  701.     else
  702.     {
  703.      if (m_pInterruptState)
  704.      {
  705.     m_pInterruptState->EnterInterruptState();
  706. }
  707.     
  708.      OnTimeSync(TRUE);
  709.     
  710. #if defined (_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  711. if ( m_bIsQuitting )
  712. {
  713.     DebugStr( "pIn InterruptTimeSync, about to ::PrimeTime, and we're QUITTING!;g" );
  714. }
  715. #endif
  716.     
  717. if ( !m_bIsQuitting )
  718. {
  719.     ::PrimeTime((QElemPtr) &m_tmInfo, m_ulGranularity); //restart timer
  720.     m_bAnyCallbackPending = 1;
  721. }
  722.     
  723.      if (m_pInterruptState)
  724.      {
  725.             m_pInterruptState->LeaveInterruptState();
  726.      }
  727.     }
  728. #endif //_MACINTOSH
  729. /*
  730.  *  ********* MAC & UNIX ONLY *****************
  731.  */
  732. #if defined(_UNIX) || defined(_MACINTOSH) || defined(__TCS__) || defined(_OPENWAVE)
  733. void
  734. Timeline::CallAllTimeSyncs(void)
  735. {    
  736. #if defined(HELIX_CONFIG_NOSTATICS)
  737.     TimelineMapType& m_zTimerMap =
  738. GlobalTimelineMapType::Get(&Timeline::m_zTimerMap);
  739. #endif
  740.     CHXMapPtrToPtr::Iterator ndxTimeline = m_zTimerMap.Begin();
  741.     for (; ndxTimeline != m_zTimerMap.End(); ++ndxTimeline)
  742.     {
  743. Timeline* pCurrentTimeline = (Timeline*)(*ndxTimeline);
  744. pCurrentTimeline->OnTimeSync();
  745.     }
  746. }
  747. #endif /* _UNIX || _MACINTOSH */