/** * @file task.cpp * @author myusgun@gmail.com * @brief task */ #include "cf/task.h" #include "cf/memory.h" #ifdef _ON_WINDOWS # include # include typedef HANDLE thread_t; typedef CRITICAL_SECTION mutex_t; # define THREAD_RETURN cf::ulong_t /**< return-type of thread worker */ # define THREAD_CALL __stdcall #else # include # include # include # include typedef pthread_t thread_t; typedef pthread_mutex_t mutex_t; # define THREAD_RETURN void * /**< return-type of thread worker */ # define THREAD_CALL #endif typedef THREAD_RETURN(THREAD_CALL * THREAD_WORKER)(cf::void_t *); /*--------------------------------------------------------------*/ static inline THREAD_RETURN THREAD_CALL Runner(cf::void_t * arg) { cf::task::thread::THREAD_CTX * ctx = reinterpret_cast(arg); ctx->mReturned = ctx->mCallback(ctx->mArgument); ctx->mIsRunning = false; return (THREAD_RETURN)(ctx->mReturned ? -1 : 0); } /*--------------------------------------------------------------*/ cf::task::mutex::mutex() throw (cf::exception) : mIsLocked(false) { mutex_t * inst = NULL; try { inst = reinterpret_cast(cf::memory::alloc(sizeof(mutex_t))); #ifdef _ON_WINDOWS InitializeCriticalSection(inst); #else if (pthread_mutex_init(inst, NULL)) THROW_EXCEPTION("cannot create mutex(" << errno << ":" << strerror(errno) << ")"); #endif mMutex = inst; } catch (cf::exception &e) { cf::memory::free(mMutex); FORWARD_EXCEPTION(e); } } cf::task::mutex::~mutex() { mutex_t * inst = reinterpret_cast(mMutex); #ifdef _ON_WINDOWS DeleteCriticalSection(inst); #else pthread_mutex_destroy(inst); #endif cf::memory::free(mMutex); } cf::void_t cf::task::mutex::lock() throw (cf::exception) { mutex_t * inst = (mutex_t *)mMutex; #ifdef _ON_WINDOWS EnterCriticalSection(inst); #else cf::int32_t result = pthread_mutex_lock(inst); if (result) THROW_EXCEPTION("cannot lock {" << result << "}"); #endif mIsLocked = true; } cf::void_t cf::task::mutex::unlock() throw (cf::exception) { mutex_t * inst = reinterpret_cast(mMutex); #ifdef _ON_WINDOWS LeaveCriticalSection(inst); #else cf::int32_t result = pthread_mutex_unlock(inst); if (result) THROW_EXCEPTION("cannot unlock {" << result << "}"); #endif mIsLocked = false; } cf::bool_t cf::task::mutex::trylock() throw (cf::exception) { cf::bool_t getLocking = false; mutex_t * inst = reinterpret_cast(mMutex); #ifdef _ON_WINDOWS getLocking = TryEnterCriticalSection(inst) ? true : false; #else cf::int32_t result = pthread_mutex_trylock(inst); switch (result) { case 0: getLocking = true; break; case EBUSY: getLocking = false; break; default: THROW_EXCEPTION("cannot trylock {" << result << "}"); } #endif if (getLocking) mIsLocked = true; return getLocking; } cf::bool_t cf::task::mutex::locked() const { return mIsLocked; } cf::task::scopedLock::scopedLock(ISynchronizer * inst) throw (cf::exception) : mSynchronizer(inst) { if (!mSynchronizer) THROW_EXCEPTION("invalid synchronizer"); mSynchronizer->lock(); } cf::task::scopedLock::~scopedLock() { try { unlock(); } catch (...) { } } cf::bool_t cf::task::scopedLock::locked() const { return mSynchronizer->locked(); } cf::void_t cf::task::scopedLock::unlock() throw (cf::exception) { mSynchronizer->unlock(); } cf::task::thread::thread(const ThreadFunction callback) throw (cf::exception) : mThreadID(NULL) { try { mCtx.mIsRunning = false; mCtx.mCallback = callback; #ifndef _ON_WINDOWS mThreadID = cf::memory::alloc(sizeof(thread_t)); #endif } catch (cf::exception &e) { FORWARD_EXCEPTION(e); } } cf::task::thread::~thread() { #ifdef _ON_WINDOWS if (!mThreadID) return; CloseHandle(mThreadID); #else cf::memory::free(mThreadID); #endif } cf::void_t cf::task::thread::start(cf::void_t * arg) throw (cf::exception) { try { if (mCtx.mIsRunning) return; if (!mMutex.trylock()) return; mCtx.mArgument = arg; #ifdef _ON_WINDOWS mThreadID = CreateThread(NULL, 0, Runner, &mCtx, 0, NULL); if (mThreadID == NULL) THROW_EXCEPTION("cannot create thread"); #else cf::int32_t result = 0; pthread_attr_t * attr = NULL; # if defined(_SOLARIS) pthread_attr_t solarisAttr; struct sched_param sched; attr = &solarisAttr; result = pthread_attr_init(attr); if (result) THROW_EXCEPTION("cannot init. thread-attr"); result = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); if (result) THROW_EXCEPTION("cannot set thread-inherit-schedule-attr"); result = pthread_attr_setschedpolicy(attr, SCHED_RR); if (result) THROW_EXCEPTION("cannot set thread-schedule-policy-attr"); sched.sched_priority = 1; result = pthread_attr_setschedparam(attr, &sched); if (result) THROW_EXCEPTION("cannot set thread-schedule-param-attr"); # endif // # if defined(_SOLARIS) result = pthread_create((thread_t *)mThreadID, attr, Runner, &mCtx); if (result) THROW_EXCEPTION("cannot create thread"); #endif mCtx.mIsRunning = true; mMutex.unlock(); } catch (cf::exception &e) { mMutex.unlock(); throw e; } } cf::void_t cf::task::thread::join() { #ifdef _ON_WINDOWS WaitForSingleObject(mThreadID, INFINITE); #else cf::char_t status[16] = {0x00,}; pthread_join(*((thread_t *)mThreadID), (cf::void_t **)status); #endif } cf::bool_t cf::task::thread::isRunning() const { return mCtx.mIsRunning; } cf::uint32_t cf::task::thread::id() { #ifdef _ON_WINDOWS DWORD tid = GetCurrentThreadId(); #else pthread_t tid = pthread_self(); #endif return static_cast(tid); } cf::void_t cf::task::thread::sleep(cf::int32_t milliseconds) { #ifdef _ON_WINDOWS Sleep(static_cast(milliseconds)); #else usleep(milliseconds * 1000); #endif } cf::uint32_t cf::task::process::id() { #ifdef _ON_WINDOWS DWORD pid = GetCurrentProcessId(); #else pid_t pid = getpid(); #endif return static_cast(pid); }