⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unixthreads.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** BEGIN LICENSE BLOCK ***** 
 * Version: RCSL 1.0/RPSL 1.0 
 *  
 * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
 *      
 * The contents of this file, and the files included with this file, are 
 * subject to the current version of the RealNetworks Public Source License 
 * Version 1.0 (the "RPSL") available at 
 * http://www.helixcommunity.org/content/rpsl unless you have licensed 
 * the file under the RealNetworks Community Source License Version 1.0 
 * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
 * in which case the RCSL will apply. You may also obtain the license terms 
 * directly from RealNetworks.  You may not use this file except in 
 * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
 * applicable to this file, the RCSL.  Please see the applicable RPSL or 
 * RCSL for the rights, obligations and limitations governing use of the 
 * contents of the file.  
 *  
 * This file is part of the Helix DNA Technology. RealNetworks is the 
 * developer of the Original Code and owns the copyrights in the portions 
 * it created. 
 *  
 * This file, and the files included with this file, is distributed and made 
 * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 * 
 * Technology Compatibility Kit Test Suite(s) Location: 
 *    http://www.helixcommunity.org/content/tck 
 * 
 * Contributor(s): 
 *  
 * ***** END LICENSE BLOCK ***** */ 

//This is used to turn off threads in libc5 builds.
#ifdef _UNIX_THREADS_SUPPORTED

#include "hxtypes.h" //for UINT32
#include "hxresult.h" //for HX_RESULT

#include <errno.h>
#include "UnixThreads.h"

#include <signal.h>   //for SIGKILL
#include "hxassert.h" //for HX_ASSERT
#include "microsleep.h"
#include "hxmsgs.h" //for HXMSG_ASYNC_TIMER message.
#include "hxtick.h"  //for GetTickCount()



//=================================================================
// In this section here include the OS specific headerfiles for
// each implementation.
//=================================================================
#if defined( _LINUX ) || defined(_HPUX) || defined(_MAC_UNIX)
#include <pthread.h>
#include <semaphore.h>
#include "pthreadthreads.h"
#endif

#if defined( _SOLARIS )
#include <synch.h>
#include <thread.h>
#include "solaristhreads.h"
#endif

#if defined( _IRIX )
#endif

#if defined( _AIX )
#endif

//=======================================================================
//
//                      HXUnixThread
//                   ------------------
//
//=======================================================================
HXUnixThread::HXUnixThread() 
    : m_threadID(0),
      m_messageQue(),
      m_pCond(NULL),
      m_pCondLock(NULL)
{
    //Create the condition with its associated mutex.
    //Do NOT delete the mutex that the cond makes for us....
    HXUnixCondition::MakeCondition(m_pCond, m_pCondLock );
    HX_ASSERT( m_pCondLock && m_pCond);
}

HXUnixThread::~HXUnixThread()
{
    if( m_threadID != 0 )
    {
        //XXXgfw Had to get rid of this. Some threads are destroyed on their own thread.
        //HX_ASSERT( "Thread has not been joined! Memory/mutex leaks????\n" == NULL );
        //We can try to cancel here but it won't work!
        //The thread may not even honor the cancel request. If it does and has not
        //set up cancelation/clean-up routine you better hope that it doesn't have
        //any mutexes locked or resources open!!! Just don't do it.
    }

    //Clean up message que.
    while( !m_messageQue.IsEmpty() )
    {
        HXThreadMessage* pTmp = (HXThreadMessage *)(m_messageQue.RemoveHead());
        HX_DELETE( pTmp );
    }

    HX_DELETE( m_pCond );
    m_pCondLock = NULL;
}

HX_RESULT HXUnixThread::MakeThread(HXThread*& pThread )
{
#if defined( _LINUX ) || defined (_HPUX) || defined(_MAC_UNIX)
    pThread = new HXPthreadThread();
#elif defined( _SOLARIS )
    pThread = new HXSolarisThread();
#else
    HX_ASSERT( "No unix thread for this platform" == NULL );
#endif    
    if(pThread == NULL)
    {
        HX_ASSERT( 0 );
	return HXR_OUTOFMEMORY;
    }
    
    return HXR_OK;
}

//ulCreationFlags is ignored. We can't suspend pthreads and that is the only
//flag possible right now.
HX_RESULT HXUnixThread::CreateThread( void*(pfExecFunc(void*)), void* pArg, ULONG32 ulCreationFlags)
{
    HX_RESULT retVal = HXR_OK;
    
    HX_ASSERT( m_threadID==0 );
    if( m_threadID != 0)
    {
        retVal = HXR_UNEXPECTED;
    }
    else
    {
        if( _thread_create( m_threadID, pfExecFunc, pArg ) != HXR_OK )
        {
            retVal = HXR_FAIL;
            m_threadID = 0;
        }
    }

    return retVal;
}


HX_RESULT HXUnixThread::Exit(UINT32 unExitCode)
{
    //Make sure that only the thread that was created it calling the exit
    //routine. If the parent thread wants to kill it maybe we should have
    //a Kill method or something.
    if( 0 == m_threadID )
    {
        //Thread has already gone. Just return.
        return HXR_UNEXPECTED;
    }
    
    if( m_threadID != GetCurrentThreadID() )
    {
        //Ok, because of the way winthrd.cpp does it, this call also
        //acts as a 'pthread_join' when the calling thread isn't the
        //m_threadID.
        
        //Also, it looks like this method isn't set up to look at the
        //return value of the thread. We could return HXR_FAIL is it
        //is anything except 0 but for now just throw it away.
        JoinThread();
    }
    else
    {
        _thread_exit( unExitCode );
    }
    
    return HXR_OK;
}


HX_RESULT HXUnixThread::SetPriority( UINT32 ulPriority)
{
    //XXXGFW not supported yet.
//     struct sched_param stThreadParams;
//     int    nPolicy = 0;
//     int    nRet    = -1;

//     HX_ASSERT( m_threadID );

//     if( m_threadID != 0)
//     {
//         nPolicy = SCHED_OTHER;
//         stThreadParams.sched_priority = (int)ulPriority; 
        
//         nRet = pthread_setschedparam( m_threadID, nPolicy, &stThreadParams );
//     }
    
//     return nRet==0 ? HXR_OK : HXR_FAIL;
    return HXR_OK;
}

//XXXgfw not tested yet!!!!!!! ...but should work. :)
HX_RESULT HXUnixThread::GetPriority( UINT32& ulPriority)
{
    //XXXGFW not supported yet.....
//     struct sched_param stThreadParams;
//     int    nPolicy = 0;
//     int    nRet    = -1;
    
//     HX_ASSERT( m_threadID );
    
//     if( m_threadID != 0)
//     {
//         nRet = pthread_getschedparam( m_threadID, &nPolicy, &stThreadParams );
//         ulPriority = stThreadParams.sched_priority;
//     }
    
//     return nRet==0 ? HXR_OK : HXR_FAIL;
    return HXR_OK;
}

HX_RESULT HXUnixThread::YieldTimeSlice()
{
    microsleep(1);
    return HXR_OK;
}


HX_RESULT HXUnixThread::GetThreadId(UINT32& ulThreadId)
{
    ulThreadId = m_threadID;
    return HXR_OK;
}

ULONG32 HXUnixThread::GetCurrentThreadID()
{
    return _thread_self();
}

//Cancels the thread that was created.
HX_RESULT HXUnixThread::CancelThread()
{
    HX_ASSERT( "This isn't portable. Don't use it" == NULL );
    if( 0 == m_threadID )
    {
        return HXR_UNEXPECTED;
    }
    _thread_cancel(m_threadID);
    return HXR_OK;
}

//Must wait for our child thread to exit and return the ret code.
ULONG32 HXUnixThread::JoinThread()
{
    ULONG32 ulRetVal = 0;

    if( 0 == m_threadID || GetCurrentThreadID() == m_threadID )
    {
        return HXR_UNEXPECTED;
    }

    ulRetVal = _thread_join( m_threadID );

    //Thread has exited and we are done.
    m_threadID = 0;
    
    return ulRetVal;
}

HX_RESULT HXUnixThread::Suspend()
{
    HX_ASSERT( "HXUnixThread::Suspend is not implemented yet." == NULL );
    return HXR_FAIL;
}

HX_RESULT HXUnixThread::Resume()
{
    HX_ASSERT( "HXUnixThread::Resume  is not implemented yet." == NULL );
    return HXR_FAIL;
}

HX_RESULT HXUnixThread::PostMessage(HXThreadMessage* pMsg, void* pWindowHandle)
{
    HX_RESULT retVal = HXR_OK;

    //Assert that we don't use pWindowHandle. 
    HX_ASSERT( pWindowHandle == NULL );
    
    //To mimic the windows PostMessage we must COPY the pMsg and put
    //it on our que. pMsg is going to go out of scope most likely
    if( NULL != pMsg )
    {
        HXThreadMessage *pMsgTmp = new HXThreadMessage(pMsg);
        if( pMsgTmp == NULL )
        {
            retVal = HXR_OUTOFMEMORY;
        }
        else
        {
            //Lock the mutex protecting the message que.
            m_pCondLock->Lock();
            m_messageQue.AddTail((void*)pMsgTmp);
            
            //If we were empty the the GetMessage thread could have been waiting 
            //on us to post. Signal it.
            m_pCond->Signal();
            m_pCondLock->Unlock();
        }
    }
    
    return retVal;
}

HX_RESULT HXUnixThread::GetMessage( HXThreadMessage* pMsg, 
                                     UINT32 ulMsgFilterMin, 
                                     UINT32 ulMsgFilterMax)
{
    HX_RESULT retVal = HXR_OK;

    //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
    HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
    HX_ASSERT( pMsg );
    
    //We must pop the next message, COPY it into pMsg and delete our copy.
    if( pMsg != NULL )
    {
        //Get access
        m_pCondLock->Lock();

        //If the que is empty we need to block and wait.
        while( m_messageQue.IsEmpty() )
        {
            m_pCond->Wait();
        }

        if( !m_messageQue.IsEmpty())
        {
            HXThreadMessage* pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
            pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
            pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
            pMsg->m_pParam2               = pMsgTmp->m_pParam2;
            pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
            
            //free it.
            HX_DELETE( pMsgTmp );
        }
        else
        {
            HX_ASSERT( "que panic" == NULL );
        }
        m_pCondLock->Unlock();
    }
    
    return retVal;
}
HX_RESULT HXUnixThread::PeekMessageMatching( HXThreadMessage* pMsg,
                                              HXThreadMessage* pMatch,
                                              BOOL bRemoveMessage )
{
    HX_RESULT retVal = HXR_OK;
        
    HX_ASSERT( pMsg );
    HX_ASSERT( pMatch );
     
    if( pMsg != NULL && pMatch!=NULL )
    {
        //Protect the que.
        m_pCondLock->Lock();

        if( !m_messageQue.IsEmpty() )
        {
            HXThreadMessage* pMsgTmp = NULL;

            //Loop throught the messages and find a matching
            //one.
            BOOL bSkipMessage  = (pMatch->m_ulMessage==0);
            BOOL bSkipParam1   = (pMatch->m_pParam1==NULL);
            BOOL bSkipParam2   = (pMatch->m_pParam2==NULL);
            BOOL bSkipPlatform = (pMatch->m_pPlatformSpecificData==NULL);
            CHXSimpleList::Iterator i;
            
            for( i=m_messageQue.Begin(); i!=m_messageQue.End(); ++i)
            {
                pMsgTmp = (HXThreadMessage*)(*i);

                //Does it match?
                if( bSkipMessage || pMatch->m_ulMessage==pMsgTmp->m_ulMessage )
                    if( bSkipParam1 || pMatch->m_pParam1==pMsgTmp->m_pParam1 )
                        if( bSkipParam2 || pMatch->m_pParam2==pMsgTmp->m_pParam2 )
                            if( bSkipPlatform || pMatch->m_pPlatformSpecificData==pMsgTmp->m_pPlatformSpecificData )
                                break;
            }
            //Did we find a match?
            if( i != m_messageQue.End())
            {
                //We found one!
                pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
                pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
                pMsg->m_pParam2               = pMsgTmp->m_pParam2;
                pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
                
                //Only free it if we removed it from the queue.
                if( bRemoveMessage )
                {
                    //XXXgfw That has to be a better way than this. We
                    //have the iterator up above. How do you delete with
                    //one.
                    LISTPOSITION listpos = m_messageQue.Find(pMsgTmp);
                    HX_ASSERT( listpos );
                    if(listpos)
                    {
                        m_messageQue.RemoveAt(listpos);
                    }
                    HX_DELETE( pMsgTmp );
                }
            }
            else
            {
                retVal=HXR_FAIL;
            }
        }
        else
        {
            //There was no message to get
            retVal=HXR_FAIL;
        }
        m_pCondLock->Unlock();
    }
    return retVal;
}

HX_RESULT HXUnixThread::PeekMessage( HXThreadMessage* pMsg,
                                      UINT32 ulMsgFilterMin,
                                      UINT32 ulMsgFilterMax,
                                      BOOL   bRemoveMessage
                                      )
{
    HX_RESULT retVal = HXR_OK;

    //assert that ulMsgFilterMax/Min is zero as we don't support it yet.
    HX_ASSERT( ulMsgFilterMax == 0 && ulMsgFilterMin == 0 );
    HX_ASSERT( pMsg );
    
    //We must pop the next message, COPY it into pMsg and delete our copy.
    if( pMsg != NULL )
    {
        //Protect the que.
        m_pCondLock->Lock();

        if( !m_messageQue.IsEmpty() )
        {
            HXThreadMessage* pMsgTmp = NULL;

            //Do we romove the message or peek at it?
            if( bRemoveMessage )
            {
                pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
            }
            else
            {
                pMsgTmp = (HXThreadMessage*)m_messageQue.GetHead();
            }
                
            if( pMsgTmp != NULL )
            {
                pMsg->m_ulMessage             = pMsgTmp->m_ulMessage; 
                pMsg->m_pParam1               = pMsgTmp->m_pParam1; 
                pMsg->m_pParam2               = pMsgTmp->m_pParam2;
                pMsg->m_pPlatformSpecificData = pMsgTmp->m_pPlatformSpecificData;
                
                //Only free it if we removed it from the queue.
                if( bRemoveMessage )
                    HX_DELETE( pMsgTmp );
            }
            else
            {
                HX_ASSERT( "que panic" == NULL );
            }
        }
        else
        {
            //There was no message to get
            retVal=HXR_FAIL;
        }
        m_pCondLock->Unlock();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -