www.pudn.com > WinGOS.rar > Thread.cpp


#include "GOS.h" 
#include "thread.h" 
 
#define MSG_WAIT 0x01L 
#define PTR_MASK ~0x3L 
#define REMOVEMSG(prev,pTmp,next) \ 
	if(pPrev)pPrev->pNext=next;else m_pMQEntry=next;\ 
	pTmp->pNext=m_pMQFree;m_pMQFree=pTmp 
 
CThread::CThread() 
{ 
	m_pMQEntry=NULL; 
	m_pMQFree=NULL; 
	m_pMQBuffer=NULL; 
	m_pWaitObject=NULL; 
	m_pStack=NULL; 
	m_nPriority=0; 
} 
 
BOOL CThread::CreateThread(PVOID pParam,int nPriority,UINT nStackSize,int nFlags) 
{ 
	PVOID pBlock; 
 
	m_nWakeTime=GetTickCount(); 
	if(nFlags & CreateSuspend) 
		m_nWakeTime+=MAXLONG; 
	pBlock=g_pKernel->MemoryAlloc(NULL, 
		nStackSize?nStackSize:ThreadDefaultStackSize); 
	m_pStack=PVOID(DWORD(pBlock)+_msize(pBlock)-sizeof(DWORD)); 
	m_heap.Create(pBlock); 
	 
	g_pHAL->CreateThread(this,pParam); 
	g_pKernel->ThreadTableAdd(this,nPriority); 
	 
	return TRUE; 
} 
 
BOOL CThread::ExitThread(DWORD dwExitCode) 
{ 
	MsgProc(msgExitThread,dwExitCode,0); 
	SetLastError(dwExitCode); 
	RemoveAllMessage(); 
	g_pKernel->MemoryAlloc(m_heap.Delete(),0); 
	g_pKernel->ThreadTableRemove(this); 
	g_pHAL->ExitThread(this); 
	return TRUE; 
} 
 
VOID CThread::SleepEx(LONG nMilliseconds,BOOL bSleepTo) 
{ 
	if(bSleepTo) 
		m_nWakeTime=nMilliseconds; 
	else 
		m_nWakeTime=GetTickCount()+nMilliseconds; 
	SwitchToThread(); 
} 
 
 
int CThread::OnRun(PVOID pData) 
{ 
	MSG msg; 
 
	while(GetMessage(&msg,INFINITE) &&  
		!(msg.message==msgQuit && msg.pObj==this)) 
	{ 
		DispatchMessage(&msg); 
	} 
	ExitThread(msg.wParam); 
 
	return msg.wParam; 
} 
 
LRESULT CThread::MsgProc(UINT message, WPARAM wParam, LPARAM lParam) 
{ 
	switch(message) 
	{ 
	case msgGetMQThread: 
		wParam=LRESULT(this); 
		break; 
	case msgRunThread: 
		wParam=OnRun(PVOID(wParam)); 
		break; 
	default: 
		wParam=CMsgObject::MsgProc(message,wParam,lParam); 
	}	 
	return wParam; 
} 
 
BOOL CThread::GetMessage(PMSG pMsg,LONG nTimeOut) 
{ 
	PMSGLE pCur,pPrev=NULL; 
	LONG nWake,nCurTime=GetTickCount(); 
	 
	nTimeOut+=nCurTime; 
	m_tlock.Lock(INFINITE); 
 
	pCur=m_pMQEntry; 
	for(;;) 
	{ 
		if(!pCur) 
		{ 
			if(LONG(nTimeOut-nCurTime)<=0) 
				break; 
			m_nWakeTime=nTimeOut; 
			*PDWORD(&m_pMQBuffer) |= MSG_WAIT; 
			m_tlock.Unlock(); 
			SwitchToThread(); 
			*PDWORD(&m_pMQBuffer) &= ~MSG_WAIT; 
			m_tlock.Lock(INFINITE); 
			pCur=m_pMQEntry; 
			nCurTime=GetTickCount(); 
			continue; 
		} 
		else if(IsEventMessage(pCur->msg.message)) 
		{ 
			if(pCur->msg.pObj) 
			{ 
				*pMsg=pCur->msg; 
				pMsg->message=msgEvent; 
				pCur->msg.pObj=NULL; 
				break; 
			} 
		} 
		else if(IsTimerMessage(pCur->msg.message)) 
		{ 
			nWake=pCur->msg.wParam; 
			if(LONG(nCurTime-nWake)>=0) 
			{ 
				pMsg->pObj=pCur->msg.pObj; 
				pMsg->message=msgTimer; 
				pMsg->wParam=LOWORD(pCur->msg.lParam); 
				pMsg->lParam=nWake; 
 
				pCur->msg.wParam=nWake=HIWORD(pCur->msg.lParam) +  
					((pMsg->wParam & 0x8000)?nWake:nCurTime); 
				break; 
			} 
			if(LONG(nTimeOut-nWake)>0) 
				nTimeOut=nWake; 
		} 
		else 
		{ 
			*pMsg=pCur->msg; 
			REMOVEMSG(pPrev,pCur,pCur->pNext); 
			break; 
		} 
		pPrev=pCur; 
		pCur=pCur->pNext; 
	} 
	m_tlock.Unlock(); 
	return BOOL(pCur); 
} 
 
 
LRESULT CThread::DispatchMessage(const MSG *pMsg) 
{ 
	LRESULT lResult; 
	CMsgObject* pObj=pMsg->pObj; 
 
	if(pObj) 
	{ 
		lResult=pObj->MsgProc(pMsg->message,pMsg->wParam,pMsg->lParam); 
	} 
	else if(pMsg->message==msgSendMessage) 
	{ 
		CMutex* lock=(CMutex*)pMsg->wParam; 
		PMSG m=PMSG(pMsg->lParam); 
		m->wParam=m->pObj->MsgProc(m->message,m->wParam,m->lParam); 
		lock->Unlock(); 
		lResult=TRUE; 
	} 
	else lResult=0; 
 
	return lResult; 
} 
 
HANDLE CThread::InsertMessage(CMsgObject* pObj,UINT nMessage,WPARAM wParam,LPARAM lParam) 
{ 
	PMSGLE pIns=NULL,pTmp,pPrev=NULL,pNext; 
 
	m_tlock.Lock(INFINITE); 
	 
	for(pTmp=m_pMQEntry;pTmp;pPrev=pTmp,pTmp=pNext) 
	{	 
		pNext=pTmp->pNext; 
		if(pTmp->msg.message>=nMessage) 
		{ 
			if(pTmp->msg.message>nMessage) 
				break; 
			if(pTmp->msg.pObj==pObj && IsUniqueMessage(nMessage)) 
			{ 
				pIns=pTmp; 
				break; 
			} 
		} 
	} 
	if(!pIns) 
	{ 
		if(!m_pMQFree) 
			GrowMQBuffer(); 
		pIns=m_pMQFree; 
		m_pMQFree=pIns->pNext; 
 
		if(pPrev) 
		{ 
			pIns->pNext=pTmp; 
			pPrev->pNext=pIns; 
		} 
		else 
		{ 
			pIns->pNext=m_pMQEntry; 
			m_pMQEntry=pIns; 
		} 
		pIns->msg.pObj=pObj; 
		pIns->msg.message=nMessage; 
	} 
	pIns->msg.wParam=wParam; 
	pIns->msg.lParam=lParam; 
	 
	m_tlock.Unlock(); 
	if(DWORD(m_pMQBuffer) & MSG_WAIT) 
		SleepEx(0,FALSE); 
 
	return HANDLE(pIns); 
} 
 
HANDLE CThread::InsertMessage(CMsgObject* pObj,HANDLE hRefMsg,WPARAM wParam,LPARAM lParam) 
{ 
	PMSGLE pIns,pRefMsg=PMSGLE(hRefMsg); 
 
	m_tlock.Lock(INFINITE); 
 
	if(!m_pMQFree) 
		GrowMQBuffer(); 
	pIns=m_pMQFree; 
	m_pMQFree=pIns->pNext; 
	pIns->pNext=pRefMsg->pNext; 
	pRefMsg->pNext=pIns; 
	 
	pIns->msg.message=pRefMsg->msg.message; 
	pIns->msg.pObj=pObj; 
	pIns->msg.wParam=wParam; 
	pIns->msg.lParam=lParam; 
	 
	m_tlock.Unlock(); 
	if(DWORD(m_pMQBuffer) & MSG_WAIT) 
		SleepEx(0,FALSE); 
 
	return HANDLE(pIns); 
} 
 
void CThread::PulseMessage(HANDLE hMsg) 
{ 
	if(DWORD(m_pMQBuffer) & MSG_WAIT) 
		SleepEx(0,FALSE); 
} 
 
BOOL CThread::RemoveMessage(CMsgObject* pObj) 
{ 
	PMSGLE pTmp,pPrev=NULL,pNext; 
	DWORD nCount=0; 
 
	m_tlock.Lock(INFINITE); 
	for(pTmp=m_pMQEntry;pTmp;pTmp=pNext) 
	{	 
		pNext=pTmp->pNext; 
		if(pTmp->msg.pObj==pObj) 
		{ 
			nCount++; 
			REMOVEMSG(pPrev,pTmp,pNext); 
		} 
		pPrev=pTmp; 
	} 
	m_tlock.Unlock(); 
	return nCount; 
} 
 
BOOL CThread::RemoveMessage(CMsgObject* pObj,UINT nMessage) 
{ 
	PMSGLE pTmp,pPrev=NULL,pNext; 
	DWORD nCount=0; 
 
	m_tlock.Lock(INFINITE); 
	for(pTmp=m_pMQEntry;pTmp;pTmp=pNext) 
	{	 
		pNext=pTmp->pNext; 
		if(pTmp->msg.message>=nMessage) 
		{ 
			if(pTmp->msg.message>nMessage) 
				break; 
			if(pTmp->msg.pObj==pObj) 
			{ 
				nCount++; 
				REMOVEMSG(pPrev,pTmp,pNext); 
				if(IsUniqueMessage(nMessage)) 
					break; 
			} 
		} 
		pPrev=pTmp; 
	} 
	m_tlock.Unlock(); 
	return nCount; 
} 
 
BOOL CThread::RemoveMessage(HANDLE hMsgFrom,HANDLE hMsgTo) 
{ 
	PMSGLE pFrom=PMSGLE(hMsgFrom),pTo=PMSGLE(hMsgTo); 
	PMSGLE pTmp,pPrev=NULL; 
 
	m_tlock.Lock(INFINITE); 
	for(pTmp=m_pMQEntry;pTmp;pPrev=pTmp,pTmp=pTmp->pNext) 
	{	 
		if(pTmp==pFrom) 
		{ 
			if(pPrev) 
				pPrev->pNext=pTo->pNext; 
			else 
				m_pMQEntry=pTo->pNext; 
			pTo->pNext=m_pMQFree; 
			m_pMQFree=pFrom; 
			break; 
		} 
	} 
	m_tlock.Unlock(); 
	return BOOL(pTmp); 
} 
 
BOOL CThread::RemoveTimerMessage(CMsgObject* pObj,UINT nIDEvent) 
{ 
	PMSGLE pTmp,pPrev=NULL,pNext; 
 
	m_tlock.Lock(INFINITE); 
	for(pTmp=m_pMQEntry;pTmp;pPrev=pTmp,pTmp=pNext) 
	{	 
		pNext=pTmp->pNext; 
		if(IsTimerMessage(pTmp->msg.message)) 
		{ 
			if(pTmp->msg.pObj==pObj && LOWORD(pTmp->msg.lParam)==nIDEvent) 
			{ 
				REMOVEMSG(pPrev,pTmp,pNext); 
				break; 
			} 
		} 
	} 
	m_tlock.Unlock(); 
 
	return BOOL(pTmp); 
} 
 
BOOL CThread::GrowMQBuffer() 
{ 
	PMSGLE pTmp,pBuf,pBufEnd; 
	DWORD nSize=MsgQueueGrowSize*sizeof(MSGLE); 
	 
	pBuf=(PMSGLE)g_pKernel->MemoryAlloc(NULL,nSize+sizeof(PMSGLE)); 
	m_pMQFree=pBuf; 
	pBufEnd=PMSGLE(DWORD(pBuf)+nSize); 
 
	nSize=DWORD(m_pMQBuffer); 
	pBufEnd->pNext=PMSGLE(nSize & PTR_MASK); 
	nSize &= MSG_WAIT; 
	nSize |= DWORD(pBuf); 
	m_pMQBuffer=PMSGLE(nSize); 
 
	for(pTmp=pBuf+1;pTmppNext=pTmp; 
	pBuf->pNext=NULL; 
 
	return TRUE; 
} 
 
void CThread::RemoveAllMessage() 
{ 
	DWORD nSize=MsgQueueGrowSize*sizeof(MSGLE); 
	PMSGLE pBufEnd,pBuf; 
 
	m_tlock.Lock(INFINITE); 
	pBuf=PMSGLE(DWORD(m_pMQBuffer) & PTR_MASK); 
	m_pMQBuffer=NULL; 
	m_pMQEntry=NULL; 
	m_pMQFree=NULL; 
	m_tlock.Unlock(); 
 
	while(pBuf) 
	{ 
		pBufEnd=PMSGLE(DWORD(pBuf)+nSize); 
		g_pKernel->MemoryAlloc(pBuf,0); 
		pBuf=pBufEnd->pNext; 
	} 
}