#include "StdAfx.h"
#include "threadskeleton.h"
#include "BadAllocException.h"
#include <typeinfo.h>
#include <process.h>


CThreadSkeleton::CThreadSkeleton()
{
	m_hThread = NULL;
	m_dwThreadId = 0;

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

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

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

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

	//	スレッド生成
	m_hThread = (HANDLE)(ULONG_PTR)_beginthreadex(NULL, 0, &WorkThread, this, CREATE_SUSPENDED, &m_dwThreadId);
	if(m_hThread == NULL)
	{
		TRACE_U8(_U16("StartThread error :%d\n"), GetLastError());
		return(-1);
	}

	//	スレッドの実行を開始
	::ResumeThread(m_hThread);

	return(0);
}


/*!
	スレッドの終了・強制終了
*/
void CThreadSkeleton::EndThread()
{
	//	中断を指示
	Break();

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


/*!
	中断
*/
void CThreadSkeleton::Break()
{
	//	中断イベントをセット
	::SetEvent(m_breakEvent);
}


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

	//	実行中かハンドルより確認
	return(::WaitForSingleObject(m_hThread, 0) != WAIT_OBJECT_0);
};


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

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

	//	ハンドル数カウント
	for(count=0; count<sizeof(wait)/sizeof(HANDLE); 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()
{
#ifndef _DEBUG
	try
	{
#endif

		ThreadMain();

#ifndef _DEBUG
	}
	catch(BadAllocException &badAlloc)
	{
		FatalError(typeid(this).name(), "メモリ不足により、処理スレッドが停止しました。");
		err->Delete();
	}
#endif

}


/*!
	実行関数
*/
UINT APIENTRY WorkThread(void *pParam)
{
//	CoInitialize(NULL);
	CThreadSkeleton	*thread = (CThreadSkeleton*)pParam;

#ifndef _DEBUG
	__try
	{
#endif

		thread->_ThreadMain();

#ifndef _DEBUG
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		FatalError(typeid(thread).name(), "サーバ内部の未処理例外により、処理スレッドが停止しました。");
	}
#endif
//	CoUninitialize();

	return(0);
}


/*!
	致命的エラー
*/
void CThreadSkeleton::FatalError(const char *clsName, const char *errInfo)
{
	//	まず、保存先を生成
	char modulePath[MAX_PATH+1];
	DWORD len = GetModuleFileNameA(NULL, modulePath, MAX_PATH);
	while ( modulePath[len--]!='\\' && len!=0 )
		;
	modulePath[len+2] = '\0';        // ￥マークで終わらせる
	strcat_s(modulePath, MAX_PATH, "FatalError.log");

	//	ログを出力
	FILE *errlog;
	if(fopen_s(&errlog, modulePath, "wt") == 0)
	{
		fprintf(errlog, "%s : %s\n", clsName, errInfo);
		fclose(errlog);
	}
}

