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

Symbian

开发平台:

Visual C++

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