/* ** ClanLib SDK ** Copyright (c) 1997-2005 The ClanLib Team ** ** This software is provided 'as-is', without any express or implied ** warranty. In no event will the authors be held liable for any damages ** arising from the use of this software. ** ** Permission is granted to anyone to use this software for any purpose, ** including commercial applications, and to alter it and redistribute it ** freely, subject to the following restrictions: ** ** 1. The origin of this software must not be misrepresented; you must not ** claim that you wrote the original software. If you use this software ** in a product, an acknowledgment in the product documentation would be ** appreciated but is not required. ** 2. Altered source versions must be plainly marked as such, and must not be ** misrepresented as being the original software. ** 3. This notice may not be removed or altered from any source distribution. ** ** Note: Some of the libraries ClanLib may link to may have additional ** requirements or restrictions. ** ** File Author(s): ** ** Magnus Norddahl ** (if your name is missing here, please add it) */ #include "Core/precomp.h" #include #include "API/Core/System/cl_assert.h" #include "API/Core/System/log.h" #include "thread_pthread.h" ///////////////////////////////////////////////////////////////////////////// // CL_Thread_Helper unix implementation: class CL_Thread_Helper : public CL_Runnable { public: CL_Thread_Helper(int (*func)(void*), void *value) : func(func), value(value) { } virtual void run() { func(value); } private: int (*func)(void*); void *value; }; ///////////////////////////////////////////////////////////////////////////// // CL_Thread unix/pthread implementation: CL_Thread::CL_Thread(int (*func)(void*), void *value) : impl(new CL_Thread_Generic) { impl->ref_count = 1; impl->runnable = new CL_Thread_Helper(func, value); impl->delete_runnable = true; impl->running = false; } CL_Thread::CL_Thread(CL_Runnable *runnable, bool delete_runnable) : impl(new CL_Thread_Generic) { impl->ref_count = 1; impl->runnable = runnable; impl->delete_runnable = delete_runnable; impl->running = false; } CL_Thread::CL_Thread(const CL_Thread ©) : impl(copy.impl) { if (impl) impl->ref_count++; } CL_Thread::CL_Thread() : impl(0) { } CL_Thread::~CL_Thread() { if (impl) { impl->ref_count--; if (impl->ref_count == 0) { terminate(); if (impl->delete_runnable) delete impl->runnable; delete impl; } } } CL_Thread &CL_Thread::operator =(const CL_Thread ©) { if (impl) { impl->ref_count--; if (impl->ref_count == 0) { terminate(); if (impl->delete_runnable) delete impl->runnable; delete impl; } } impl = copy.impl; if (impl) impl->ref_count++; return *this; } void CL_Thread::start() { if (impl->running) return; cl_assert( pthread_create( &impl->thread, NULL, impl->run_init, impl)==0); impl->running = true; } void *CL_Thread_Generic::run_init(void *_self) { CL_Thread_Generic *self = (CL_Thread_Generic *) _self; // kill thread immidiately - no cancelation point... pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); self->runnable->run(); return NULL; } void CL_Thread::terminate() { if (impl->running) pthread_cancel(impl->thread); impl->running = false; } void CL_Thread::wait() { if (impl->running) pthread_join(impl->thread, NULL); impl->running = false; } void CL_Thread::set_priority(EThreadPriority priority) { #ifdef __APPLE__ struct sched_param param; memset(¶m, 0, sizeof(struct sched_param)); // on macosx the valid values for thread priority are 0-127 // may be different on other posix systems - unknown. switch (priority) { case cl_priority_above_normal: param.sched_priority = 50; break; case cl_priority_below_normal: param.sched_priority = 15; break; case cl_priority_highest: param.sched_priority = 100; break; case cl_priority_idle: param.sched_priority = 5; break; case cl_priority_lowest: param.sched_priority = 0; break; case cl_priority_time_critical: param.sched_priority = 127; break; case cl_priority_normal: default: param.sched_priority = 31; break; } int i = pthread_setschedparam(impl->thread, SCHED_RR, ¶m); if (i != 0) throw CL_Error(CL_String::format("Failed to set thread priority (error %1)",i)); #endif // Linux doesn't let your set proirities real time due to its renice model } CL_ThreadId CL_Thread::get_current_id() { return CL_ThreadId(); } CL_ThreadId::CL_ThreadId() :impl(new CL_ThreadId_Generic) { impl->thread_id = pthread_self(); } CL_ThreadId::CL_ThreadId(const CL_ThreadId ©) :impl(new CL_ThreadId_Generic) { *this = copy; } CL_ThreadId::~CL_ThreadId() { delete impl; } CL_ThreadId &CL_ThreadId::operator=(const CL_ThreadId ©) { // I think this is safe to do, but I'm not certain at this point impl->thread_id = copy.impl->thread_id; return *this; } bool CL_ThreadId::operator ==(const CL_ThreadId &cmp) const { return pthread_equal(impl->thread_id, cmp.impl->thread_id); } bool CL_ThreadId::operator !=(const CL_ThreadId &cmp) const { return !operator ==(cmp); } bool CL_ThreadId::operator <(const CL_ThreadId &cmp) const { // first test with operator== because different pthread_t values from the same // thread may not be binary equal to each other - this routine is probably not // the best but it should get the job done for now if (operator ==(cmp)) return false; return memcmp(&impl->thread_id, &cmp.impl->thread_id, sizeof(pthread_t)) < 0; }