29 #include <sys/socket.h>
41void service_runner::service_thread() {
43 const std::lock_guard<std::mutex> lock(mtx_lifecycle);
44 service_init_locked(*
this);
46 DBG_PRINT(
"%s::worker Started", name_.c_str());
51 DBG_PRINT(
"%s::worker::ThreadCleanup: serviceRunning %d -> 0", name_.c_str(), running.
load());
56 while( !shall_stop_ ) {
60 const std::lock_guard<std::mutex> lock(mtx_lifecycle);
62 service_end_locked(*
this);
65 thread_cleanup.set_released();
74 WORDY_PRINT(
"service_runner.sigaction: sig %d, info[code %d, errno %d, signo %d, pid %d, uid %d], pid-self %d (match %d)",
75 sig, info->si_code, info->si_errno, info->si_signo,
76 info->si_pid, info->si_uid,
80 if( !pidMatch || SIGALRM != sig ) {
90bool service_runner::install_sighandler() noexcept {
91 struct sigaction sa_setup;
92 ::bzero(&sa_setup,
sizeof(sa_setup));
94 ::sigemptyset(&(sa_setup.sa_mask));
95 sa_setup.sa_flags = SA_SIGINFO;
96 if( 0 != ::sigaction( SIGALRM, &sa_setup,
nullptr ) ) {
97 ERR_PRINT(
"service_runner::install_sighandler: Setting sighandler");
100 DBG_PRINT(
"service_runner::install_sighandler: OK");
105 struct sigaction sa_setup;
106 ::bzero(&sa_setup,
sizeof(sa_setup));
107 sa_setup.sa_handler = SIG_DFL;
108 ::sigemptyset(&(sa_setup.sa_mask));
109 sa_setup.sa_flags = 0;
110 if( 0 != ::sigaction( SIGALRM, &sa_setup,
nullptr ) ) {
111 ERR_PRINT(
"service_runner::remove_sighandler: Resetting sighandler");
114 DBG_PRINT(
"service_runner::remove_sighandler: OK");
122 Callback service_end_locked_) noexcept
123: name_( std::move(name__) ),
124 service_shutdown_timeout_( service_shutdown_timeout ),
125 service_work( std::move(service_work_) ),
126 service_init_locked( std::move(service_init_locked_) ),
127 service_end_locked( std::move(service_end_locked_) ),
128 shall_stop_(
true), running(
false),
135 DBG_PRINT(
"%s::dtor: Begin", name_.c_str());
137 DBG_PRINT(
"%s::dtor: End", name_.c_str());
142 const std::lock_guard<std::mutex> lock_stop(mtx_shall_stop_);
145 cv_shall_stop_.notify_all();
153 std::unique_lock<std::mutex> lock(mtx_lifecycle);
155 const std::lock_guard<std::mutex> lock_stop(mtx_shall_stop_);
158 cv_shall_stop_.notify_all();
165 std::thread t(&service_runner::service_thread,
this);
166 thread_id_ = t.native_handle();
171 while(
false == running &&
false == shall_stop_ ) {
180 std::unique_lock<std::mutex> lock(mtx_lifecycle);
181 const ::pthread_t tid_service = thread_id_;
182 const bool is_service = tid_service == ::pthread_self();
183 DBG_PRINT(
"%s::stop: service[running %d, shall_stop %d, is_service %d, tid %p)",
184 name_.c_str(), running.
load(), shall_stop_.
load(), is_service, (
void*)tid_service);
189 if( 0 != tid_service ) {
191 if( 0 != ( kerr = ::pthread_kill(tid_service, SIGALRM) ) ) {
192 ERR_PRINT(
"%s::stop: pthread_kill %p FAILED: %d", name_.c_str(), (
void*)tid_service, kerr);
198 while(
true == running && result ) {
199 std::cv_status s { std::cv_status::no_timeout };
205 if( std::cv_status::timeout == s &&
true == running ) {
206 ERR_PRINT(
"%s::stop: Timeout (force !running): %s", name_.c_str(),
toString().c_str());
217 DBG_PRINT(
"%s::stop: End: Result %d, %s", name_.c_str(), result,
toString().c_str());
223 std::unique_lock<std::mutex> lock(mtx_lifecycle);
225 const bool is_service = thread_id_ == ::pthread_self();
226 DBG_PRINT(
"%s::join: is_service %d, %s", name_.c_str(), is_service,
toString().c_str());
233 while(
true == running && result ) {
234 std::cv_status s { std::cv_status::no_timeout };
240 if( std::cv_status::timeout == s &&
true == running ) {
241 ERR_PRINT(
"%s::join: Timeout (force !running): %s", name_.c_str(),
toString().c_str());
252 DBG_PRINT(
"%s::join: End: Result %d, %s", name_.c_str(), result,
toString().c_str());
Call on release allows the user to pass a function to be called at destruction of this instance.
bool stop() noexcept
Stops this service, if running.
static bool remove_sighandler() noexcept
Remove the sighandler.
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(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.
bool is_running() const noexcept
Returns true if service is running.
bool join() noexcept
Blocks the current thread until service is stopped or returns immediately if not running or called fr...
std::string toString() const noexcept
Returns a string representation of this service.
~service_runner() noexcept
Service runner destructor.
void start() noexcept
Starts this service, if not running already.
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define WORDY_PRINT(...)
Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time...
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
std::string to_string(const alphabet &v) noexcept
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
constexpr const jau::fraction_i64 zero(0l, 1lu)
zero is 0/1
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
std::cv_status wait_until(std::condition_variable &cv, std::unique_lock< std::mutex > &lock, const fraction_timespec &absolute_time, const bool monotonic=true) noexcept
wait_until causes the current thread to block until the condition variable is notified,...
static void sigaction_handler(int sig, siginfo_t *info, void *ucontext) noexcept
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
CXX_ALWAYS_INLINE _Tp load() const noexcept