jaulib v1.3.0
Jau Support Library (C++, Java, ..)
test_service_runner01.cpp
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#include <cassert>
25#include <cinttypes>
26#include <cstring>
27#include <memory>
28#include <thread>
29#include <pthread.h>
30
32
34#include <jau/latch.hpp>
35
36using namespace jau;
37using namespace jau::fractions_i64_literals;
38using namespace jau::int_literals;
39
41 public:
42 // install it once ..
44
45 private:
46 jau::sc_atomic_int ping_count = 0;
47
48 jau::latch serviceInitDone;
49 jau::latch serviceEndDone;
50 jau::latch serviceWorkDone;
51
52 void serviceCounterInit(jau::service_runner& sr0) noexcept {
53 (void)sr0;
54 serviceInitDone.count_down();
55 }
56
57 void serviceCounterEnd(jau::service_runner& sr) noexcept {
58 (void)sr;
59 serviceEndDone.count_down();
60 }
61
62 // immediately self stopping after start, testing service_runner::start()
63 void service01FastStopWork(jau::service_runner& sr) noexcept {
64 sr.set_shall_stop(); // trigger service_runner::start() issue: running == false and shall_stop == true before start queries while running != true
65
66 ping_count++;
67 serviceWorkDone.count_down();
68 }
69
70 // self stopping after work
71 void service10CounterWork(jau::service_runner& sr) noexcept {
72 ping_count++;
73 serviceWorkDone.count_down();
74 std::this_thread::sleep_for(std::chrono::milliseconds(10));
75 if( 0 == serviceWorkDone.value() ) {
76 sr.set_shall_stop();
77 }
78 }
79
80 public:
81
82 // immediately self stopping after start, testing service_runner::start()
84 fprintf(stderr, "\n\ntest01\n");
85
86 ping_count = 0;
87 serviceInitDone.set(1);
88 serviceEndDone.set(1);
89 serviceWorkDone.set(1);
90
91 jau::service_runner service("service_01", 100_ms,
92 jau::bind_member(this, &TestServiceRunner01::service01FastStopWork),
93 jau::bind_member(this, &TestServiceRunner01::serviceCounterInit),
94 jau::bind_member(this, &TestServiceRunner01::serviceCounterEnd));
95
96 REQUIRE( 0 == ping_count.load() );
97 REQUIRE( 1 == serviceInitDone.value());
98 REQUIRE( 1 == serviceWorkDone.value());
99 REQUIRE( 1 == serviceEndDone.value());
100
101 fprintf(stderr, "test01: start: %s\n", service.toString().c_str());
102 service.start();
103
104 REQUIRE_MSG("service10_init_complete", true == serviceInitDone.wait_for(100_ms) );
105 REQUIRE( true == serviceWorkDone.wait_for(2_s) );
106 REQUIRE_MSG("service10_end_complete", true == serviceEndDone.wait_for(100_ms) );
107 fprintf(stderr, "test01: latched: %zu\n", serviceWorkDone.value());
108 fprintf(stderr, "test01: latched: %s\n", service.toString().c_str());
109 REQUIRE( 1 == ping_count.load() );
110 REQUIRE( 0 == serviceInitDone.value());
111 REQUIRE( 0 == serviceWorkDone.value());
112 REQUIRE( 0 == serviceEndDone.value());
113
114 REQUIRE( true == service.stop() );
115 }
116
117 // 10'000x immediately self stopping after start - faster, testing service_runner::start()
119 fprintf(stderr, "\n\ntest02\n");
120
121 const int loops = 10000;
122 for(int i=0; i<loops; ++i) {
123 ping_count = 0;
124 serviceWorkDone.set(1);
125
126 jau::service_runner service("service_01", 100_ms,
127 jau::bind_member(this, &TestServiceRunner01::service01FastStopWork));
128
129 REQUIRE( 0 == ping_count.load() );
130 REQUIRE( 1 == serviceWorkDone.value());
131
132 // fprintf(stderr, "test02: start %d: %s\n", i, service.toString().c_str());
133 service.start();
134
135 REQUIRE( true == serviceWorkDone.wait_for(2_s) );
136 REQUIRE( 1 == ping_count.load() );
137 REQUIRE( 0 == serviceWorkDone.value());
138
139 REQUIRE( true == service.stop() );
140 }
141 }
142
143 // self stopping after work
145 fprintf(stderr, "\n\ntest10\n");
146
147 ping_count = 0;
148 serviceInitDone.set(1);
149 serviceEndDone.set(1);
150 serviceWorkDone.set(10);
151
152 jau::service_runner service("service_10", 100_ms,
153 jau::bind_member(this, &TestServiceRunner01::service10CounterWork),
154 jau::bind_member(this, &TestServiceRunner01::serviceCounterInit),
155 jau::bind_member(this, &TestServiceRunner01::serviceCounterEnd));
156
157 REQUIRE( 0 == ping_count.load() );
158 REQUIRE( 1 == serviceInitDone.value());
159 REQUIRE( 10 == serviceWorkDone.value());
160 REQUIRE( 1 == serviceEndDone.value());
161
162 fprintf(stderr, "test10: start: %s\n", service.toString().c_str());
163 service.start();
164
165 REQUIRE_MSG("service10_init_complete", true == serviceInitDone.wait_for(100_ms) );
166 REQUIRE_MSG("service10_work_complete", true == serviceWorkDone.wait_for(500_ms) );
167 REQUIRE_MSG("service10_end_complete", true == serviceEndDone.wait_for(100_ms) );
168 fprintf(stderr, "test10: latched: %zu\n", serviceWorkDone.value());
169 fprintf(stderr, "test10: latched: %s\n", service.toString().c_str());
170 REQUIRE( 10 == ping_count.load() );
171 REQUIRE( 0 == serviceInitDone.value());
172 REQUIRE( 0 == serviceWorkDone.value());
173 REQUIRE( 0 == serviceEndDone.value());
174
175 REQUIRE( true == service.stop() );
176 }
177
178
179};
180
184
#define REQUIRE_MSG(MSG,...)
Definition: catch2_ext.hpp:58
Inspired by std::latch of C++20.
Definition: latch.hpp:50
size_t value() const noexcept
Return the current atomic internal counter.
Definition: latch.hpp:94
void set(const size_t n) noexcept
Atomically set the internal counter by n.
Definition: latch.hpp:154
bool wait_for(const fraction_i64 &timeout_duration) const noexcept
Blocks the calling thread until the internal counter reaches 0 or the given timeout duration has expi...
Definition: latch.hpp:210
void count_down(const size_t n=1) noexcept
Atomically decrements the internal counter by n and notifies all blocked wait() threads if zero is re...
Definition: latch.hpp:108
Service runner, a reusable dedicated thread performing custom user services.
bool stop() noexcept
Stops this service, if running.
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.
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
CXX_ALWAYS_INLINE _Tp load() const noexcept
static int loops
METHOD_AS_TEST_CASE(TestServiceRunner01::test01_service01_fast_stop, "test01_service01_fast_stop")