libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
thread_api_traits.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_THREAD_API_TRAITS_HPP
2 #define LIBJMMCG_CORE_THREAD_API_TRAITS_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #ifdef _MSC_VER
23 # pragma warning(disable:4786) // identifier was truncated to '255' characters in the debug information
24 # define NOMINMAX
25 # undef max
26 # undef min
27 #endif
28 
29 #include "locking.hpp"
30 #include "atomic_counter.hpp"
31 
32 #include <array>
33 #include <limits>
34 #include <mutex>
35 
36 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
37 
38  template<ppd::generic_traits::api_type API, typename Mdl>
39  class crt_exception;
40 
41 namespace ppd {
42 
43  template<generic_traits::api_type API, typename Mdl>
44  struct api_lock_traits;
45 
46  namespace no_locking {
47  struct critical_section;
48  class anon_event;
49 
61  };
62  }
63 
64  /// The various lock-types for sequential use, with no threading.
65  template<>
66  struct api_lock_traits<platform_api, sequential_mode> {
67  static constexpr generic_traits::api_type api_type=platform_api;
68  typedef sequential_mode model_type;
81  };
82 
83  typedef int handle_type;
84 
85  typedef no_locking::critical_section anon_mutex_type;
86  typedef no_locking::critical_section nonrecursive_anon_mutex_type;
87  typedef no_locking::critical_section recursive_anon_mutex_type;
88  typedef no_locking::anon_event anon_event_type;
89  using anon_spin_event_type=no_locking::critical_section;
90  typedef no_locking::critical_section critical_section_type;
91  typedef no_locking::critical_section recursive_critical_section_type;
92  typedef no_locking::critical_section mutex_type;
93  typedef no_locking::critical_section recursive_mutex_type;
94  typedef no_locking::anon_event event_type;
95  typedef no_locking::anon_event anon_semaphore_type;
96  typedef no_locking::anon_event semaphore_type;
97  /**
98  This counter-type may not use a mutex_type to protect the counter, it may use the underlying API to provide a lock-free atomic counter. It is 2-5 times faster than the atomic_counter_type, also the CPU load on two processors is close to 100% in certain performance tests.
99  */
100  template<class V>
101  using atomic_counter_type=atomic_ctr<V, api_lock_traits<api_type, model_type>>;
102  template<class V>
103  using noop_atomic_ctr=noop_atomic_ctr_base<V, api_lock_traits<api_type, model_type>>;
104  template<class V>
105  using atomic=atomic_ctr<V, api_lock_traits<api_type, model_type>>;
106  using timeout_type=int;
107  template<class... T>
108  struct scoped_lock {
109  explicit constexpr scoped_lock(T&...) noexcept(true) {}
110  };
111 
112  using exception_type=crt_exception<platform_api, sequential_mode>;
113 
114  static constexpr timeout_type infinite_timeout() noexcept(true) FORCE_INLINE {
115  return std::numeric_limits<timeout_type>::max();
116  }
117  };
118 
119  template<>
120  struct api_lock_traits<generic_traits::api_type::no_api, sequential_mode> : public api_lock_traits<platform_api, sequential_mode> {
121  };
122 
123  namespace no_locking {
124 
125  typedef api_lock_traits<platform_api, sequential_mode> lock_traits;
126 
127  struct critical_section final : public lock::lockable<lock_traits> {
128 // typedef no_locking::lock_traits lock_traits;
130  using lock_traits=base_t::lock_traits;
131  typedef lock_traits::atomic_state_type atomic_state_type;
132  typedef lock_traits::timeout_type timeout_type;
133  typedef lock::in_process<critical_section> lock_type;
136  typedef lock::in_process_unlockable<critical_section> unlockable_type;
139  /**
140  To assist in allowing compile-time computation of the algorithmic order of the threading model.
141  */
143 
144  explicit critical_section(const atomic_state_type =lock_traits::atom_set) noexcept(true) FORCE_INLINE {
145  }
146  critical_section(critical_section const &)=delete;
147  static constexpr atomic_state_type __fastcall set() noexcept(true) FORCE_INLINE {
148  return lock_traits::atom_set;
149  }
150  atomic_state_type __fastcall lock() noexcept(true) override FORCE_INLINE {
151  return lock_traits::atom_set;
152  }
153  atomic_state_type __fastcall lock(const timeout_type) noexcept(true) override FORCE_INLINE {
154  return lock_traits::atom_set;
155  }
156  atomic_state_type __fastcall unlock() noexcept(true) override FORCE_INLINE {
158  }
159  static void decay() noexcept(true) FORCE_INLINE {}
160  };
161  template<class V>
162  struct atomic_ctr final : public lock_traits {
163  typedef no_locking::lock_traits lock_traits;
164  typedef lock_traits base_t;
165  typedef lock_traits::atomic_state_type atomic_state_type;
166 
167  /**
168  To assist in allowing compile-time computation of the algorithmic order of the threading model.
169  */
171 
172  explicit constexpr atomic_ctr(const atomic_state_type =atom_set) noexcept(true) FORCE_INLINE {
173  }
174  atomic_ctr(atomic_ctr const &)=delete;
175  };
176 
177  class anon_event final : public lock::lockable_settable<lock_traits> {
178  public:
179  typedef no_locking::lock_traits lock_traits;
180  typedef lock::lockable<lock_traits> base_t;
181  typedef lock_traits::atomic_state_type atomic_state_type;
182  typedef atomic_state_type lock_result_type;
183  typedef lock_traits::timeout_type timeout_type;
184  typedef int count_type;
185  typedef lock::in_process<anon_event> lock_type;
188 
189  /**
190  To assist in allowing compile-time computation of the algorithmic order of the threading model.
191  */
193 
194  explicit anon_event(const atomic_state_type f=lock_traits::atom_unset) noexcept(true) FORCE_INLINE
195  : fudge(f) {
196  }
197  anon_event(anon_event const &)=delete;
198  atomic_state_type __fastcall set(void) noexcept(true) override FORCE_INLINE {
199  fudge=lock_traits::atom_set;
200  return fudge;
201  }
202  atomic_state_type __fastcall reset(void) noexcept(true) override FORCE_INLINE {
203  fudge=lock_traits::atom_unset;
204  return fudge;
205  }
206  lock_result_type __fastcall lock() noexcept(true) override FORCE_INLINE {
207  fudge=lock_traits::atom_set;
208  return fudge;
209  }
210  lock_result_type __fastcall lock(const timeout_type) noexcept(true) override FORCE_INLINE {
211  fudge=lock_traits::atom_set;
212  return fudge;
213  }
214  lock_result_type __fastcall unlock() noexcept(true) override FORCE_INLINE {
215  fudge=lock_traits::atom_unset;
216  return fudge;
217  }
218  static constexpr count_type __fastcall count() noexcept(true) FORCE_INLINE {
219  return 0;
220  }
221  static lock_type::atomic_t &__fastcall locker() noexcept(true) FORCE_INLINE {
222  static lock_type::atomic_t lk;
223  return lk;
224  }
225 
226  private:
227  atomic_state_type fudge;
228  };
229 
230  }
231 
232  template<generic_traits::api_type API, typename Mdl>
233  struct api_threading_traits {
235  typedef api_lock_traits<API, Mdl> lock_traits;
236  typedef Mdl model_type;
237  /// An unmangled name surely can't be longer than 16k?!
238  using demangled_name_t=std::array<char, 16384>;
239  /// 100 functions in the stack frame should be enough for anyone... Eeek!
240  static constexpr int max_num_fn_ptrs=100;
241  /// And this struct would *never* be larger than the stack size we've allowed in a thread, surely?!
243 
244  static void raise(int sig) noexcept(true);
245  /// Create a new OS-level thread of the appropriate type.
246  /**
247  \return true is the OS-level thread was successfully created, false otherwise.
248  */
249  static bool __fastcall create(const typename api_params_type::creation_flags creflag, api_params_type &) noexcept(true) FORCE_INLINE;
250  static typename api_params_type::suspend_count __fastcall suspend(api_params_type const &) noexcept(true) FORCE_INLINE;
251  static typename api_params_type::suspend_count __fastcall resume(api_params_type const &) noexcept(true) FORCE_INLINE;
252  static typename api_params_type::states __fastcall state(api_params_type &) noexcept(true) FORCE_INLINE;
253  static bool __fastcall is_running(api_params_type &) noexcept(true) FORCE_INLINE;
254  /// Exit the currently running thread.
255  static void __fastcall exit(typename api_params_type::states &) noexcept(true) FORCE_INLINE;
256  /// Request or force that the target thread exit.
257  /**
258  Note that this may result in undefined behaviour depending upon how the underlying OS copes with cleaning the state loaded by the thread.
259  */
260  static void __fastcall terminate(typename api_params_type::handle_type) noexcept(false) FORCE_INLINE;
261  /// Ensure that any possible clean up that may need to be done of thread state may be performed after the thread has exited.
262  static void __fastcall cleanup(typename api_params_type::handle_type) noexcept(false) FORCE_INLINE;
263  static void __fastcall set_kernel_priority(typename api_params_type::handle_type, const typename api_params_type::priority_type) noexcept(false) FORCE_INLINE;
264  static typename api_params_type::priority_type __fastcall get_kernel_priority(typename api_params_type::handle_type) noexcept(false) FORCE_INLINE;
265  static void __fastcall set_kernel_affinity(typename api_params_type::handle_type const, typename api_params_type::processor_mask_type const) noexcept(false) FORCE_INLINE;
266  static typename api_params_type::processor_mask_type __fastcall get_kernel_affinity(typename api_params_type::handle_type const) noexcept(false) FORCE_INLINE;
267  static typename api_params_type::pid_type __fastcall get_current_process_id() noexcept(true) FORCE_INLINE;
268  static typename api_params_type::tid_type __fastcall get_current_thread_id() noexcept(true) FORCE_INLINE;
269  static typename api_params_type::handle_type __fastcall get_current_thread() noexcept(true) FORCE_INLINE;
270  static typename api_params_type::username_type __fastcall get_current_username() noexcept(true) FORCE_INLINE;
271  static void __fastcall set_cancelstate(typename api_params_type::thread_cancel_state state) noexcept(false) FORCE_INLINE;
272  /// Sort-of threading, as it suspends the current thread of execution.
273  /**
274  \param period The period to sleep in ms. A value of zero should cause the thread to yield, so that it is no longer in a running state. (The rest of its time-slice is re-scheduled to run at some later period.)
275  */
276  static void __fastcall sleep(const typename api_params_type::suspend_period_ms period) noexcept(false) FORCE_INLINE;
277  static typename api_params_type::states __fastcall wait_thread_exit(api_params_type &, const typename lock_traits::timeout_type period) noexcept(false) FORCE_INLINE;
278  /// Attempt to demangle a potentially mangled C++ identifier.
279  static void __fastcall demangle_name(char const * const mangled_name, demangled_name_t &demangled_name) noexcept(true);
280  static demangled_name_t __fastcall demangle_name(std::type_info const &mangled_type) noexcept(true);
281  /// Return a string containing the current backtrace, with demangled names, separated by "\n".
282  /**
283  \todo Reimplement with: <a href="https://www.boost.org/doc/libs/1_73_0/doc/html/boost/stacktrace/basic_stacktrace.html"/>
284  */
285  static demangled_names_t __fastcall gen_backtrace() noexcept(true);
286  /// Dump a backtrace to std::cerr if SIGABRT is raised, once this function is called.
287  static void __fastcall set_backtrace_on_signal() noexcept(true);
288  /// Dump a backtrace to std::cerr if std::terminate is called, once this function is called.
289  static void __fastcall set_backtrace_on_terminate() noexcept(true);
290  static void __fastcall set_name(typename api_params_type::handle_type, char const *name) noexcept(false);
291 
292  struct cancellability {
293  cancellability() noexcept(false) FORCE_INLINE {
294  set_cancelstate(api_params_type::cancel_enable);
295  }
296  ~cancellability() noexcept(false) FORCE_INLINE {
297  set_cancelstate(api_params_type::cancel_disable);
298  }
299  };
300  };
301 
302 } } }
303 
305 
306 #include "hp_timer.hpp"
307 
308 #ifdef WIN32
309 # include "../experimental/NT-based/NTSpecific/thread_api_traits.hpp"
310 # include "../experimental/NT-based/NTSpecific/NTLocking.hpp"
311 #elif defined(__unix__)
312 # include "../unix/thread_api_traits.hpp"
313 # include "../unix/posix_locking.hpp"
314 #endif
315 
316 #endif