Lumiera  0.pre.03
»edit your freedom«
thread.cpp
1 /*
2  THREAD.hpp - thin convenience wrapper for starting threads
3 
4  Copyright (C)
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
23 #include "lib/thread.hpp"
24 #include "lib/format-string.hpp"
25 #include "lib/symbol.hpp"
26 #include "lib/util.hpp"
27 
28 #include <chrono>
29 #include <atomic>
30 #include <pthread.h>
31 
32 using util::_Fmt;
33 using lib::Literal;
34 using std::atomic_uint;
35 using std::chrono::steady_clock;
36 using std::chrono_literals::operator ""ms;
37 
38 
39 
40 namespace lib {
41 namespace thread{
42 
43  namespace {
44  const auto SHUTDOWN_GRACE_PERIOD = 20ms;
45 
46  string
47  lifecycleMsg (Literal phase, string threadID)
48  {
49  return _Fmt{"Thread '%s' %s"} % threadID % phase;
50  }
51  }
52 
53 
55  string
57  {
58  static atomic_uint globalCnt{1};
59  return _Fmt{"%s.%03i"} % rawID % globalCnt.fetch_add (+1, std::memory_order_acq_rel);
60  }
61 
62 
64  bool
66  {
67  return threadImpl_.get_id() == std::this_thread::get_id();
68  }
69 
70 
71  void
72  ThreadWrapper::markThreadStart()
73  {
74  TRACE (thread, "%s", lifecycleMsg ("start...", threadID_).c_str());
75  setThreadName();
76  }
77 
78 
79  void
80  ThreadWrapper::markThreadEnd()
81  {
82  TRACE (thread, "%s", lifecycleMsg ("terminates.", threadID_).c_str());
83  }
84 
85 
86  void
87  ThreadWrapper::setThreadName()
88  {
89  pthread_t nativeHandle = threadImpl_.native_handle();
90 
91  // API limitation: max 15 characters + \0
92  pthread_setname_np(nativeHandle, threadID_.substr(0, 15).c_str());
93  }
94 
95 
96  void
97  ThreadWrapper::waitGracePeriod() noexcept
98  {
99  try {
100  auto start = steady_clock::now();
101  while (threadImpl_.joinable()
102  and steady_clock::now () - start < SHUTDOWN_GRACE_PERIOD
103  )
104  std::this_thread::yield();
105  }
106  ERROR_LOG_AND_IGNORE (thread, lifecycleMsg("shutdown wait", threadID_).c_str());
107 
108  if (threadImpl_.joinable())
109  ALERT (thread, "Thread '%s' failed to terminate after grace period. Abort.", threadID_.c_str());
110  // invocation of std::thread dtor will presumably call std::terminate...
111  }
112 
113 
114 
115 }}// namespace lib::thread
bool invokedWithinThread() const
detect if the currently executing code runs within this thread
Definition: thread.cpp:65
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:266
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Implementation namespace for support and library code.
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Convenience front-end to simplify and codify basic thread handling.
static string decorate_with_global_count(string const &)
Helper to create a suffix to the thread-ID with running count.
Definition: thread.cpp:56