libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
thread_base_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace ppd { namespace private_ {
20 
21 // Implementation details..... Don't look below here!!! ;)
22 
23 // "thread_base" implementation...
24 
25  template<generic_traits::api_type API, typename Mdl> inline bool
26  thread_base<API, Mdl>::is_running() const noexcept(true) {
27  return thread_params.state.load()==thread_traits::api_params_type::active;
28  }
29 
30  template<generic_traits::api_type API, typename Mdl> inline const typename thread_base<API, Mdl>::thread_traits::api_params_type::states
31  thread_base<API, Mdl>::state_nolk(typename thread_traits::api_params_type const &params) noexcept(true) {
32  if (params.state.load()!=thread_traits::api_params_type::no_kernel_thread) {
33  const typename thread_traits::api_params_type::states current_state=params.state.load();
34  if (current_state==thread_traits::api_params_type::active) {
35  return params.state.load()==thread_traits::api_params_type::active ? current_state : thread_traits::api_params_type::suspended;
36  } else {
37  return current_state;
38  }
39  } else {
40  return thread_traits::api_params_type::no_kernel_thread;
41  }
42  }
43 
44 /* TODO JMG: can't generically suspend, because how do I suspend sequential traits?
45  template<generic_traits::api_type API, typename Mdl> inline const typename thread_base<API, Mdl>::thread_traits::api_params_type::suspend_count
46  thread_base<API, Mdl>::suspend() noexcept(true) {
47  if (this->state()<thread_traits::api_params_type::no_kernel_thread) {
48  thread_params_lock.lock();
49  // Critical sections don't like double-unlocking....
50  bool locked=true;
51  if (thread_traits::get_current_thread_id()==thread_params.id) {
52  // We want to suspend ourselves - better release the lock, otherwise we'll get deadlocks.
53  thread_params_lock.unlock();
54  locked=false;
55  }
56  const typename thread_traits::api_params_type::suspend_count sus_ct=thread_traits::suspend(thread_params);
57  if (locked) {
58  thread_params_lock.unlock();
59  }
60  return sus_ct;
61  } else {
62  return 0;
63  }
64  }
65 */
66  template<generic_traits::api_type API, typename Mdl> inline const typename thread_base<API, Mdl>::thread_traits::api_params_type::suspend_count
67  thread_base<API, Mdl>::resume() noexcept(true) {
68  if (this->state()<thread_traits::api_params_type::no_kernel_thread) {
69  const typename lock_traits::critical_section_type::write_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
70  return thread_traits::resume(thread_params);
71  } else {
72  return 0;
73  }
74  }
75 
76  template<generic_traits::api_type API, typename Mdl>
77  inline void
78  thread_base<API, Mdl>::create_running() noexcept(false) {
79  {
80  const typename lock_traits::critical_section_type::write_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
81  if (state_nolk(thread_params)>=thread_traits::api_params_type::no_kernel_thread) {
82  if (!thread_traits::create(thread_traits::api_params_type::create_running, thread_params)) {
83  assert(!"Failed to create thread!");
84  throw exception_type(
85  _T("Failed to create thread."),
86  info::function(
87  __LINE__, __PRETTY_FUNCTION__,
88  typeid(&thread_base<API, Mdl>::create_running),
90  thread_traits::demangle_name(typeid(typename thread_traits::api_params_type::creation_flags)).begin(),
91  tostring(thread_traits::api_params_type::create_running)
92  )
93  ),
95  );
96  } else {
97  // Although a kernel thread may not yet have been created, pretend one has to ensure that an immediate call to is_running() returns true, not false, whilst we await the creation of the kernel thread.
98  thread_params.state=thread_traits::api_params_type::activating;
99  }
100  }
101  }
102  }
103 
104  template<generic_traits::api_type API, typename Mdl> inline const typename thread_base<API, Mdl>::thread_traits::api_params_type::states
105  thread_base<API, Mdl>::state() const noexcept(true) {
106  const typename lock_traits::critical_section_type::write_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
107  return state_nolk(thread_params);
108  }
109 
110  template<generic_traits::api_type API, typename Mdl> inline
111  typename thread_base<API, Mdl>::thread_traits::api_params_type::priority_type __fastcall
112  thread_base<API, Mdl>::kernel_priority() const noexcept(false) {
113 // const typename lock_traits::critical_section_type::read_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
114  return thread_traits::get_kernel_priority(thread_params.id);
115  }
116 
117  template<generic_traits::api_type API, typename Mdl> inline void
118  thread_base<API, Mdl>::kernel_priority(const typename thread_traits::api_params_type::priority_type priority) noexcept(false) {
119 // const typename lock_traits::critical_section_type::read_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
120  thread_traits::set_kernel_priority(thread_params.id, priority);
121  }
122 
123  template<generic_traits::api_type API, typename Mdl> inline
125  thread_base<API, Mdl>::kernel_affinity() const noexcept(false) {
126 // const typename lock_traits::critical_section_type::read_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
127  return thread_traits::get_kernel_affinity(thread_params.id);
128  }
129 
130  template<generic_traits::api_type API, typename Mdl> inline void
131  thread_base<API, Mdl>::kernel_affinity(const typename thread_traits::api_params_type::processor_mask_type &mask) noexcept(false) {
132 // const typename lock_traits::critical_section_type::read_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
133  thread_traits::set_kernel_affinity(thread_params.id, mask);
134  }
135 
136  template<generic_traits::api_type API, typename Mdl> inline void
137  thread_base<API, Mdl>::set_name(char const *name) noexcept(false) {
138 // const typename lock_traits::critical_section_type::read_lock_type lock(thread_params_lock, lock_traits::infinite_timeout());
139  thread_traits::set_name(thread_params.id, name);
140  }
141 
142  template<generic_traits::api_type API, typename Mdl> inline const tstring
143  thread_base<API, Mdl>::to_string() const noexcept(false) {
144  tostringstream str;
145  str<<StringToTString(thread_traits::demangle_name(typeid(*this)).begin())
146  <<_T("\nException thrown: ")<<exception_thrown_in_thread
147  <<_T("\nParams: ")<<thread_params.to_string()
148  <<_T("\nExit wait period=")<<exit_wait_period<<_T("ms");
149  return str.str();
150  }
151 
152  template<generic_traits::api_type API, typename Mdl> inline
153  thread_base<API, Mdl>::thread_base(const typename thread_traits::api_params_type::suspend_period_ms exit_wait_p) noexcept(false)
154  : exit_wait_period(exit_wait_p), thread_params(core_work_fn, nullptr, thread_traits::api_params_type::max_stack_size) {
155  // No need to lock here - creating a new object.
156  thread_params.arglist=static_cast<typename thread_traits::api_params_type::arglist_type>(this);
157  }
158 
159  template<generic_traits::api_type API, typename Mdl> inline
160  thread_base<API, Mdl>::thread_base(const thread_base &tb) noexcept(true)
161  : exit_wait_period(tb.exit_wait_period), exception_thrown_in_thread(tb.exception_thrown_in_thread), thread_params(tb.thread_params) {
162  // No need to lock here - creating a new object.
163  thread_params.arglist=static_cast<typename thread_traits::api_params_type::arglist_type>(this);
164  }
165 
166  template<generic_traits::api_type API, typename Mdl> inline
167  thread_base<API, Mdl>::~thread_base() noexcept(false) {
168  // Despite that, what the hell - throw this and be damned...
169  if (state_nolk(thread_params)==thread_traits::api_params_type::null_this_pointer) {
170  throw exception_type(_T("The thread registered an abnormal exit state (a NULL 'this' pointer)."), info::function(__LINE__, __PRETTY_FUNCTION__, typeid(*this), info::function::argument(_T("const typename api_threading_traits<API, Mdl>::states"), tostring(this->state()))), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
171  }
172  }
173 
174  template<generic_traits::api_type API, typename Mdl> inline void
175  thread_base<API, Mdl>::wait_thread_exit() noexcept(false) {
176  switch (thread_params.state) {
177  case thread_traits::api_params_type::no_kernel_thread:
178  case thread_traits::api_params_type::exiting:
179  break;
180  default:
181  if (state_nolk(thread_params)==thread_traits::api_params_type::suspended) {
182  thread_traits::resume(thread_params);
183  }
184  thread_traits::wait_thread_exit(thread_params, exit_wait_period);
185  if (state_nolk(thread_params)==thread_traits::api_params_type::active || state_nolk(thread_params)==thread_traits::api_params_type::suspended) {
186  // O.k. we tried to let it die naturally. No more Mr.Nice Guy...
187  JMMCG_TRACE(_T("Terminating thread: ")<<*this);
188  thread_traits::terminate(thread_params.id);
189  }
190  thread_traits::cleanup(thread_params.id);
191  assert(state_nolk(thread_params)>=thread_traits::api_params_type::no_kernel_thread);
192  thread_params.id=0;
193  break;
194  }
195  }
196 
197  template<generic_traits::api_type API, typename Mdl> inline void
198  thread_base<API, Mdl>::request_exit() const noexcept(false) {
199  if (thread_params.id) {
200  thread_traits::terminate(thread_params.id);
201  }
202  }
203 
204 /* Not used, just here as a template for code you might need...
205  template<generic_traits::api_type API, typename Mdl> typename thread_base<API, Mdl>::thread_traits::api_params_type::core_work_fn_ret_t
206  thread_base<API, Mdl>::core_work_fn(thread_traits::api_params_type::core_work_fn_arg_t ptr) noexcept(false) {
207  assert(ptr);
208  thread_base<API, Mdl> * const pthis=reinterpret_cast<thread_base<API, Mdl> *>(ptr);
209  assert(pthis);
210  if (pthis) {
211  try {
212  const api_threading_traits<API, Mdl>::api_params_type::states ret=pthis->process();
213  pthread_params.id=0;
214  return reinterpret_cast<thread_traits::api_params_type::core_work_fn_ret_t>(ret);
215  } catch (abi::__forced_unwind &) {
216  throw;
217  } catch (...) {
218  assert(!"Unknown exception caught.");
219  pthis->exception_thrown_in_thread.set(std::current_exception());
220  }
221  return reinterpret_cast<thread_traits::api_params_type::core_work_fn_ret_t>(api_threading_traits<API, Mdl>::api_params_type::unknown_exception);
222  }
223  // In reality, no errors are actively reported to the user for this case, as the pthis was null.
224  // So we almost silently fail, and hope that they aren't sooooo dumb as to not notice that their work isn't being processed...
225  // This is because the only "opportunity" I have to report it is as an exception in the destructor. Hooo-boy would that be evil...
226  // Just think of the memory leaks.... So I don't do that. That's the breaks....
227  return reinterpret_cast<thread_traits::api_params_type::core_work_fn_ret_t>(api_threading_traits<API, Mdl>::api_params_type::null_this_pointer);
228  }
229 */
230 
231 } } } }