thread_pos.cpp
Go to the documentation of this file.
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 ( has_started && !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 */


ecl_threads
Author(s): Daniel Stonier
autogenerated on Mon Jul 3 2017 02:22:01