jaulib v1.3.0
Jau Support Library (C++, Java, ..)
service_runner.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_SERVICE_RUNNER_HPP_
26#define JAU_SERVICE_RUNNER_HPP_
27
28#include <cstring>
29#include <string>
30#include <cstdint>
31#include <limits>
32#include <atomic>
33#include <memory>
34#include <mutex>
35#include <condition_variable>
36#include <thread>
37#include <algorithm>
38
39#include <jau/cpp_lang_util.hpp>
41#include <jau/fraction_type.hpp>
42#include <jau/functional.hpp>
43
44extern "C" {
45 #include <unistd.h>
46 #include <pthread.h>
47}
48
49namespace jau {
50
51 /** \addtogroup Concurrency
52 *
53 * @{
54 */
55
56 /**
57 * Service runner, a reusable dedicated thread performing custom user services.
58 */
60 public:
63
64 static const ::pid_t pid_self;
65
66 private:
67 std::string name_;
68
69 /**
70 * Maximum duration in fractions of seconds to wait for service to stop at stop() and join(), where fractions_i64::zero waits infinitely
71 */
72 fraction_i64 service_shutdown_timeout_;
73
74 Callback service_work;
75 Callback service_init_locked;
76 Callback service_end_locked;
77
78 std::mutex mtx_shall_stop_;
79 std::condition_variable cv_shall_stop_;
80 jau::sc_atomic_bool shall_stop_;
81 jau::sc_atomic_bool running;
82 ::pthread_t thread_id_;
83
84 std::mutex mtx_lifecycle;
85 std::condition_variable cv_init;
86
87 void service_thread();
88
89 static bool install_sighandler() noexcept;
90
91 public:
92 /**
93 * Remove the sighandler
94 */
95 static bool remove_sighandler() noexcept;
96
97 /**
98 * Install the singleton SIGALRM sighandler instance.
99 * - First call will install the sighandler
100 * - Should be called at least once within the application using jau::service_runner
101 */
102 static bool singleton_sighandler() noexcept {
103 /**
104 * Thread safe starting with C++11 6.7:
105 *
106 * If control enters the declaration concurrently while the variable is being initialized,
107 * the concurrent execution shall wait for completion of the initialization.
108 *
109 * (Magic Statics)
110 *
111 * Avoiding non-working double checked locking.
112 */
113 static bool r = install_sighandler();
114 return r;
115 }
116
117 /**
118 * Service runner constructor.
119 *
120 * start() shall be issued to kick off this service.
121 *
122 * @param name service name
123 * @param service_shutdown_timeout maximum duration in fractions of seconds to wait for service to stop at stop() and join(), where fractions_i64::zero waits infinitely
124 * @param service_work service working function
125 * @param service_init_locked optional service init function, lifecycle mutex is locked
126 * @param service_end_locked optional service end function, lifecycle mutex is locked
127 */
128 service_runner(std::string name,
130 Callback service_work,
131 Callback service_init_locked = Callback(),
132 Callback service_end_locked = Callback()) noexcept;
133
134 /**
135 * Service runner destructor.
136 *
137 * Issues stop()
138 */
139 ~service_runner() noexcept;
140
141 /**
142 * Return the given name of this service
143 */
144 const std::string& name() const noexcept { return name_; }
145
146 /**
147 * Returns maximum duration in fractions of seconds to wait for service to stop at stop() and join(), where fractions_i64::zero waits infinitely
148 * @see stop()
149 * @see join()
150 */
151 fraction_i64 service_shutdown_timeout() const noexcept { return service_shutdown_timeout_; }
152
153 /**
154 * Return the thread-id of this service service thread, zero if not running.
155 */
156 pthread_t thread_id() const noexcept { return thread_id_; }
157
158 /**
159 * Returns true if service is running
160 *
161 * @see start()
162 * @see stop()
163 * @see join()
164 */
165 bool is_running() const noexcept { return running; }
166
167 /**
168 * Returns true if service shall stop.
169 *
170 * This flag can be used by the service_work Callback to determine whether to skip lengthly tasks,
171 * or even to skip stopping this service (again).
172 *
173 * @see is_running()
174 * @see set_shall_stop()
175 * @see mtx_shall_stop()
176 * @see cv_shall_stop()
177 * @see start()
178 * @see stop()
179 * @see join()
180 */
181 bool shall_stop() const noexcept { return shall_stop_; }
182
183 /**
184 * Helper function to easy FunctionDef usage w/o creating a lambda alike capture
185 * with same semantics as shall_stop().
186 *
187 * The const qualifier has also been lifted, since free function pointer declarations can't match it.
188 *
189 * @param dummy a dummy argument to help FunctionDef template parameter pack, not used
190 * @see shall_stop()
191 */
192 bool shall_stop2(int dummy) /* const */ noexcept { (void)dummy; return shall_stop_; }
193
194 /**
195 * Marks the service thread to stop in due process by flagging `shall stop` to `true`.
196 * @see is_running()
197 * @see shall_stop()
198 * @see mtx_shall_stop()
199 * @see cv_shall_stop()
200 * @see start()
201 * @see stop()
202 * @see join()
203 */
204 void set_shall_stop() noexcept;
205
206 /** mtx_shall_stop() and cv_shall_stop() allows caller to be notified when shall_stop() changes, i.e. start(), set_shall_stop() or stop() is called. */
207 std::mutex& mtx_shall_stop() noexcept { return mtx_shall_stop_; }
208
209 /** mtx_shall_stop() and cv_shall_stop() allows caller to be notified when shall_stop() changes, i.e. start(), set_shall_stop() or stop() is called. */
210 std::condition_variable& cv_shall_stop() noexcept { return cv_shall_stop_; }
211
212 /**
213 * Starts this service, if not running already.
214 *
215 * Methods blocks the current thread until service is started.
216 *
217 * @see is_running()
218 * @see shall_stop()
219 * @see set_shall_stop()
220 * @see mtx_shall_stop()
221 * @see cv_shall_stop()
222 * @see stop()
223 * @see join()
224 * @see service_shutdown_timeout()
225 */
226 void start() noexcept;
227
228 /**
229 * Stops this service, if running.
230 *
231 * If called from the service thread, method just issues set_shall_stop() without blocking,
232 * otherwise methods blocks the current thread until service is stopped.
233 *
234 * Maximum blocked wait period is optionally limited by service_shutdown_timeout().
235 *
236 * Method attempts to stop the service thread
237 * - by flagging `shall stop` via set_shall_stop()
238 * - if not called from the service thread itself:
239 * - sending `SIGALRM` to the service thread
240 * - waiting until service thread has stopped or timeout occurred
241 *
242 * Implementation requires a `SIGALRM` handler to be install,
243 * e.g. using singleton_sighandler().
244 *
245 * @returns true if thread has been stopped or false if timeout has been hit
246 *
247 * @see is_running()
248 * @see shall_stop()
249 * @see set_shall_stop()
250 * @see mtx_shall_stop()
251 * @see cv_shall_stop()
252 * @see start()
253 * @see join()
254 * @see service_shutdown_timeout()
255 * @see singleton_sighandler()
256 */
257 bool stop() noexcept;
258
259 /**
260 * Blocks the current thread until service is stopped
261 * or returns immediately if not running or called from the service thread.
262 *
263 * Maximum blocked wait period is optionally limited by service_shutdown_timeout().
264 *
265 * @returns true if thread has been stopped or false if timeout has been hit
266 * @see is_running()
267 * @see shall_stop()
268 * @see set_shall_stop()
269 * @see mtx_shall_stop()
270 * @see cv_shall_stop()
271 * @see start()
272 * @see stop()
273 * @see service_shutdown_timeout()
274 */
275 bool join() noexcept;
276
277 /**
278 * Returns a string representation of this service
279 */
280 std::string toString() const noexcept;
281 };
282
283 /**@}*/
284} // namespace jau
285
286
287
288#endif /* JAU_SERVICE_RUNNER_HPP_ */
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Service runner, a reusable dedicated thread performing custom user services.
bool stop() noexcept
Stops this service, if running.
bool shall_stop2(int dummy) noexcept
Helper function to easy FunctionDef usage w/o creating a lambda alike capture with same semantics as ...
const std::string & name() const noexcept
Return the given name of this service.
function< void(service_runner_ref)> Callback
static bool remove_sighandler() noexcept
Remove the sighandler.
std::mutex & mtx_shall_stop() noexcept
mtx_shall_stop() and cv_shall_stop() allows caller to be notified when shall_stop() changes,...
fraction_i64 service_shutdown_timeout() const noexcept
Returns maximum duration in fractions of seconds to wait for service to stop at stop() and join(),...
static const ::pid_t pid_self
void set_shall_stop() noexcept
Marks the service thread to stop in due process by flagging shall stop to true.
service_runner & service_runner_ref
service_runner(std::string name, fraction_i64 service_shutdown_timeout, Callback service_work, Callback service_init_locked=Callback(), Callback service_end_locked=Callback()) noexcept
Service runner constructor.
std::condition_variable & cv_shall_stop() noexcept
mtx_shall_stop() and cv_shall_stop() allows caller to be notified when shall_stop() changes,...
bool is_running() const noexcept
Returns true if service is running.
pthread_t thread_id() const noexcept
Return the thread-id of this service service thread, zero if not running.
bool join() noexcept
Blocks the current thread until service is stopped or returns immediately if not running or called fr...
bool shall_stop() const noexcept
Returns true if service shall stop.
static bool singleton_sighandler() noexcept
Install the singleton SIGALRM sighandler instance.
std::string toString() const noexcept
Returns a string representation of this service.
void start() noexcept
Starts this service, if not running already.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
STL namespace.