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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: symbianthreads.cpp,v 1.8.22.3 2004/07/09 01:43:27 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. //This is used to turn off threads in libc5 builds.
  50. #include "hxtypes.h"  //for UINT32
  51. #include "hxresult.h" //for HX_RESULT
  52. #include "hxslist.h"
  53. #include "hxassert.h" //for HX_ASSERT
  54. #include "hxmsgs.h"   //for HXMSG_ASYNC_TIMER message.
  55. #include "hxmap.h"    //for CHXMapLongToObj
  56. #include "hxtick.h"   //for GetTickCount()
  57. #include "globals/hxglobals.h"
  58. #include "SymbianThreads.h"
  59. #include "symbian_async_timer_imp.h"
  60. #include "symbian_rtimer_at_imp.h"
  61. #include "symbian_thread_at_imp.h"
  62. #include "hxglobalmgr_inst.h"
  63. //XXXgfw I first coded this to use RTimers for RunL callbacks to get
  64. //the work of the async timer done. But, if the thread that creates
  65. //the timer blocks at all we stop getting callbacks. I think now that
  66. //this may cause problems with the way Helix uses the timers. So, I am
  67. //going to code a version that uses real threads to get the work
  68. //done. You can use the below define to build either one you want.
  69. //#define  USE_SYMBIAN_THREADS_FOR_ASYNCTIMERS
  70. //=======================================================================
  71. //
  72. //                      HXSymbianThread
  73. //                   ------------------
  74. //
  75. //=======================================================================
  76. HXSymbianThread::HXSymbianThread()
  77.     : m_pThread(NULL),
  78.       m_pSemMessageCount(NULL),
  79.       m_pmtxQue(NULL)
  80. {
  81.     TInt err;
  82.     m_pSemMessageCount = new RSemaphore();
  83.     HX_ASSERT( m_pSemMessageCount );
  84.     if( m_pSemMessageCount )
  85.     {
  86.         err = m_pSemMessageCount->CreateLocal(0);
  87.         if( KErrNone != err )
  88.         {
  89.             HX_DELETE( m_pSemMessageCount );
  90.         }
  91.     }
  92.     
  93.     HXMutex::MakeMutex( m_pmtxQue );
  94.     HX_ASSERT( m_pmtxQue );
  95. }
  96. HXSymbianThread::~HXSymbianThread()
  97. {
  98.     //Clean up message que.
  99.     while( !m_messageQue.IsEmpty() )
  100.     {
  101.         HXThreadMessage* pTmp = (HXThreadMessage *)(m_messageQue.RemoveHead());
  102.         HX_DELETE( pTmp );
  103.     }
  104.     if( m_pSemMessageCount)
  105.     {
  106.         m_pSemMessageCount->Close();
  107.         HX_DELETE( m_pSemMessageCount );
  108.     }
  109.     
  110.     HX_DELETE( m_pmtxQue );
  111.     if( m_pThread )
  112.     {
  113.         m_pThread->Kill(0);
  114.         m_pThread->Close();
  115.         HX_DELETE(m_pThread);
  116.     }
  117. }
  118. HX_RESULT HXSymbianThread::CreateThread( void*(pfExecFunc(void*)),
  119.                                          void* pArg,
  120.                                          ULONG32 ulCreationFlags)
  121. {
  122.     HX_RESULT retVal = HXR_OK;
  123.     TInt      err    = KErrNone;
  124.     
  125.     HX_ASSERT( NULL==m_pThread );
  126.     if( NULL != m_pThread )
  127.     {
  128.         retVal = HXR_UNEXPECTED;
  129.     }
  130.     else
  131.     {
  132.         m_pThread = new RThread();
  133.         if( NULL == m_pThread )
  134.         {
  135.             retVal = HXR_FAIL;
  136.         }
  137.         else
  138.         {
  139.             //Each thread has to have a unique name. Oh bother.
  140.             //Lets just use the heap pointer.
  141.             char szBuff[20]; /* Flawfinder: ignore */
  142.             sprintf( szBuff, "%p", m_pThread ); /* Flawfinder: ignore */
  143.             TPtr ThreadName((unsigned short*)szBuff, strlen(szBuff), 20);
  144.             st_execStruct stExecStruct;
  145.             stExecStruct.pfExecProc     = (TThreadFunction)pfExecFunc;
  146.             stExecStruct.pExecArg       = pArg;
  147.             stExecStruct.pGlobalManager = HXGlobalManInstance::GetInstance();
  148.             
  149.             err = m_pThread->Create( ThreadName, 
  150.                                      _ThreadWrapper,
  151.                                      KDefaultStackSize,
  152.                                      &User::Heap(), //Use parent HEAP
  153.                                      &stExecStruct 
  154.                                      );
  155.             if( KErrNone != err )
  156.             {
  157.                 //Could not start thread.
  158.                 retVal = HXR_FAIL;
  159.                 m_pThread->Close();
  160.                 HX_DELETE( m_pThread );
  161.             }
  162.             else
  163.             {
  164.                 //Tell the system we want to be notifed when this
  165.                 //thread terminates for any reason.
  166.                 m_pThread->Logon(m_reqStat);
  167.                 //Symbian threads start up in a 'suspended' mode. HXThreads
  168.                 //assume that the threads are running from the get go. So, we
  169.                 //do a resume here.
  170.                 m_pThread->Resume();
  171.             }
  172.         }
  173.     }
  174.     return retVal;
  175. }
  176. HX_RESULT HXSymbianThread::Exit(UINT32 unExitCode)
  177. {
  178.     if( NULL==m_pThread )
  179.     {
  180.         //Thread has already gone or was never here.
  181.         return HXR_UNEXPECTED;
  182.     }
  183.     
  184.     if( m_pThread->Id() != (TThreadId)GetCurrentThreadID() )
  185.     {
  186.         //Ok, because of the way winthrd.cpp does it, this call also
  187.         //acts as a 'pthread_join' when the calling thread isn't the
  188.         //m_threadID.
  189.         
  190.         //Also, it looks like this method isn't set up to look at the
  191.         //return value of the thread. We could return HXR_FAIL is it
  192.         //is anything except 0 but for now just throw it away.
  193.         User::WaitForRequest(m_reqStat);
  194.     }
  195.     else
  196.     {
  197.         //Kill our selves....
  198.         m_pThread->Kill(unExitCode);
  199.     }
  200.     
  201.     return HXR_OK;
  202. }
  203. HX_RESULT HXSymbianThread::SetPriority( UINT32 ulPriority)
  204. {
  205.     HX_RESULT res = HXR_FAIL;
  206.     if( m_pThread)
  207.     {
  208.         m_pThread->SetPriority((TThreadPriority)ulPriority);
  209.         res = HXR_OK;
  210.     }
  211.     return res;
  212. }
  213. HX_RESULT HXSymbianThread::GetPriority( UINT32& ulPriority)
  214. {
  215.     HX_RESULT res = HXR_FAIL;
  216.     if( m_pThread)
  217.     {
  218.         ulPriority = m_pThread->Priority();
  219.         res = HXR_OK;
  220.     }
  221.     return res;
  222. }
  223. HX_RESULT HXSymbianThread::YieldTimeSlice()
  224. {
  225.     //Just sleep for a tiny amount so someone else can
  226.     //run.
  227.     User::After(10);
  228.     return HXR_OK;
  229. }
  230. HX_RESULT HXSymbianThread::GetThreadId(UINT32& ulThreadId)
  231. {
  232.     HX_RESULT res = HXR_FAIL;
  233.     if( m_pThread )
  234.     {
  235.         ulThreadId = m_pThread->Id();
  236.         res = HXR_OK;
  237.     }
  238.     
  239.     return res;
  240. }
  241. ULONG32 HXSymbianThread::GetCurrentThreadID()
  242. {
  243.     return RThread().Id();
  244. }
  245. HX_RESULT HXSymbianThread::Suspend()
  246. {
  247.     HX_RESULT res = HXR_FAIL;
  248.     if( m_pThread )
  249.     {
  250.         m_pThread->Suspend();
  251.         res = HXR_OK;
  252.     }
  253.     
  254.     return res;
  255. }
  256. HX_RESULT HXSymbianThread::Resume()
  257. {
  258.     HX_RESULT res = HXR_FAIL;
  259.     if( m_pThread )
  260.     {
  261.         m_pThread->Resume();
  262.         res = HXR_OK;
  263.     }
  264.     
  265.     return res;
  266. }
  267. HX_RESULT HXSymbianThread::PostMessage(HXThreadMessage* pMsg, void* pWindowHandle)
  268. {
  269.     HX_RESULT retVal = HXR_OK;
  270.     
  271.     //Assert that we don't use pWindowHandle. 
  272.     HX_ASSERT( pWindowHandle == NULL );
  273.     
  274.     //To mimic the windows PostMessage we must COPY the pMsg and put
  275.     //it on our que. pMsg is going to go out of scope most likely
  276.     if( NULL != pMsg )
  277.     {
  278.         HXThreadMessage *pMsgTmp = new HXThreadMessage(pMsg);
  279.         if( pMsgTmp == NULL )
  280.         {
  281.             retVal = HXR_OUTOFMEMORY;
  282.         }
  283.         else
  284.         {
  285.             //Lock the mutex protecting the message que.
  286.             m_pmtxQue->Lock();
  287.             
  288.             m_messageQue.AddTail((void*)pMsgTmp);
  289.             
  290.             //If we were empty the the GetMessage thread could have
  291.             //been waiting on us to post. Signal it.
  292.             m_pSemMessageCount->Signal(); 
  293.             m_pmtxQue->Unlock();
  294.         }
  295.     }
  296.     
  297.     return retVal;
  298. }
  299. HX_RESULT HXSymbianThread::GetMessage( HXThreadMessage* pMsg, 
  300.                                      UINT32 ulMsgFilterMin, 
  301.                                      UINT32 ulMsgFilterMax)
  302. {
  303.     HX_RESULT retVal = HXR_OK;
  304.     //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
  305.     HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
  306.     HX_ASSERT( pMsg );
  307.     
  308.     //We must pop the next message, COPY it into pMsg and delete our copy.
  309.     if( pMsg != NULL )
  310.     {
  311.         //Wait until there is a message.
  312.         m_pSemMessageCount->Wait();
  313.         
  314.         //Protect the que.
  315.         m_pmtxQue->Lock();
  316.         //Sanity check.
  317.         HX_ASSERT( !m_messageQue.IsEmpty() );
  318.         
  319.         HXThreadMessage* pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
  320.         if( pMsgTmp != NULL )
  321.         {
  322.             pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  323.             pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  324.             pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  325.             pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  326.             
  327.             //free it.
  328.             HX_DELETE( pMsgTmp );
  329.         }
  330.         else
  331.         {
  332.             HX_ASSERT( "que panic" == NULL );
  333.         }
  334.         m_pmtxQue->Unlock();
  335.     }
  336.     
  337.     return retVal;
  338. }
  339. HX_RESULT HXSymbianThread::PeekMessageMatching( HXThreadMessage* pMsg,
  340.                                               HXThreadMessage* pMatch,
  341.                                               BOOL bRemoveMessage )
  342. {
  343.     HX_RESULT retVal = HXR_OK;
  344.         
  345.     HX_ASSERT( pMsg );
  346.     HX_ASSERT( pMatch );
  347.      
  348.     if( pMsg != NULL && pMatch!=NULL )
  349.     {
  350.         //Protect the que.
  351.         m_pmtxQue->Lock();
  352.         //Sanity check.
  353.         if( !m_messageQue.IsEmpty() )
  354.         {
  355.             HXThreadMessage* pMsgTmp = NULL;
  356.             //Loop throught the messages and find a matching
  357.             //one.
  358.             BOOL bSkipMessage  = (pMatch->m_ulMessage==0);
  359.             BOOL bSkipParam1   = (pMatch->m_pParam1==NULL);
  360.             BOOL bSkipParam2   = (pMatch->m_pParam2==NULL);
  361.             BOOL bSkipPlatform = (pMatch->m_pPlatformSpecificData==NULL);
  362.             CHXSimpleList::Iterator i;
  363.             
  364.             for( i=m_messageQue.Begin(); i!=m_messageQue.End(); ++i)
  365.             {
  366.                 pMsgTmp = (HXThreadMessage*)(*i);
  367.                 //Does it match?
  368.                 if( bSkipMessage || pMatch->m_ulMessage==pMsgTmp->m_ulMessage )
  369.                     if( bSkipParam1 || pMatch->m_pParam1==pMsgTmp->m_pParam1 )
  370.                         if( bSkipParam2 || pMatch->m_pParam2==pMsgTmp->m_pParam2 )
  371.                             if( bSkipPlatform || pMatch->m_pPlatformSpecificData==pMsgTmp->m_pPlatformSpecificData )
  372.                                 break;
  373.             }
  374.             //Did we find a match?
  375.             if( i != m_messageQue.End())
  376.             {
  377.                 //We found one!
  378.                 pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  379.                 pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  380.                 pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  381.                 pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  382.                 
  383.                 //Only free it if we removed it from the queue.
  384.                 if( bRemoveMessage )
  385.                 {
  386.                     //XXXgfw That has to be a better way than this. We
  387.                     //have the iterator up above. How do you delete with
  388.                     //one.
  389.                     LISTPOSITION listpos = m_messageQue.Find(pMsgTmp);
  390.                     HX_ASSERT( listpos );
  391.                     if(listpos)
  392.                     {
  393.                         m_messageQue.RemoveAt(listpos);
  394.                     }
  395.                     HX_DELETE( pMsgTmp );
  396.                 }
  397.             }
  398.             else
  399.             {
  400.                 retVal=HXR_FAIL;
  401.             }
  402.         }
  403.         else
  404.         {
  405.             //There was no message to get
  406.             retVal=HXR_FAIL;
  407.         }
  408.         m_pmtxQue->Unlock();
  409.     }
  410.     return retVal;
  411. }
  412. HX_RESULT HXSymbianThread::PeekMessage( HXThreadMessage* pMsg,
  413.                                       UINT32 ulMsgFilterMin,
  414.                                       UINT32 ulMsgFilterMax,
  415.                                       BOOL   bRemoveMessage
  416.                                       )
  417. {
  418.     HX_RESULT retVal = HXR_OK;
  419.     //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
  420.     HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
  421.     HX_ASSERT( pMsg );
  422.     
  423.     //We must pop the next message, COPY it into pMsg and delete our copy.
  424.     if( pMsg != NULL ) 
  425.     {
  426.         //Protect the que.
  427.         m_pmtxQue->Lock();
  428.         //Sanity check.
  429.         if( !m_messageQue.IsEmpty() )
  430.         {
  431.             HXThreadMessage* pMsgTmp = NULL;
  432.             //Do we romove the message or peek at it?
  433.             if( bRemoveMessage )
  434.             {
  435.                 pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
  436.             }
  437.             else
  438.             {
  439.                 pMsgTmp = (HXThreadMessage*)m_messageQue.GetHead();
  440.             }
  441.                 
  442.             if( pMsgTmp != NULL )
  443.             {
  444.                 pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  445.                 pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  446.                 pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  447.                 pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  448.                 
  449.                 //Only free it if we removed it from the queue.
  450.                 if( bRemoveMessage )
  451.                     HX_DELETE( pMsgTmp );
  452.             }
  453.             else
  454.             {
  455.                 HX_ASSERT( "que panic" == NULL );
  456.             }
  457.         }
  458.         else
  459.         {
  460.             //There was no message to get
  461.             retVal=HXR_FAIL;
  462.         }
  463.         m_pmtxQue->Unlock();
  464.     }
  465.     return retVal;
  466. }
  467. HX_RESULT HXSymbianThread::DispatchMessage(HXThreadMessage* pMsg)
  468. {
  469.     HX_ASSERT( "HXSymbianThread::DispatchMessage is not implemented yet." == NULL );
  470.     return HXR_FAIL;
  471. }
  472. TInt HXSymbianThread::_ThreadWrapper(TAny* pExecStruct)
  473. {
  474.     TInt nRetVal = KErrNone;
  475.     
  476.     st_execStruct* pstExec = (st_execStruct*)pExecStruct;
  477.     
  478.     //Install a handle to the global manager for this thread.
  479.     HXGlobalManInstance::SetInstance(pstExec->pGlobalManager);
  480.     
  481.     //Install an active Scheduler for this thread.
  482.     CActiveScheduler* pSched = new CActiveScheduler();
  483.     CActiveScheduler::Install(pSched);
  484.     
  485.     //Call the thread.
  486.     nRetVal =  pstExec->pfExecProc(pstExec->pExecArg);
  487.     CActiveScheduler::Install(0);
  488.     HX_DELETE(pSched);
  489.     
  490.     return nRetVal;
  491. }
  492. //=======================================================================
  493. //
  494. //                      HXSymbianMutex
  495. //                   ------------------
  496. //
  497. //=======================================================================
  498. HXSymbianMutex::HXSymbianMutex()
  499.     : m_pCritSec(NULL),
  500.       m_bInited(FALSE),
  501.       m_pCritSecLck(NULL),
  502.       m_ulOwnerThread(0),
  503.       m_ulLockCount(0)
  504. {
  505. }
  506.     
  507. HXSymbianMutex::~HXSymbianMutex()
  508. {
  509.     if( m_pCritSec )
  510.     {
  511.         m_pCritSec->Close();
  512.         HX_DELETE(m_pCritSec);
  513.     }
  514.     if( m_pCritSecLck )
  515.     {
  516.         m_pCritSecLck->Close();
  517.         HX_DELETE(m_pCritSecLck);
  518.     }
  519.     m_bInited = FALSE;
  520. }
  521. HX_RESULT HXSymbianMutex::_Init()
  522. {
  523.     TInt      err1 = KErrNone;
  524.     TInt      err2 = KErrNone;
  525.     HX_RESULT res  = HXR_FAIL;
  526.     
  527.     if( !m_bInited)
  528.     {
  529.         m_pCritSec = new RCriticalSection;
  530.         if( m_pCritSec )
  531.         {
  532.             err1 = m_pCritSec->CreateLocal();
  533.         }
  534.         m_pCritSecLck = new RCriticalSection;
  535.         if( m_pCritSecLck )
  536.         {
  537.             err2 = m_pCritSecLck->CreateLocal();
  538.         }
  539.     }
  540.     if( m_pCritSec && m_pCritSecLck && KErrNone==err1 && KErrNone==err2 )
  541.     {
  542.         res = HXR_OK;
  543.         m_bInited = TRUE;
  544.     }
  545.     return res;
  546. }
  547. HX_RESULT HXSymbianMutex::Lock()
  548. {
  549.     HX_RESULT res = HXR_OK;
  550.     RThread   me;
  551.     
  552.     //XXXgfw I wonder if the check every time is too much of a perf
  553.     //hit.
  554.     if( !m_bInited )
  555.     {
  556.         res = _Init();
  557.         if( FAILED(res) )
  558.             return res;
  559.     }
  560.     m_pCritSecLck->Wait();
  561.     if( m_ulOwnerThread != me.Id() )
  562.     {
  563.         m_pCritSecLck->Signal();
  564.         m_pCritSec->Wait();
  565.         m_pCritSecLck->Wait();
  566.         m_ulOwnerThread = me.Id();
  567.         //Make sure the lock count is always zero when we hand off a
  568.         //mutex to another thread. Otherwise there was too many
  569.         //unlocks or the like.
  570.         HX_ASSERT( m_ulLockCount == 0 );
  571.         m_ulLockCount   = 1;
  572.     }
  573.     else
  574.     {
  575.         //We alread have it locked. Just increment the lock count
  576.         m_ulLockCount++;
  577.     }
  578.     m_pCritSecLck->Signal();
  579.     return res;
  580. }
  581.     
  582. HX_RESULT HXSymbianMutex::Unlock()
  583. {
  584.     HX_RESULT res = HXR_OK;
  585.     RThread me;
  586.     
  587.     //XXXgfw I wonder if the check every time is too much of a perf
  588.     //hit.
  589.     if( !m_bInited )
  590.     {
  591.         res = _Init();
  592.         if( FAILED(res) )
  593.             return res;
  594.     }
  595.     m_pCritSecLck->Wait();
  596.     HX_ASSERT( m_ulLockCount != 0 && m_ulOwnerThread == me.Id() );
  597.     if( m_ulLockCount == 0 || m_ulOwnerThread!=me.Id() )
  598.     {
  599.         m_pCritSecLck->Signal();
  600.         return HXR_FAIL;
  601.     }
  602.     
  603.     if( m_ulLockCount == 1 )
  604.     {
  605.         //We are really done with it. Do the real unlock now.
  606.         m_pCritSec->Signal();
  607.         m_ulOwnerThread = 0;
  608.         m_ulLockCount=0;
  609.     }
  610.     else
  611.     {
  612.         m_ulLockCount--;
  613.     }
  614.     m_pCritSecLck->Signal();
  615.     return res;
  616. }
  617.     
  618. HX_RESULT HXSymbianMutex::Trylock()
  619. {
  620.     HX_RESULT res = HXR_OK;
  621.     RThread me;
  622.     
  623.     //XXXgfw I wonder if the check every time is too much of a perf
  624.     //hit.
  625.     if( !m_bInited )
  626.     {
  627.         res = _Init();
  628.         if( FAILED(res) )
  629.             return res;
  630.     }
  631.     m_pCritSecLck->Wait();
  632.     if( m_pCritSec->IsBlocked() )
  633.     {
  634.         //Someone has it.
  635.         HX_ASSERT( m_ulOwnerThread != 0 );
  636.         HX_ASSERT( m_ulLockCount != 0 );
  637.         if( m_ulOwnerThread == me.Id() )
  638.         {
  639.             //It us.
  640.             m_ulLockCount++;
  641.             res = HXR_OK;
  642.         }
  643.         else
  644.         {
  645.             //We would block on it.
  646.             res = HXR_FAIL;
  647.         }
  648.     }
  649.     else
  650.     {
  651.         //No one has it. grab it now.
  652.         HX_ASSERT( m_ulOwnerThread == 0 );
  653.         HX_ASSERT( m_ulLockCount == 0 );
  654.         m_pCritSec->Wait();
  655.         m_ulLockCount=1;
  656.         m_ulOwnerThread = me.Id();
  657.         res = HXR_OK;
  658.     }
  659.     m_pCritSecLck->Signal();
  660.     
  661.     return res;
  662. }
  663. //=======================================================================
  664. //
  665. //                     HXSymbianEvent
  666. //                  ------------------
  667. //
  668. //=======================================================================   
  669. HXSymbianEvent::HXSymbianEvent(const char* pEventName, BOOL bManualReset)
  670.     : m_bIsManualReset( bManualReset ),
  671.       m_bEventIsSet(FALSE),
  672.       m_pCondLock(NULL),
  673.       m_pCond(NULL)
  674. {
  675.     //
  676.     //  NOTE: Because of the way the windows Cond vars work we have:
  677.     //
  678.     //   bManualReset==1  Once we signal once, all other signal/wait
  679.     //                    calls are noops. All threads awake.
  680.     //   bManualReset==0  Once signaled we retain until someone Waits.
  681.     //                    Once someone waits, only one thread wakes up
  682.     //                    and the signal is reset.
  683.     //
  684.     m_pCond = new RSemaphore();
  685.     if( m_pCond )
  686.     {
  687.         m_pCond->CreateLocal(0);
  688.     }
  689.     HXMutex* pTmp =  NULL;
  690.     HXMutex::MakeMutex(pTmp);
  691.     m_pCondLock = (HXSymbianMutex*)pTmp;
  692.     HX_ASSERT( m_pCondLock && m_pCond );
  693.     //We ignore the EventName for now...
  694. }
  695. HXSymbianEvent::~HXSymbianEvent()
  696. {
  697.     if( m_pCond )
  698.     {
  699.         m_pCond->Close();
  700.         HX_DELETE( m_pCond );
  701.     }
  702.     HX_DELETE(m_pCondLock);
  703. }
  704. HX_RESULT HXSymbianEvent::Wait( UINT32 uTimeoutPeriod )
  705. {
  706.     HX_RESULT res = HXR_OK;
  707.     //Symbian does not support timed waits...
  708.     HX_ASSERT( uTimeoutPeriod==ALLFS);
  709.     m_pCondLock->Lock();
  710.     
  711.     //Check to see if this event has already been signaled.
  712.     if( !m_bEventIsSet )
  713.     {
  714.         //We must wait on the event then....
  715.         m_pCondLock->Unlock();
  716.         m_pCond->Wait();
  717.         m_pCondLock->Lock();
  718.     }
  719.     //If we are not manual reset and we are signaled. reset the
  720.     //signaled flag before returning otherwise leave it signaled for
  721.     //everyone else that comes in to wait.
  722.     if( !m_bIsManualReset )
  723.         m_bEventIsSet = FALSE;
  724.     
  725.     //Now that we have waited
  726.     m_pCondLock->Unlock();
  727.     return res;
  728. }
  729. HX_RESULT HXSymbianEvent::ResetEvent()
  730. {
  731.     m_pCondLock->Lock();
  732.     m_bEventIsSet = FALSE;
  733.     m_pCondLock->Unlock();
  734.     return HXR_OK;
  735. }
  736. HX_RESULT HXSymbianEvent::SignalEvent()
  737. {
  738.     //Lock it all down.
  739.     m_pCondLock->Lock();
  740.     //Whether or not this is manual reset, set the state.
  741.     m_bEventIsSet = TRUE;
  742.     //See if anyone is waiting on this event or not...
  743.     int nCount = m_pCond->Count();
  744.     //Signal the event depending on what type it is.
  745.     if( m_bIsManualReset && nCount<0 )
  746.     {
  747.         //Manual reset, wake up all threads. All waits become noops
  748.         //until the event is reset.
  749.         
  750.         //XXXgfw symbian has no 'broadcast' kind of option. We can
  751.         //fake it by getting the sem count and calling signal that
  752.         //much.
  753.         m_pCond->Signal(Abs(nCount));
  754.     }
  755.     else
  756.     {
  757.         m_pCond->Signal();
  758.     }
  759.     
  760.     //Unlock it and go.
  761.     m_pCondLock->Unlock();
  762.     return HXR_OK;
  763. }
  764. void* HXSymbianEvent::GetEventHandle()
  765. {
  766.     return (void*)m_pCond;
  767. }
  768. //=======================================================================
  769. //
  770. //                     HXSymbianAsyncTimer
  771. //                  -----------------------
  772. //
  773. //=======================================================================   
  774. UINT32 HXSymbianAsyncTimer::SetTimer(ULONG32 ulTimeOut, HXThread* pReceivingThread )
  775. {
  776.     //lock it.
  777.     GetMapLock()->Lock();
  778.     ULONG32 ulTimerID = 0;
  779.     
  780.     HX_ASSERT( ulTimeOut != 0 );
  781.     HX_ASSERT( pReceivingThread != NULL );
  782.     
  783.     HXSymbianAsyncTimerImp* pTimer = CreateTimer();
  784.     HX_ASSERT( pTimer != NULL );
  785.     if( pTimer != NULL )
  786.     {
  787. pTimer->Init(ulTimeOut, pReceivingThread );
  788.         //Add new timer to map.
  789.         ulTimerID = pTimer->GetID();
  790.         GetMapTimers().SetAt( ulTimerID, (void*)pTimer );    
  791.     }
  792.     
  793.     //unlock the map.
  794.     GetMapLock()->Unlock();
  795.     return ulTimerID;
  796. }
  797. UINT32 HXSymbianAsyncTimer::SetTimer(ULONG32 ulTimeOut, TIMERPROC pfExecFunc )
  798. {
  799.     //lock it.
  800.     GetMapLock()->Lock();
  801.     ULONG32 ulTimerID = 0;
  802.     
  803.     HX_ASSERT( ulTimeOut != 0 );
  804.     HX_ASSERT( pfExecFunc != NULL );
  805.     
  806.     HXSymbianAsyncTimerImp* pTimer = CreateTimer();
  807.     HX_ASSERT( pTimer != NULL );
  808.     if( pTimer != NULL )
  809.     {
  810. pTimer->Init(ulTimeOut, pfExecFunc );
  811.         //Add new timer to map.
  812.         ulTimerID = pTimer->GetID();
  813.         GetMapTimers().SetAt( ulTimerID, (void*)pTimer );    
  814.     }
  815.     
  816.     //unlock the map.
  817.     GetMapLock()->Unlock();
  818.     return ulTimerID;
  819. }
  820. BOOL HXSymbianAsyncTimer::KillTimer(UINT32 ulTimerID )
  821. {
  822.     //lock it.
  823.     GetMapLock()->Lock();
  824.     BOOL  bRetVal = FALSE;
  825.     void* pTimer  = NULL;
  826.     HX_ASSERT( ulTimerID != 0 );
  827.     
  828.     if( GetMapTimers().Lookup( ulTimerID, pTimer ) )
  829.     {
  830.         //Found it.
  831.         HXSymbianAsyncTimerImp* pTmp = (HXSymbianAsyncTimerImp*)pTimer;
  832.         bRetVal = TRUE;
  833. // delete is not used because the timer
  834. // may need to delay it's destruction.
  835. // The Destroy() call hides this detail
  836.         pTmp->Destroy(); 
  837. pTmp = 0;
  838.         GetMapTimers().RemoveKey( ulTimerID );
  839.     }
  840.     //unlock the map.
  841.     GetMapLock()->Unlock();
  842.     return bRetVal;
  843. }
  844. HXSymbianAsyncTimerImp* HXSymbianAsyncTimer::CreateTimer()
  845. {
  846.     HXSymbianAsyncTimerImp* pRet = 0;
  847. #if defined USE_SYMBIAN_THREADS_FOR_ASYNCTIMERS
  848.     pRet = new HXSymbianThreadAsyncTimer;
  849. #else
  850.     pRet = new HXSymbianRTimerAsyncTimer;
  851. #endif
  852.     return pRet;
  853. }
  854. static void DestroyMapLock(GlobalType pObj)
  855. {
  856.     HXMutex* pMapLock = (HXMutex*)pObj;
  857.     delete pMapLock;
  858. }
  859. HXMutex* HXSymbianAsyncTimer::GetMapLock()
  860. {
  861.     static const HXMutex* const z_pMapLock = NULL;
  862.     HXGlobalManager* pGM = HXGlobalManager::Instance();
  863.     GlobalPtr ptr = pGM->Get(&z_pMapLock);
  864.     if (!ptr)
  865.     {
  866. HXMutex* pMapLock = 0;
  867. HXMutex::MakeMutex(pMapLock);
  868. ptr = pGM->Add(&z_pMapLock, pMapLock, &DestroyMapLock);
  869.     }
  870.     return  (HXMutex*)(*ptr);
  871. }
  872. CHXMapLongToObj& HXSymbianAsyncTimer::GetMapTimers()
  873. {
  874.     static const CHXMapLongToObj* const z_pMapTimers = NULL;
  875.     return HXGlobalMapLongToObj::Get(&z_pMapTimers);
  876. }