/* 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