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

Symbian

开发平台:

C/C++

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