📄 symbianthreads.cpp
字号:
/* ***** 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.
#include "hxtypes.h" //for UINT32
#include "hxresult.h" //for HX_RESULT
#include "hxslist.h"
#include "hxassert.h" //for HX_ASSERT
#include "hxmsgs.h" //for HXMSG_ASYNC_TIMER message.
#include "hxmap.h" //for CHXMapLongToObj
#include "hxtick.h" //for GetTickCount()
#include "globals/hxglobals.h"
#include "SymbianThreads.h"
#include "symbian_async_timer_imp.h"
#include "symbian_rtimer_at_imp.h"
#include "symbian_thread_at_imp.h"
#include "hxglobalmgr_inst.h"
//XXXgfw I first coded this to use RTimers for RunL callbacks to get
//the work of the async timer done. But, if the thread that creates
//the timer blocks at all we stop getting callbacks. I think now that
//this may cause problems with the way Helix uses the timers. So, I am
//going to code a version that uses real threads to get the work
//done. You can use the below define to build either one you want.
//#define USE_SYMBIAN_THREADS_FOR_ASYNCTIMERS
//=======================================================================
//
// HXSymbianThread
// ------------------
//
//=======================================================================
HXSymbianThread::HXSymbianThread()
: m_pThread(NULL),
m_pSemMessageCount(NULL),
m_pmtxQue(NULL)
{
TInt err;
m_pSemMessageCount = new RSemaphore();
HX_ASSERT( m_pSemMessageCount );
if( m_pSemMessageCount )
{
err = m_pSemMessageCount->CreateLocal(0);
if( KErrNone != err )
{
HX_DELETE( m_pSemMessageCount );
}
}
HXMutex::MakeMutex( m_pmtxQue );
HX_ASSERT( m_pmtxQue );
}
HXSymbianThread::~HXSymbianThread()
{
//Clean up message que.
while( !m_messageQue.IsEmpty() )
{
HXThreadMessage* pTmp = (HXThreadMessage *)(m_messageQue.RemoveHead());
HX_DELETE( pTmp );
}
if( m_pSemMessageCount)
{
m_pSemMessageCount->Close();
HX_DELETE( m_pSemMessageCount );
}
HX_DELETE( m_pmtxQue );
if( m_pThread )
{
m_pThread->Kill(0);
m_pThread->Close();
HX_DELETE(m_pThread);
}
}
HX_RESULT HXSymbianThread::CreateThread( void*(pfExecFunc(void*)),
void* pArg,
ULONG32 ulCreationFlags)
{
HX_RESULT retVal = HXR_OK;
TInt err = KErrNone;
HX_ASSERT( NULL==m_pThread );
if( NULL != m_pThread )
{
retVal = HXR_UNEXPECTED;
}
else
{
m_pThread = new RThread();
if( NULL == m_pThread )
{
retVal = HXR_FAIL;
}
else
{
//Each thread has to have a unique name. Oh bother.
//Lets just use the heap pointer.
char szBuff[20]; /* Flawfinder: ignore */
sprintf( szBuff, "%p", m_pThread ); /* Flawfinder: ignore */
TPtr ThreadName((unsigned short*)szBuff, strlen(szBuff), 20);
st_execStruct stExecStruct;
stExecStruct.pfExecProc = (TThreadFunction)pfExecFunc;
stExecStruct.pExecArg = pArg;
stExecStruct.pGlobalManager = HXGlobalManInstance::GetInstance();
err = m_pThread->Create( ThreadName,
_ThreadWrapper,
KDefaultStackSize,
&User::Heap(), //Use parent HEAP
&stExecStruct
);
if( KErrNone != err )
{
//Could not start thread.
retVal = HXR_FAIL;
m_pThread->Close();
HX_DELETE( m_pThread );
}
else
{
//Tell the system we want to be notifed when this
//thread terminates for any reason.
m_pThread->Logon(m_reqStat);
//Symbian threads start up in a 'suspended' mode. HXThreads
//assume that the threads are running from the get go. So, we
//do a resume here.
m_pThread->Resume();
}
}
}
return retVal;
}
HX_RESULT HXSymbianThread::Exit(UINT32 unExitCode)
{
if( NULL==m_pThread )
{
//Thread has already gone or was never here.
return HXR_UNEXPECTED;
}
if( m_pThread->Id() != (TThreadId)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.
User::WaitForRequest(m_reqStat);
}
else
{
//Kill our selves....
m_pThread->Kill(unExitCode);
}
return HXR_OK;
}
HX_RESULT HXSymbianThread::SetPriority( UINT32 ulPriority)
{
HX_RESULT res = HXR_FAIL;
if( m_pThread)
{
m_pThread->SetPriority((TThreadPriority)ulPriority);
res = HXR_OK;
}
return res;
}
HX_RESULT HXSymbianThread::GetPriority( UINT32& ulPriority)
{
HX_RESULT res = HXR_FAIL;
if( m_pThread)
{
ulPriority = m_pThread->Priority();
res = HXR_OK;
}
return res;
}
HX_RESULT HXSymbianThread::YieldTimeSlice()
{
//Just sleep for a tiny amount so someone else can
//run.
User::After(10);
return HXR_OK;
}
HX_RESULT HXSymbianThread::GetThreadId(UINT32& ulThreadId)
{
HX_RESULT res = HXR_FAIL;
if( m_pThread )
{
ulThreadId = m_pThread->Id();
res = HXR_OK;
}
return res;
}
ULONG32 HXSymbianThread::GetCurrentThreadID()
{
return RThread().Id();
}
HX_RESULT HXSymbianThread::Suspend()
{
HX_RESULT res = HXR_FAIL;
if( m_pThread )
{
m_pThread->Suspend();
res = HXR_OK;
}
return res;
}
HX_RESULT HXSymbianThread::Resume()
{
HX_RESULT res = HXR_FAIL;
if( m_pThread )
{
m_pThread->Resume();
res = HXR_OK;
}
return res;
}
HX_RESULT HXSymbianThread::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_pmtxQue->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_pSemMessageCount->Signal();
m_pmtxQue->Unlock();
}
}
return retVal;
}
HX_RESULT HXSymbianThread::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 )
{
//Wait until there is a message.
m_pSemMessageCount->Wait();
//Protect the que.
m_pmtxQue->Lock();
//Sanity check.
HX_ASSERT( !m_messageQue.IsEmpty() );
HXThreadMessage* pMsgTmp = (HXThreadMessage*)m_messageQue.RemoveHead();
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;
//free it.
HX_DELETE( pMsgTmp );
}
else
{
HX_ASSERT( "que panic" == NULL );
}
m_pmtxQue->Unlock();
}
return retVal;
}
HX_RESULT HXSymbianThread::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_pmtxQue->Lock();
//Sanity check.
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_pmtxQue->Unlock();
}
return retVal;
}
HX_RESULT HXSymbianThread::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_pmtxQue->Lock();
//Sanity check.
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_pmtxQue->Unlock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -