thread_pos.cpp
Go to the documentation of this file.
1 
8 /*****************************************************************************
9 ** Platform Check
10 *****************************************************************************/
11 
12 #include <ecl/config/ecl.hpp>
13 #if defined(ECL_IS_POSIX)
14 
15 /*****************************************************************************
16 ** Includes
17 *****************************************************************************/
18 
19 #include <iostream>
20 #include "../../include/ecl/threads/thread_pos.hpp"
21 #include <sys/resource.h> // provides PRIO_MIN, PRIO_MAX for niceness levels
22 
23 /*****************************************************************************
24 ** Namespaces
25 *****************************************************************************/
26 
27 namespace ecl {
28 
29 /*****************************************************************************
30 * Thread Class Methods
31 *****************************************************************************/
32 
33 Thread::Thread(VoidFunction function, const Priority &priority, const long &stack_size) :
34  thread_task(NULL),
35  has_started(false),
36  join_requested(false)
37 {
38  start(function, priority, stack_size);
39 }
40 
41 Error Thread::start(VoidFunction function, const Priority &priority, const long &stack_size)
42 {
43  if ( has_started ) {
44  ecl_debug_throw(StandardException(LOC,BusyError,"The thread has already been started."));
45  return Error(BusyError); // if in release mode, gracefully fall back to return values.
46  } else {
47  has_started = true;
48  }
49  initialise(stack_size);
50  NullaryFreeFunction<void> nullary_function_object = generateFunctionObject(function);
51  thread_task = new threads::ThreadTask< NullaryFreeFunction<void> >(nullary_function_object, priority);
52  int result = pthread_create(&(this->thread_handle), &(this->attrs), threads::ThreadTask< NullaryFreeFunction<void> >::EntryPoint, thread_task);
53  pthread_attr_destroy(&attrs);
54  if ( result != 0 ) {
55  delete thread_task;
56  thread_task = NULL;
57  ecl_debug_throw(threads::throwPthreadCreateException(LOC,result));
58  return threads::handlePthreadCreateError(result); // if in release mode, gracefully fall back to return values.
59  }
60  return Error(NoError);
61 }
62 
63 Thread::~Thread() {
64  // This should work, but it doesn't. pthread_tryjoin_np fails to differentiate
65  // between an already running thread and one that has already been joined (both
66  // return EBUSY instead of EBUSY and EINVAL
67 // int res;
68 // if ( (res = pthread_tryjoin_np(thread_handle,0)) != 0 ) {
69 // if ( res == EBUSY ) {
70 // // still running, so detach.
71 // pthread_detach(thread_handle);
72 // } else {
73 // // Has already been joined, so leave it be.
74 // }
75 // }
76  if ( has_started && !join_requested ) {
77  pthread_detach(thread_handle);
78  }
79 }
80 void Thread::cancel() {
81  int result = pthread_cancel(thread_handle);
82  // Note - if we reach here, then entrypoint hasn't gone through to conclusion and
83  // subsequently the thread_task object on the heap hasn't been deleted. So...
84  // always delete it here!
85  if ( thread_task != NULL ) {
86  delete thread_task;
87  thread_task = NULL;
88  }
89  if ( result != 0 ) {
90  ecl_debug_throw(threads::throwPthreadJoinException(LOC,result));
91  }
92 }
93 
94 void Thread::join() {
95  join_requested = true;
96  if( thread_task != NULL ) {
97  int result = pthread_join( thread_handle, 0 ); // This also frees up memory like pthread_detach
98  ecl_assert_throw( result == 0, threads::throwPthreadJoinException(LOC,result));
99  }
100 }
101 
102 void Thread::initialise(const long &stack_size) {
103 
104  pthread_attr_init( &attrs );
105  /*************************************************************************
106  ** Linux implementation does not allow PTHREAD_SCOPE_PROCESS
107  *************************************************************************/
108  pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
109  // We can't set priorities for SCHED_OTHER (non real time) here anyway, so just use the default
110  pthread_attr_setinheritsched(&attrs,PTHREAD_INHERIT_SCHED);
111 
112  /*************************************************************************
113  ** Detached State
114  **************************************************************************
115  ** By default on linux, it is joinable. I do cleanup operations within
116  ** this class, so no need to create it as detached, especially as more
117  ** often than not, I need to be able to join to the thread again.
118  *************************************************************************/
119  pthread_attr_setdetachstate(&attrs,PTHREAD_CREATE_JOINABLE);
120 
121  /*************************************************************************
122  ** Stack Size
123  **************************************************************************/
124  if ( stack_size != DefaultStackSize ) {
125  int result = pthread_attr_setstacksize(&attrs,stack_size);
126  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."));
127  }
128 }
129 
130 }; // namespace ecl
131 
132 #endif /* ECL_IS_POSIX */
ecl::VoidFunction
void(* VoidFunction)()
ecl_assert_throw
#define ecl_assert_throw(expression, exception)
ecl
Embedded control libraries.
ecl::Priority
Priority
Shared abstraction of the scheduling priorities.
Definition: priority_common.hpp:36
generateFunctionObject
NullaryFreeFunction< R > generateFunctionObject(R(*function)())
ecl_debug_throw
#define ecl_debug_throw(exception)


ecl_threads
Author(s): Daniel Stonier
autogenerated on Wed Mar 2 2022 00:16:43