/* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 :
* =====================================================================
* sc_thread.c
* Copyright (c) 2003 - 2011 sys0tem
* LICENSE :
* LGPL (GNU Lesser General Public License - Version 3,29 June 2007)
* http://www.gnu.org/copyleft/lesser.html
* or
* EPL (Eclipse Public License - v1.0)
* http://www.eclipse.org/legal/epl-v10.html
* =====================================================================
*/
#include <sc_mmgr.h>
#include <sc_thread.h>
#include <sc_string.h>
/* =====================================================================
* プロトタイプ宣言
* =====================================================================
*/
static void SC_Thread_start(SC_Thread* thread);
static void SC_Thread_join(SC_Thread* thread);
#if (SC_isWindows)
static unsigned __stdcall SC_Thread_run(void* data);
#else
static void* SC_Thread_run(void* data);
#endif
/**
* SC_Thread を生成する。
* スレッドに渡されるデータ data は、コピーしスレッドに渡されます。
*
* @param run スレッドにて実行する関数ポインタ
* @param data スレッドに渡すデータ
* @param dataSize データのサイズ
* @return スレッドオブジェクト
*/
SC_Thread* SC_Thread_new(void (*run)(void*), void* data, size_t dataSize)
{
SC_Thread* thread;
thread = (SC_Thread*) malloc(sizeof(SC_Thread) + dataSize);
if (thread == NULL)
{ /* メモリ確保失敗 */
return NULL;
}
if (data == NULL)
{
thread->_data = NULL;
}
else
{
thread->_data = (thread + 1);
memcpy(thread->_data, data, dataSize);
}
thread->_run = run;
thread->start = SC_Thread_start;
thread->join = SC_Thread_join;
return thread;
}
/**
* スレッドのリソースを開放します。
* [注意]
* 本メソッドでは、スレッドの生死にかかわらず、
* thread 管理メモリを破棄します。
*
* @param thread スレッド
*/
void SC_Thread_delete(SC_Thread* thread)
{
free(thread);
}
/**
* mutex を初期化します。
*
* @param mutex mutex
*/
void SC_Mutex_init(mutex_t* mutex)
{
#if (SC_isWindows)
*mutex = CreateMutex(NULL, FALSE, NULL);
#else
pthread_mutex_init(mutex, NULL);
#endif
}
/**
* mutex を破棄します。
*
* @param mutex 破棄する mutex
*/
void SC_Mutex_destroy(mutex_t* mutex)
{
#if (SC_isWindows)
CloseHandle(*mutex);
#else
pthread_mutex_destroy(mutex);
#endif
}
/**
* 指定された mutex をロックします。
*
* @param mutex ロックする mutex
*/
void SC_Mutex_lock(mutex_t* mutex)
{
#if (SC_isWindows)
WaitForSingleObject(*mutex, INFINITE);
#else
pthread_mutex_lock(mutex);
#endif
}
/**
* 指定された mutex をアンロックします。
*
* @param mutex アンロックする mutex
*/
void SC_Mutex_unlock(mutex_t* mutex)
{
#if (SC_isWindows)
ReleaseMutex(*mutex);
#else
pthread_mutex_unlock(mutex);
#endif
}
/**
* 指定された ms 間スリープします。
*/
void SC_sleep(long time)
{
#if (SC_isWindows)
Sleep(time);
#else
struct timespec req;
long sec = time / 1000;
long msec = time - (sec * 1000);
req.tv_sec = sec;
req.tv_nsec = msec * 1000000;
nanosleep(&req, NULL);
#endif
}
/* =====================================================================
* 以下、内部でのみ使用する関数
* =====================================================================
*/
/**
* スレッドを開始します。
*
* @param thread スレッド
*/
static
void SC_Thread_start(SC_Thread* thread)
{
#if (SC_isWindows)
thread->_hThread = (HANDLE) _beginthreadex(
NULL,
0,
&SC_Thread_run,
(LPVOID) thread,
0,
&thread->_threadID);
#else
pthread_create(
&(thread->_tid),
NULL,
SC_Thread_run,
thread);
#endif
}
/**
* 指定されたスレッドが終了するのを待ちます。
*
* @param thread スレッド
*/
static
void SC_Thread_join(SC_Thread* thread)
{
#if (SC_isWindows)
WaitForSingleObject(thread->_hThread, INFINITE);
CloseHandle(thread->_hThread);
#else
pthread_join(thread->_tid, NULL);
#endif
}
/**
* スレッドにて実行される関数。
*
* @param pArguments SC_Thread が渡されます。
* @return 0 or NULL ポインタ
*/
#if (SC_isWindows)
static
unsigned __stdcall SC_Thread_run(void* pArguments)
{
SC_Thread* thread = (SC_Thread*) pArguments;
thread->_run(thread->_data);
_endthreadex(0);
return 0;
}
#else
static
void* SC_Thread_run(void* pArguments)
{
SC_Thread* thread = (SC_Thread*) pArguments;
thread->_run(thread->_data);
pthread_exit(NULL);
}
#endif