////////////////////////////////////////////////////////////////////////////
// CThread クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include <assert.h>
#include <pthread.h>
#include "Thread.h"

// スレッド生成用の関数のプロトタイプ宣言
extern "C" void* CThread_ThreadEntry( void* );

////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CThread::CThread() :
	semaWait( 1 ),
	semaExitFlg( 1 ),
	IsExit( true )
{

}

CThread::~CThread()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

// スレッドの開始
bool CThread::start()
{
	pthread_attr_t att;
	int r;
	assert( IsExit );

	// 待ち合わせ用のフラグとセマフォを設定
	IsExit = false;
	semaWait.P();

	// スレッドを構築する
	pthread_attr_init( &att );
	pthread_attr_setdetachstate( &att, PTHREAD_CREATE_DETACHED );
	r = pthread_create( &m_ThreadID, &att, CThread_ThreadEntry, this );
	return ( r == 0 );
}

// スレッドのエントリポイント
void CThread::run()
{
	
}

// スレッドの前後の処理
void CThread::RunEntry()
{
	// スレッドの処理を開始してやる
	this->run();

	// 終了する
	ExitThread();
}

// スレッド番号を取得
pthread_t CThread::GetThreadID() const
{
	return m_ThreadID;
}

// このスレッドの終了を待ち合わせる
void CThread::Wait()
{
	bool flg;

	// 終了フラグの値を取得する
	semaExitFlg.P();
	flg = IsExit;
	semaExitFlg.V();

	// すでに終了していた場合は特にすることはない
	if ( flg ) return ;

	// このスレッドの終了を待ち合わせる
	semaWait.P();
	semaWait.V();
}

// スレッドを終了させる
void CThread::ExitThread()
{
	// 終了フラグに値を設定する
	semaExitFlg.P();
	IsExit = true;
	semaExitFlg.V();

	// 待ち合わせ用セマフォを解放
	semaWait.V();

	// スレッドを終了する
	pthread_exit( NULL );
}

// 一定時間だけスレッドの終了を待ち合わせる
bool CThread::WaitForTime( int ms )
{
	bool flg;
	bool r;

	// 終了フラグの値を取得する
	semaExitFlg.P();
	flg = IsExit;
	semaExitFlg.V();

	// すでに終了していた場合は特にすることはない
	if ( flg ) return true;

	// 終了を待ち合わせる
	r = semaWait.WaitForTime( ms );
	if ( r ) semaWait.V();	// WaitForTimeで占有したセマフォを解放する

	return r;
}

////////////////////////////////////////////////////////////////////////////
// その他
////////////////////////////////////////////////////////////////////////////

// スレッド生成用
void* CThread_ThreadEntry( void *pArg )
{
	CThread *p = reinterpret_cast< CThread* >( pArg );
	p->RunEntry();
	return NULL;
}
