Lumiera  0.pre.03
»edit your freedom«
thread.cpp
1 /*
2  THREAD.hpp - thin convenience wrapper for starting threads
3 
4  Copyright (C) Lumiera.org
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program 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
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
32 #include "lib/thread.hpp"
33 #include "lib/format-string.hpp"
34 #include "lib/symbol.hpp"
35 #include "lib/util.hpp"
36 
37 #include <chrono>
38 #include <atomic>
39 #include <pthread.h>
40 
41 using util::_Fmt;
42 using lib::Literal;
43 using std::atomic_uint;
44 using std::chrono::steady_clock;
45 using std::chrono_literals::operator ""ms;
46 
47 
48 
49 namespace lib {
50 namespace thread{
51 
52  namespace {
53  const auto SHUTDOWN_GRACE_PERIOD = 20ms;
54 
55  string
56  lifecycleMsg (Literal phase, string threadID)
57  {
58  return _Fmt{"Thread '%s' %s"} % threadID % phase;
59  }
60  }
61 
62 
64  string
66  {
67  static atomic_uint globalCnt{1};
68  return _Fmt{"%s.%03i"} % rawID % globalCnt.fetch_add (+1, std::memory_order_acq_rel);
69  }
70 
71 
73  bool
75  {
76  return threadImpl_.get_id() == std::this_thread::get_id();
77  }
78 
79 
80  void
81  ThreadWrapper::markThreadStart()
82  {
83  TRACE (thread, "%s", lifecycleMsg ("start...", threadID_).c_str());
84  setThreadName();
85  }
86 
87 
88  void
89  ThreadWrapper::markThreadEnd()
90  {
91  TRACE (thread, "%s", lifecycleMsg ("terminates.", threadID_).c_str());
92  }
93 
94 
95  void
96  ThreadWrapper::setThreadName()
97  {
98  pthread_t nativeHandle = threadImpl_.native_handle();
99 
100  // API limitation: max 15 characters + \0
101  pthread_setname_np(nativeHandle, threadID_.substr(0, 15).c_str());
102  }
103 
104 
105  void
106  ThreadWrapper::waitGracePeriod() noexcept
107  {
108  try {
109  auto start = steady_clock::now();
110  while (threadImpl_.joinable()
111  and steady_clock::now () - start < SHUTDOWN_GRACE_PERIOD
112  )
113  std::this_thread::yield();
114  }
115  ERROR_LOG_AND_IGNORE (thread, lifecycleMsg("shutdown wait", threadID_).c_str());
116 
117  if (threadImpl_.joinable())
118  ALERT (thread, "Thread '%s' failed to terminate after grace period. Abort.", threadID_.c_str());
119  // invocation of std::thread dtor will presumably call std::terminate...
120  }
121 
122 
123 
124 }}// namespace lib::thread
bool invokedWithinThread() const
detect if the currently executing code runs within this thread
Definition: thread.cpp:74
#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:275
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
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:65