$search
00001 00008 /***************************************************************************** 00009 ** Platform Check 00010 *****************************************************************************/ 00011 00012 #include <ecl/config/ecl.hpp> 00013 #if defined(ECL_IS_POSIX) 00014 00015 /***************************************************************************** 00016 ** Includes 00017 *****************************************************************************/ 00018 00019 #include <iostream> 00020 #include "../../include/ecl/threads/thread_pos.hpp" 00021 #include <sys/resource.h> // provides PRIO_MIN, PRIO_MAX for niceness levels 00022 00023 /***************************************************************************** 00024 ** Namespaces 00025 *****************************************************************************/ 00026 00027 namespace ecl { 00028 00029 /***************************************************************************** 00030 * Thread Class Methods 00031 *****************************************************************************/ 00032 00033 Thread::Thread(VoidFunction function, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException) : 00034 thread_task(NULL), 00035 has_started(false), 00036 join_requested(false) 00037 { 00038 start(function, priority, stack_size); 00039 } 00040 00041 Error Thread::start(VoidFunction function, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException) 00042 { 00043 if ( has_started ) { 00044 ecl_debug_throw(StandardException(LOC,BusyError,"The thread has already been started.")); 00045 return Error(BusyError); // if in release mode, gracefully fall back to return values. 00046 } else { 00047 has_started = true; 00048 } 00049 initialise(stack_size); 00050 NullaryFreeFunction<void> nullary_function_object = generateFunctionObject(function); 00051 thread_task = new threads::ThreadTask< NullaryFreeFunction<void> >(nullary_function_object, priority); 00052 int result = pthread_create(&(this->thread_handle), &(this->attrs), threads::ThreadTask< NullaryFreeFunction<void> >::EntryPoint, thread_task); 00053 pthread_attr_destroy(&attrs); 00054 if ( result != 0 ) { 00055 delete thread_task; 00056 thread_task = NULL; 00057 ecl_debug_throw(threads::throwPthreadCreateException(LOC,result)); 00058 return threads::handlePthreadCreateError(result); // if in release mode, gracefully fall back to return values. 00059 } 00060 return Error(NoError); 00061 } 00062 00063 Thread::~Thread() { 00064 // This should work, but it doesn't. pthread_tryjoin_np fails to differentiate 00065 // between an already running thread and one that has already been joined (both 00066 // return EBUSY instead of EBUSY and EINVAL 00067 // int res; 00068 // if ( (res = pthread_tryjoin_np(thread_handle,0)) != 0 ) { 00069 // if ( res == EBUSY ) { 00070 // // still running, so detach. 00071 // pthread_detach(thread_handle); 00072 // } else { 00073 // // Has already been joined, so leave it be. 00074 // } 00075 // } 00076 if ( !join_requested ) { 00077 pthread_detach(thread_handle); 00078 } 00079 } 00080 void Thread::cancel() ecl_debug_throw_decl(StandardException) { 00081 int result = pthread_cancel(thread_handle); 00082 // Note - if we reach here, then entrypoint hasn't gone through to conclusion and 00083 // subsequently the thread_task object on the heap hasn't been deleted. So... 00084 // always delete it here! 00085 if ( thread_task != NULL ) { 00086 delete thread_task; 00087 thread_task = NULL; 00088 } 00089 if ( result != 0 ) { 00090 ecl_debug_throw(threads::throwPthreadJoinException(LOC,result)); 00091 } 00092 } 00093 00094 void Thread::join() ecl_debug_throw_decl(StandardException) { 00095 join_requested = true; 00096 if( thread_task != NULL ) { 00097 int result = pthread_join( thread_handle, 0 ); // This also frees up memory like pthread_detach 00098 ecl_assert_throw( result == 0, threads::throwPthreadJoinException(LOC,result)); 00099 } 00100 } 00101 00102 void Thread::initialise(const long &stack_size) ecl_assert_throw_decl(StandardException) { 00103 00104 pthread_attr_init( &attrs ); 00105 /************************************************************************* 00106 ** Linux implementation does not allow PTHREAD_SCOPE_PROCESS 00107 *************************************************************************/ 00108 pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); 00109 // We can't set priorities for SCHED_OTHER (non real time) here anyway, so just use the default 00110 pthread_attr_setinheritsched(&attrs,PTHREAD_INHERIT_SCHED); 00111 00112 /************************************************************************* 00113 ** Detached State 00114 ************************************************************************** 00115 ** By default on linux, it is joinable. I do cleanup operations within 00116 ** this class, so no need to create it as detached, especially as more 00117 ** often than not, I need to be able to join to the thread again. 00118 *************************************************************************/ 00119 pthread_attr_setdetachstate(&attrs,PTHREAD_CREATE_JOINABLE); 00120 00121 /************************************************************************* 00122 ** Stack Size 00123 **************************************************************************/ 00124 if ( stack_size != DefaultStackSize ) { 00125 int result = pthread_attr_setstacksize(&attrs,stack_size); 00126 ecl_assert_throw( result == 0, StandardException(LOC,ConfigurationError,"Specified stack size was less than PTHREAD_STACK_MIN or wasn't a multiple of the page size.")); 00127 } 00128 } 00129 00130 }; // namespace ecl 00131 00132 #endif /* ECL_IS_POSIX */