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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: UnixThreads.cpp,v 1.8.2.3 2004/07/09 01:43:30 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. #ifdef _UNIX_THREADS_SUPPORTED
  51. #include "hxtypes.h" //for UINT32
  52. #include "hxresult.h" //for HX_RESULT
  53. #include <errno.h>
  54. #include "UnixThreads.h"
  55. #include <signal.h>   //for SIGKILL
  56. #include "hxassert.h" //for HX_ASSERT
  57. #include "microsleep.h"
  58. #include "hxmsgs.h" //for HXMSG_ASYNC_TIMER message.
  59. #include "hxtick.h"  //for GetTickCount()
  60. //=================================================================
  61. // In this section here include the OS specific headerfiles for
  62. // each implementation.
  63. //=================================================================
  64. #if defined( _LINUX ) || defined(_HPUX) || defined(_MAC_UNIX)
  65. #include <pthread.h>
  66. #include <semaphore.h>
  67. #include "pthreadthreads.h"
  68. #endif
  69. #if defined( _SOLARIS )
  70. #include <synch.h>
  71. #include <thread.h>
  72. #include "solaristhreads.h"
  73. #endif
  74. #if defined( _IRIX )
  75. #endif
  76. #if defined( _AIX )
  77. #endif
  78. //=======================================================================
  79. //
  80. //                      HXUnixThread
  81. //                   ------------------
  82. //
  83. //=======================================================================
  84. HXUnixThread::HXUnixThread() 
  85.     : m_threadID(0),
  86.       m_messageQue(),
  87.       m_pCond(NULL),
  88.       m_pCondLock(NULL)
  89. {
  90.     //Create the condition with its associated mutex.
  91.     //Do NOT delete the mutex that the cond makes for us....
  92.     HXUnixCondition::MakeCondition(m_pCond, m_pCondLock );
  93.     HX_ASSERT( m_pCondLock && m_pCond);
  94. }
  95. HXUnixThread::~HXUnixThread()
  96. {
  97.     if( m_threadID != 0 )
  98.     {
  99.         //XXXgfw Had to get rid of this. Some threads are destroyed on their own thread.
  100.         //HX_ASSERT( "Thread has not been joined! Memory/mutex leaks????n" == NULL );
  101.         //We can try to cancel here but it won't work!
  102.         //The thread may not even honor the cancel request. If it does and has not
  103.         //set up cancelation/clean-up routine you better hope that it doesn't have
  104.         //any mutexes locked or resources open!!! Just don't do it.
  105.     }
  106.     //Clean up message que.
  107.     while( !m_messageQue.IsEmpty() )
  108.     {
  109.         HXThreadMessage* pTmp = (HXThreadMessage *)(m_messageQue.RemoveHead());
  110.         HX_DELETE( pTmp );
  111.     }
  112.     HX_DELETE( m_pCond );
  113.     m_pCondLock = NULL;
  114. }
  115. HX_RESULT HXUnixThread::MakeThread(HXThread*& pThread )
  116. {
  117. #if defined( _LINUX ) || defined (_HPUX) || defined(_MAC_UNIX)
  118.     pThread = new HXPthreadThread();
  119. #elif defined( _SOLARIS )
  120.     pThread = new HXSolarisThread();
  121. #else
  122.     HX_ASSERT( "No unix thread for this platform" == NULL );
  123. #endif    
  124.     if(pThread == NULL)
  125.     {
  126.         HX_ASSERT( 0 );
  127. return HXR_OUTOFMEMORY;
  128.     }
  129.     
  130.     return HXR_OK;
  131. }
  132. //ulCreationFlags is ignored. We can't suspend pthreads and that is the only
  133. //flag possible right now.
  134. HX_RESULT HXUnixThread::CreateThread( void*(pfExecFunc(void*)), void* pArg, ULONG32 ulCreationFlags)
  135. {
  136.     HX_RESULT retVal = HXR_OK;
  137.     
  138.     HX_ASSERT( m_threadID==0 );
  139.     if( m_threadID != 0)
  140.     {
  141.         retVal = HXR_UNEXPECTED;
  142.     }
  143.     else
  144.     {
  145.         if( _thread_create( m_threadID, pfExecFunc, pArg ) != HXR_OK )
  146.         {
  147.             retVal = HXR_FAIL;
  148.             m_threadID = 0;
  149.         }
  150.     }
  151.     return retVal;
  152. }
  153. HX_RESULT HXUnixThread::Exit(UINT32 unExitCode)
  154. {
  155.     //Make sure that only the thread that was created it calling the exit
  156.     //routine. If the parent thread wants to kill it maybe we should have
  157.     //a Kill method or something.
  158.     if( 0 == m_threadID )
  159.     {
  160.         //Thread has already gone. Just return.
  161.         return HXR_UNEXPECTED;
  162.     }
  163.     
  164.     if( m_threadID != GetCurrentThreadID() )
  165.     {
  166.         //Ok, because of the way winthrd.cpp does it, this call also
  167.         //acts as a 'pthread_join' when the calling thread isn't the
  168.         //m_threadID.
  169.         
  170.         //Also, it looks like this method isn't set up to look at the
  171.         //return value of the thread. We could return HXR_FAIL is it
  172.         //is anything except 0 but for now just throw it away.
  173.         JoinThread();
  174.     }
  175.     else
  176.     {
  177.         _thread_exit( unExitCode );
  178.     }
  179.     
  180.     return HXR_OK;
  181. }
  182. HX_RESULT HXUnixThread::SetPriority( UINT32 ulPriority)
  183. {
  184.     //XXXGFW not supported yet.
  185. //     struct sched_param stThreadParams;
  186. //     int    nPolicy = 0;
  187. //     int    nRet    = -1;
  188. //     HX_ASSERT( m_threadID );
  189. //     if( m_threadID != 0)
  190. //     {
  191. //         nPolicy = SCHED_OTHER;
  192. //         stThreadParams.sched_priority = (int)ulPriority; 
  193.         
  194. //         nRet = pthread_setschedparam( m_threadID, nPolicy, &stThreadParams );
  195. //     }
  196.     
  197. //     return nRet==0 ? HXR_OK : HXR_FAIL;
  198.     return HXR_OK;
  199. }
  200. //XXXgfw not tested yet!!!!!!! ...but should work. :)
  201. HX_RESULT HXUnixThread::GetPriority( UINT32& ulPriority)
  202. {
  203.     //XXXGFW not supported yet.....
  204. //     struct sched_param stThreadParams;
  205. //     int    nPolicy = 0;
  206. //     int    nRet    = -1;
  207.     
  208. //     HX_ASSERT( m_threadID );
  209.     
  210. //     if( m_threadID != 0)
  211. //     {
  212. //         nRet = pthread_getschedparam( m_threadID, &nPolicy, &stThreadParams );
  213. //         ulPriority = stThreadParams.sched_priority;
  214. //     }
  215.     
  216. //     return nRet==0 ? HXR_OK : HXR_FAIL;
  217.     return HXR_OK;
  218. }
  219. HX_RESULT HXUnixThread::YieldTimeSlice()
  220. {
  221.     microsleep(1);
  222.     return HXR_OK;
  223. }
  224. HX_RESULT HXUnixThread::GetThreadId(UINT32& ulThreadId)
  225. {
  226.     ulThreadId = m_threadID;
  227.     return HXR_OK;
  228. }
  229. ULONG32 HXUnixThread::GetCurrentThreadID()
  230. {
  231.     return _thread_self();
  232. }
  233. //Cancels the thread that was created.
  234. HX_RESULT HXUnixThread::CancelThread()
  235. {
  236.     HX_ASSERT( "This isn't portable. Don't use it" == NULL );
  237.     if( 0 == m_threadID )
  238.     {
  239.         return HXR_UNEXPECTED;
  240.     }
  241.     _thread_cancel(m_threadID);
  242.     return HXR_OK;
  243. }
  244. //Must wait for our child thread to exit and return the ret code.
  245. ULONG32 HXUnixThread::JoinThread()
  246. {
  247.     ULONG32 ulRetVal = 0;
  248.     if( 0 == m_threadID || GetCurrentThreadID() == m_threadID )
  249.     {
  250.         return HXR_UNEXPECTED;
  251.     }
  252.     ulRetVal = _thread_join( m_threadID );
  253.     //Thread has exited and we are done.
  254.     m_threadID = 0;
  255.     
  256.     return ulRetVal;
  257. }
  258. HX_RESULT HXUnixThread::Suspend()
  259. {
  260.     HX_ASSERT( "HXUnixThread::Suspend is not implemented yet." == NULL );
  261.     return HXR_FAIL;
  262. }
  263. HX_RESULT HXUnixThread::Resume()
  264. {
  265.     HX_ASSERT( "HXUnixThread::Resume  is not implemented yet." == NULL );
  266.     return HXR_FAIL;
  267. }
  268. HX_RESULT HXUnixThread::PostMessage(HXThreadMessage* pMsg, void* pWindowHandle)
  269. {
  270.     HX_RESULT retVal = HXR_OK;
  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_pCondLock->Lock();
  287.             m_messageQue.AddTail((void*)pMsgTmp);
  288.             
  289.             //If we were empty the the GetMessage thread could have been waiting 
  290.             //on us to post. Signal it.
  291.             m_pCond->Signal();
  292.             m_pCondLock->Unlock();
  293.         }
  294.     }
  295.     
  296.     return retVal;
  297. }
  298. HX_RESULT HXUnixThread::GetMessage( HXThreadMessage* pMsg, 
  299.                                      UINT32 ulMsgFilterMin, 
  300.                                      UINT32 ulMsgFilterMax)
  301. {
  302.     HX_RESULT retVal = HXR_OK;
  303.     //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
  304.     HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
  305.     HX_ASSERT( pMsg );
  306.     
  307.     //We must pop the next message, COPY it into pMsg and delete our copy.
  308.     if( pMsg != NULL )
  309.     {
  310.         //Get access
  311.         m_pCondLock->Lock();
  312.         //If the que is empty we need to block and wait.
  313.         while( m_messageQue.IsEmpty() )
  314.         {
  315.             m_pCond->Wait();
  316.         }
  317.         if( !m_messageQue.IsEmpty())
  318.         {
  319.             HXThreadMessage* pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
  320.             pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  321.             pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  322.             pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  323.             pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  324.             
  325.             //free it.
  326.             HX_DELETE( pMsgTmp );
  327.         }
  328.         else
  329.         {
  330.             HX_ASSERT( "que panic" == NULL );
  331.         }
  332.         m_pCondLock->Unlock();
  333.     }
  334.     
  335.     return retVal;
  336. }
  337. HX_RESULT HXUnixThread::PeekMessageMatching( HXThreadMessage* pMsg,
  338.                                               HXThreadMessage* pMatch,
  339.                                               BOOL bRemoveMessage )
  340. {
  341.     HX_RESULT retVal = HXR_OK;
  342.         
  343.     HX_ASSERT( pMsg );
  344.     HX_ASSERT( pMatch );
  345.      
  346.     if( pMsg != NULL && pMatch!=NULL )
  347.     {
  348.         //Protect the que.
  349.         m_pCondLock->Lock();
  350.         if( !m_messageQue.IsEmpty() )
  351.         {
  352.             HXThreadMessage* pMsgTmp = NULL;
  353.             //Loop throught the messages and find a matching
  354.             //one.
  355.             BOOL bSkipMessage  = (pMatch->m_ulMessage==0);
  356.             BOOL bSkipParam1   = (pMatch->m_pParam1==NULL);
  357.             BOOL bSkipParam2   = (pMatch->m_pParam2==NULL);
  358.             BOOL bSkipPlatform = (pMatch->m_pPlatformSpecificData==NULL);
  359.             CHXSimpleList::Iterator i;
  360.             
  361.             for( i=m_messageQue.Begin(); i!=m_messageQue.End(); ++i)
  362.             {
  363.                 pMsgTmp = (HXThreadMessage*)(*i);
  364.                 //Does it match?
  365.                 if( bSkipMessage || pMatch->m_ulMessage==pMsgTmp->m_ulMessage )
  366.                     if( bSkipParam1 || pMatch->m_pParam1==pMsgTmp->m_pParam1 )
  367.                         if( bSkipParam2 || pMatch->m_pParam2==pMsgTmp->m_pParam2 )
  368.                             if( bSkipPlatform || pMatch->m_pPlatformSpecificData==pMsgTmp->m_pPlatformSpecificData )
  369.                                 break;
  370.             }
  371.             //Did we find a match?
  372.             if( i != m_messageQue.End())
  373.             {
  374.                 //We found one!
  375.                 pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  376.                 pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  377.                 pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  378.                 pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  379.                 
  380.                 //Only free it if we removed it from the queue.
  381.                 if( bRemoveMessage )
  382.                 {
  383.                     //XXXgfw That has to be a better way than this. We
  384.                     //have the iterator up above. How do you delete with
  385.                     //one.
  386.                     LISTPOSITION listpos = m_messageQue.Find(pMsgTmp);
  387.                     HX_ASSERT( listpos );
  388.                     if(listpos)
  389.                     {
  390.                         m_messageQue.RemoveAt(listpos);
  391.                     }
  392.                     HX_DELETE( pMsgTmp );
  393.                 }
  394.             }
  395.             else
  396.             {
  397.                 retVal=HXR_FAIL;
  398.             }
  399.         }
  400.         else
  401.         {
  402.             //There was no message to get
  403.             retVal=HXR_FAIL;
  404.         }
  405.         m_pCondLock->Unlock();
  406.     }
  407.     return retVal;
  408. }
  409. HX_RESULT HXUnixThread::PeekMessage( HXThreadMessage* pMsg,
  410.                                       UINT32 ulMsgFilterMin,
  411.                                       UINT32 ulMsgFilterMax,
  412.                                       BOOL   bRemoveMessage
  413.                                       )
  414. {
  415.     HX_RESULT retVal = HXR_OK;
  416.     //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
  417.     HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
  418.     HX_ASSERT( pMsg );
  419.     
  420.     //We must pop the next message, COPY it into pMsg and delete our copy.
  421.     if( pMsg != NULL )
  422.     {
  423.         //Protect the que.
  424.         m_pCondLock->Lock();
  425.         if( !m_messageQue.IsEmpty() )
  426.         {
  427.             HXThreadMessage* pMsgTmp = NULL;
  428.             //Do we romove the message or peek at it?
  429.             if( bRemoveMessage )
  430.             {
  431.                 pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
  432.             }
  433.             else
  434.             {
  435.                 pMsgTmp = (HXThreadMessage*)m_messageQue.GetHead();
  436.             }
  437.                 
  438.             if( pMsgTmp != NULL )
  439.             {
  440.                 pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
  441.                 pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
  442.                 pMsg->m_pParam2               = pMsgTmp->m_pParam2;
  443.                 pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
  444.                 
  445.                 //Only free it if we removed it from the queue.
  446.                 if( bRemoveMessage )
  447.                     HX_DELETE( pMsgTmp );
  448.             }
  449.             else
  450.             {
  451.                 HX_ASSERT( "que panic" == NULL );
  452.             }
  453.         }
  454.         else
  455.         {
  456.             //There was no message to get
  457.             retVal=HXR_FAIL;
  458.         }
  459.         m_pCondLock->Unlock();
  460.     }
  461.     return retVal;
  462. }
  463. HX_RESULT HXUnixThread::DispatchMessage(HXThreadMessage* pMsg)
  464. {
  465.     HX_ASSERT( "HXUnixThread::DispatchMessage is not implemented yet." == NULL );
  466.     return HXR_FAIL;
  467. }
  468. //=======================================================================
  469. //
  470. //                      HXUnixMutex
  471. //                   ------------------
  472. //
  473. //=======================================================================
  474. HXUnixMutex::HXUnixMutex()
  475. {
  476. }
  477.     
  478. HXUnixMutex::~HXUnixMutex()
  479. {
  480. }
  481. HX_RESULT HXUnixMutex::MakeMutex( HXMutex*& pMutex )
  482. {
  483. #if defined( _LINUX ) || defined(_HPUX) || defined(_MAC_UNIX)
  484.     pMutex = new HXPthreadMutex();
  485. #elif defined( _SOLARIS )
  486.     pMutex = new HXSolarisMutex();
  487. #else
  488.     HX_ASSERT( "No unix mutex for this platform" == NULL );
  489. #endif
  490.     if(pMutex == NULL)
  491.     {
  492.         HX_ASSERT( 0 );
  493. return HXR_OUTOFMEMORY;
  494.     }
  495.     
  496.     return HXR_OK;
  497. }
  498. HX_RESULT HXUnixMutex::Lock()
  499. {
  500.     return _Lock();
  501. }
  502.     
  503. HX_RESULT HXUnixMutex::Unlock()
  504. {
  505.     return _Unlock();
  506. }
  507.     
  508. HX_RESULT HXUnixMutex::Trylock()
  509. {
  510.     return _TryLock();
  511. }
  512. //=======================================================================
  513. //
  514. //                      HXUnixSemaphore
  515. //                   ------------------
  516. //
  517. //=======================================================================
  518. HXUnixSemaphore::HXUnixSemaphore(UINT32 unInitialCount)
  519.     : m_unInitialCount(unInitialCount)
  520. {
  521. }
  522. HXUnixSemaphore::~HXUnixSemaphore()
  523. {
  524. }
  525. HX_RESULT HXUnixSemaphore::MakeSemaphore(HXUnixSemaphore*& pSem)
  526. {
  527. #if defined( _LINUX ) || defined(_HPUX)
  528.     pSem = new HXPthreadSemaphore();
  529. #elif defined(_MAC_UNIX)
  530.     pSem = new HXPthreadMacSemaphore();
  531. #elif defined( _SOLARIS )
  532.     pSem = new HXSolarisSemaphore();
  533. #else
  534.     HX_ASSERT( "No unix semaphore for this platform" == NULL );
  535. #endif
  536.     if(pSem == NULL)
  537.     {
  538.         HX_ASSERT(0);
  539. return HXR_OUTOFMEMORY;
  540.     }
  541.     
  542.     return HXR_OK;
  543. }
  544.  
  545. HX_RESULT HXUnixSemaphore::Post()
  546. {
  547.     return _Post();
  548. }
  549. HX_RESULT HXUnixSemaphore::Wait()
  550. {
  551.     return _Wait();
  552. }
  553. HX_RESULT HXUnixSemaphore::TryWait()
  554. {
  555.     return _TryWait();
  556. }
  557. HX_RESULT HXUnixSemaphore::GetValue( int* pnCount)
  558. {
  559.     return _GetValue( pnCount );
  560. }
  561. //=======================================================================
  562. //
  563. //                      HXUnixEvent
  564. //                   ------------------
  565. //
  566. //=======================================================================   
  567. HXUnixEvent::HXUnixEvent(const char* pEventName, BOOL bManualReset)
  568.     : m_bIsManualReset( bManualReset ),
  569.       m_bEventIsSet(FALSE),
  570.       m_pCondLock(NULL),
  571.       m_pCond(NULL)
  572. {
  573.     //
  574.     //  NOTE: Because of the way the windows Cond vars work we have:
  575.     //
  576.     //   bManualReset==1  Once we signal once, all other signal/wait
  577.     //                    calls are noops. All threads awake.
  578.     //   bManualReset==0  Once signaled we retain until someone Waits.
  579.     //                    Once someone waits, only one thread wakes up
  580.     //                    and the signal is reset.
  581.     //
  582.     //Create the condition with its associated mutex.
  583.     //Do NOT delete the mutex that the cond makes for us....
  584.     HXUnixCondition::MakeCondition(m_pCond, m_pCondLock );
  585.     HX_ASSERT( m_pCondLock && m_pCond);
  586. }
  587. HXUnixEvent::~HXUnixEvent()
  588. {
  589.     //Do NOT delete the mutex that the cond makes for us....
  590.     HX_DELETE( m_pCond );
  591.     m_pCondLock = NULL;
  592. }
  593. HX_RESULT HXUnixEvent::SignalEvent()
  594. {
  595.     //Lock it all down.
  596.     m_pCondLock->Lock();
  597.     //Whether or not this is manual reset, set the state.
  598.     m_bEventIsSet = TRUE;
  599.     //Signal the event depending on what type it is.
  600.     if( m_bIsManualReset )
  601.     {
  602.         //Manual reset, wake up all threads. All waits become noops
  603.         //until the event is reset.
  604.         m_pCond->Broadcast();
  605.     }
  606.     else
  607.     {
  608.         m_pCond->Signal();
  609.     }
  610.     
  611.     //Unlock it and go.
  612.     m_pCondLock->Unlock();
  613.     return HXR_OK;
  614. }
  615. HX_RESULT HXUnixEvent::Wait( UINT32 uTimeoutPeriod )
  616. {
  617.     HX_RESULT res = HXR_OK;
  618.     
  619.     m_pCondLock->Lock();
  620.     //Check to see if this event has already been signaled.
  621.     if( m_bEventIsSet )
  622.     {
  623.         //If we are not manual reset and we are signaled. reset the
  624.         //signaled flag before returning.
  625.         if( !m_bIsManualReset )
  626.         {
  627.             m_bEventIsSet = FALSE;
  628.         }
  629.         m_pCondLock->Unlock();
  630.         return HXR_OK;
  631.     }
  632.     
  633.     //We are not manual reset.
  634.     if(uTimeoutPeriod!=ALLFS)
  635.     {
  636.         //XXXgfw We can be woken up by signals before the event is
  637.         //actually signaled or the time has elapsed. Not sure what to
  638.         //do in that case yet. Since most implementations try to
  639.         //minimize these wakups I will just ignore it for now since we
  640.         //are just using condtionals to mimic Window's events.
  641.         res = m_pCond->TimedWait(uTimeoutPeriod);
  642.     }
  643.     else
  644.     {
  645.         m_pCond->Wait();
  646.     }
  647.     //Now, if we just woke up and the event had been signaled, We need
  648.     //reset the event.
  649.     if( !m_bIsManualReset && m_bEventIsSet )
  650.     {
  651.         m_bEventIsSet = FALSE;
  652.     }
  653.     //Now that we have waited
  654.     m_pCondLock->Unlock();
  655.     return res;
  656. }
  657. HX_RESULT HXUnixEvent::ResetEvent()
  658. {
  659.     m_pCondLock->Lock();
  660.     m_bEventIsSet = FALSE;
  661.     m_pCondLock->Unlock();
  662.     return HXR_OK;
  663. }
  664. void* HXUnixEvent::GetEventHandle()
  665. {
  666.     //XXXgfw This doesn't look like it is used right now. Assuming we
  667.     //just want it to be a unique handle to this event, we can use the
  668.     //this pointer to the cond class we made.
  669.     return (void*)m_pCond;
  670. }
  671. //=======================================================================
  672. //
  673. //                      HXUnixCondition
  674. //                   ---------------------
  675. //
  676. //=======================================================================
  677. HXUnixCondition::HXUnixCondition()
  678. {
  679. };
  680. HXUnixCondition::~HXUnixCondition()
  681. {
  682. };
  683. HX_RESULT HXUnixCondition::MakeCondition( HXUnixCondition*& pCond,
  684.                                           HXUnixMutex*&     pMutex )
  685. {
  686.     HX_ASSERT( pMutex==NULL);
  687.     
  688. #if defined( _LINUX ) && defined(_UNIX_THREADS_SUPPORTED) || defined(_MAC_UNIX)
  689.     pCond = (HXUnixCondition*) new HXPthreadCondition(pMutex);
  690. #elif defined(_SOLARIS)
  691.     pCond = (HXUnixCondition*) new HXSolarisCondition(pMutex);
  692. #else
  693.     HX_ASSERT( "No unix condtional for this platform" == NULL );
  694. #endif
  695.     if(pCond == NULL )
  696.     {
  697.         HX_ASSERT(0);
  698.         return HXR_OUTOFMEMORY;
  699.     }
  700.     HX_ASSERT( pMutex );
  701.     return HXR_OK;
  702. }
  703. HX_RESULT HXUnixCondition::Wait()
  704. {
  705.     HX_RESULT ret;
  706.     ret = _Wait();
  707.     return ret;
  708. }
  709. HX_RESULT HXUnixCondition::TimedWait( UINT32 uTimeoutPeriod )
  710. {
  711.     return _TimedWait(uTimeoutPeriod);
  712. }
  713. HX_RESULT HXUnixCondition::Broadcast()
  714. {
  715.     return _Broadcast();
  716. }
  717. HX_RESULT HXUnixCondition::Signal()
  718. {
  719.     return _Signal();
  720. }
  721. //=======================================================================
  722. //
  723. //                      HXUnixAsyncTimer
  724. //                   -----------------------
  725. //
  726. //=======================================================================   
  727. //Static data initializers
  728. HXMutex*       HXUnixAsyncTimer::m_pmtxMapLock = NULL;
  729. CHXMapLongToObj HXUnixAsyncTimer::m_mapTimers;
  730. //Timeouts are in miliseconds.
  731. HXUnixAsyncTimer::HXUnixAsyncTimer( ULONG32 ulTimeOut, HXThread* pReceivingThread )
  732.     : m_ulTimeOut( ulTimeOut ),
  733.       m_pReceivingThread( pReceivingThread ),
  734.       m_pMessagePump( NULL ),
  735.       m_pMsg(NULL),
  736.       m_pfExecFunc(NULL)
  737. {
  738.     //Make the message to pump.
  739.     m_pMsg = new HXThreadMessage( HXMSG_ASYNC_TIMER, (void*)m_ulTimeOut, NULL, NULL );
  740.     
  741.     //Start the thread. We have to do this weird casting because
  742.     //the HXThread::MakeThread takes HXThread*&....
  743.     HXThread* pTmp = NULL;
  744.     HXUnixThread::MakeThread(pTmp);
  745.     HX_ASSERT( pTmp );
  746.     m_pMessagePump = (HXUnixThread*)pTmp;
  747.     m_pMessagePump->CreateThread( _ActualMessagePump, (void*)this );
  748. }
  749. HXUnixAsyncTimer::HXUnixAsyncTimer( ULONG32 ulTimeOut, TIMERPROC pfExecFunc )
  750.     : m_ulTimeOut( ulTimeOut ),
  751.       m_pReceivingThread(NULL),
  752.       m_pMessagePump(NULL),
  753.       m_pMsg(NULL),
  754.       m_pfExecFunc( pfExecFunc )
  755. {
  756.     //we need non-null pfExecFunc
  757.     HX_ASSERT( m_pfExecFunc != NULL );
  758.     
  759.     //Start the thread.
  760.     HXThread* pTmp = NULL;
  761.     HXUnixThread::MakeThread(pTmp);
  762.     HX_ASSERT( pTmp );
  763.     m_pMessagePump = (HXUnixThread*)pTmp;
  764.     m_pMessagePump->CreateThread( _ActualMessagePump, (void*)this );
  765. }
  766. HXUnixAsyncTimer::~HXUnixAsyncTimer()    
  767. {
  768.    //Tell the message pump to quit.
  769.     HXThreadMessage msgQuit(HXMSG_QUIT, NULL, NULL);
  770.     m_pMessagePump->PostMessage( &msgQuit );
  771.     //Wait for it to stop.
  772.     m_pMessagePump->JoinThread();
  773.     HX_DELETE( m_pMessagePump );
  774. }
  775. ULONG32 HXUnixAsyncTimer::GetID()
  776. {
  777.     ULONG32 ulTmp=0;
  778.     m_pMessagePump->GetThreadId(ulTmp);
  779.     return ulTmp;
  780. }
  781. //XXXgfw just to keep the below more readable.
  782. #define PARG ((HXUnixAsyncTimer*)pArg)
  783. void* HXUnixAsyncTimer::_ActualMessagePump(void* pArg)
  784. {
  785.     while(1)
  786.     {
  787.         if( HXR_OK == PARG->m_pMessagePump->PeekMessage(&PARG->m_msgTmp))
  788.         {
  789.             //Got a message. If it is HXMSG_QUIT get our of here.
  790.             if( PARG->m_msgTmp.m_ulMessage == HXMSG_QUIT )
  791.             {
  792.                 break;
  793.             }
  794.         }
  795.         
  796.         microsleep( PARG->m_ulTimeOut*1000 );
  797.         if( PARG->m_pMsg != NULL )
  798.             PARG->m_pReceivingThread->PostMessage( PARG->m_pMsg);
  799.         else
  800.             PARG->m_pfExecFunc( 0, 0, PARG->GetID(), GetTickCount() );
  801.     }
  802.     return NULL;
  803. }
  804. #undef PARG
  805. UINT32 HXUnixAsyncTimer::SetTimer(ULONG32 ulTimeOut, HXThread* pReceivingThread )
  806. {
  807.     if( m_pmtxMapLock == NULL )
  808.     {
  809.         HXMutex::MakeMutex( m_pmtxMapLock );
  810.         HX_ASSERT( m_pmtxMapLock );
  811.     }
  812.     
  813.     //lock it.
  814.     m_pmtxMapLock->Lock();
  815.     ULONG32 ulTimerID = 0;
  816.     
  817.     HX_ASSERT( ulTimeOut != 0 );
  818.     HX_ASSERT( pReceivingThread != NULL );
  819.     
  820.     HXUnixAsyncTimer* pTimer = new HXUnixAsyncTimer(ulTimeOut, pReceivingThread );
  821.     HX_ASSERT( pTimer != NULL );
  822.     if( pTimer != NULL )
  823.     {
  824.         //Add new timer to map.
  825.         ulTimerID = pTimer->GetID();
  826.         m_mapTimers.SetAt( ulTimerID, (void*)pTimer );    
  827.     }
  828.     
  829.     //unlock the map.
  830.     m_pmtxMapLock->Unlock();
  831.     return ulTimerID;
  832. }
  833. UINT32 HXUnixAsyncTimer::SetTimer(ULONG32 ulTimeOut, TIMERPROC pfExecFunc )
  834. {
  835.     if( m_pmtxMapLock == NULL )
  836.     {
  837.         HXMutex::MakeMutex( m_pmtxMapLock );
  838.         HX_ASSERT( m_pmtxMapLock );
  839.     }
  840.     
  841.     //lock it.
  842.     m_pmtxMapLock->Lock();
  843.     ULONG32 ulTimerID = 0;
  844.     
  845.     HX_ASSERT( ulTimeOut != 0 );
  846.     HX_ASSERT( pfExecFunc != NULL );
  847.     
  848.     HXUnixAsyncTimer* pTimer = new HXUnixAsyncTimer(ulTimeOut, pfExecFunc );
  849.     HX_ASSERT( pTimer != NULL );
  850.     if( pTimer != NULL )
  851.     {
  852.         //Add new timer to map.
  853.         ulTimerID = pTimer->GetID();
  854.         m_mapTimers.SetAt( ulTimerID, (void*)pTimer );    
  855.     }
  856.     
  857.     //unlock the map.
  858.     m_pmtxMapLock->Unlock();
  859.     return ulTimerID;
  860. }
  861. BOOL HXUnixAsyncTimer::KillTimer(UINT32 ulTimerID )
  862. {
  863.     //lock it.
  864.     m_pmtxMapLock->Lock();
  865.     BOOL  bRetVal = FALSE;
  866.     void* pTimer  = NULL;
  867.     HX_ASSERT( ulTimerID != 0 );
  868.     
  869.     if( m_mapTimers.Lookup( ulTimerID, pTimer ) )
  870.     {
  871.         //Found it.
  872.         bRetVal = TRUE;
  873.         HXUnixAsyncTimer* pTmp = (HXUnixAsyncTimer*)pTimer;
  874.         HX_DELETE(pTmp); 
  875.         m_mapTimers.RemoveKey( ulTimerID );
  876.     }
  877.     //unlock the map.
  878.     m_pmtxMapLock->Unlock();
  879.     return bRetVal;
  880. }
  881. #endif //_UNIX_THREADS_SUPPORTED