#include "StdAfx.h"
#include "threadskeleton.h"
#include "04WebServer.h"

CThreadSkeleton::CThreadSkeleton(void)
{
	m_thread = NULL;
	m_hThread = NULL;

	//	中断用イベント
	m_breakEvent.Create(TRUE,FALSE);

	//	クラス名設定
	DEBUG_SET_THREAD_CLASS_NAME("CThreadSkeleton");
}

CThreadSkeleton::~CThreadSkeleton(void)
{
	//	スレッド停止
	EndThread();

	//	スレッドオブジェクト削除
	SAFE_DELETE(m_thread);	//	スレッドハンドルも閉じられる模様
}



////////////////////////////////////////////////////////////////////////////////////////////
//	開始・終了・中断
////////////////////////////////////////////////////////////////////////////////////////////
/*!
	スレッドの開始
*/
int CThreadSkeleton::StartThread(int stackSize)
{
	//	中断イベント解除
	::ResetEvent(m_breakEvent);

	//	スレッドを作成する
	m_thread = AfxBeginThread(WorkThread, this, THREAD_PRIORITY_NORMAL, stackSize*1024, CREATE_SUSPENDED);
	if(m_thread == NULL)
	{
		TRACE("GetLastError :%d\n",GetLastError());
		return(-1);
	}

	//	自動削除解除
	m_thread->m_bAutoDelete = FALSE;

	//	ハンドル取得
	m_hThread = m_thread->m_hThread;

	//	スレッド実行開始
	m_thread->ResumeThread();

	return(0);
}


/*!
	スレッドの終了
*/
void CThreadSkeleton::EndThread()
{
	Break();

	//	スレッドが終了するまで待つ
	if(IsRunning())
		::WaitForSingleObject(m_hThread, INFINITE);
}


/*!
	中断
*/
void CThreadSkeleton::Break()
{
	::SetEvent(m_breakEvent);
}

/*!
	強制終了（特別な理由が無い限り、使用禁止）
*/
void CThreadSkeleton::ForceKillThread()
{
	::TerminateThread(m_hThread, 0);
	::SetEvent(m_breakEvent);
}

/*!
	実行中か取得する
*/
int CThreadSkeleton::IsRunning()
{
	if(m_hThread == NULL)
		return(0);

	return(::WaitForSingleObject(m_hThread, 0) != WAIT_OBJECT_0);
};

/*!
	中断を指示したか取得する
*/
int CThreadSkeleton::GetBreak()
{
	return(WaitForSingleObject(m_breakEvent,0) == WAIT_OBJECT_0);
};



////////////////////////////////////////////////////////////////////////////////////////////
//	ツール関数
////////////////////////////////////////////////////////////////////////////////////////////
/*!
	いくつかのオブジェクトを待つ

	\return	-1:エラー、0:タイムアウト、1以降:反応したハンドル	
*/
int CThreadSkeleton::WaitForSomeObjects(int timeoutMs, HANDLE obj1, HANDLE obj2, HANDLE obj3, HANDLE obj4)
{
	HANDLE	wait[4];
	DWORD 	count;

	wait[0] = obj1;
	wait[1] = obj2;
	wait[2] = obj3;
	wait[3] = obj4;

	//	ハンドル数カウント
	for(count=0;count<4;count++)
	{
		if(wait[count] == NULL)
			break;
	}

	DWORD ret = ::WaitForMultipleObjects(count,wait,FALSE,timeoutMs);
	if(ret == WAIT_TIMEOUT)
		return(0);

	if(ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + count)
		return(ret - WAIT_OBJECT_0 + 1);

	return(-1);
}

////////////////////////////////////////////////////////////////////////////////////////////
//	スレッド関数
////////////////////////////////////////////////////////////////////////////////////////////
/*!
	継承クラスのThreadMainを呼ぶ
*/
void CThreadSkeleton::_ThreadMain()
{
	DEBUG_SET_THREAD_FUNCTION_NAME("CThreadSkeleton::_ThreadMain");

#ifndef _DEBUG
	try
	{
#endif

		ThreadMain();

#ifndef _DEBUG
	}
	catch(CMemoryException *err)
	{
		GET_APP()->WriteDebugLog("メモリ不足により、処理スレッドが停止しました。");
		err->Delete();

		//	クラス情報
		TCHAR   szCause[255];
		sprintf_s(szCause, 254, "\tClass = %s, Function = %s", m_className, m_functionName);
		GET_APP()->WriteDebugLog(szCause);
	}
	catch(CException *err)
	{
		GET_APP()->WriteDebugLog("サーバ内部の未処理MFC例外により、処理スレッドが停止しました。");

		//	詳細メッセージ
		TCHAR   szCause[255];
		err->GetErrorMessage(szCause, 255);
		GET_APP()->WriteDebugLog(szCause);

		//	クラス情報
		sprintf_s(szCause, 254, "\tClass = %s, Function = %s", m_className, m_functionName);
		GET_APP()->WriteDebugLog(szCause);

		err->Delete();
	}
#endif

}


/*!
	実行関数
*/
UINT CThreadSkeleton::WorkThread(LPVOID pParam)
{
	CoInitialize(NULL);

#ifndef _DEBUG
	//	例外情報保存用
	EXCEPTION_RECORD	savedExceptRec;

	__try
	{
#endif
		((CThreadSkeleton*)pParam)->_ThreadMain();
#ifndef _DEBUG
	}
	__except(savedExceptRec = *(GetExceptionInformation())->ExceptionRecord, EXCEPTION_EXECUTE_HANDLER)
	{
		GET_APP()->WriteDebugLog("サーバ内部の未処理例外により、処理スレッドが停止しました。");

		//	詳細メッセージ
		TCHAR   szCause[255];
		sprintf_s(szCause, 254, "\tError code = 0x%x, Error address = 0x%p", savedExceptRec.ExceptionCode, savedExceptRec.ExceptionAddress);
		GET_APP()->WriteDebugLog(szCause);

		__try
		{
			//	クラス情報
			sprintf_s(szCause, 254, "\tClass = %s, Function = %s", ((CThreadSkeleton*)pParam)->m_className, ((CThreadSkeleton*)pParam)->m_functionName);
			GET_APP()->WriteDebugLog(szCause);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			GET_APP()->WriteDebugLog("クラス破損のため、詳細情報取得不能です");
		}
	}
#endif
	CoUninitialize();

	return(0);
}
