Skip to content

Commit 03fa2c9

Browse files
authored
Merge pull request #74 from basiliscos/v0.37-dev
V0.37 dev
2 parents 1c92abb + c9bf499 commit 03fa2c9

File tree

10 files changed

+57
-21
lines changed

10 files changed

+57
-21
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
cmake_minimum_required(VERSION 3.15)
1+
cmake_minimum_required(VERSION 3.17)
22

33
cmake_policy(SET CMP0074 NEW)
44

5-
set(ROTOR_VERSION "0.36")
5+
set(ROTOR_VERSION "0.37")
66
project (rotor LANGUAGES CXX VERSION ${ROTOR_VERSION})
77
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
88
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ project.
6767

6868
## Changelog
6969

70+
### 0.37 (14-Dec-2025)
71+
- [feature, asio, thread, ev] allow poll-duration to be set to zero save CPU cycles/battery
72+
- [cmake, breaking] increase cmake version requirement `3.15` -> `3.17`
73+
- [cmake] generate file for clangd langserv (thanks for @rymdbar)
74+
- [cosmetic] removed trailing spaces (thanks for @rymdbar)
75+
- [cosmetic] fixed identation to make sources more vim-folding friendly (thanks for @rymdbar)
76+
- [cosmetic] configure linters to project style (thanks for @rymdbar)
77+
7078
### 0.36 (14-Oct-2025)
7179
- [feature] add `route()` and `redirect()` high-level actor methods, which
7280
provide convenient API over `make_routed_message()` introduced in `v0.32`

docs/Changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
[reliable]: https://en.wikipedia.org/wiki/Reliability_(computer_networking) "reliable"
55
[request-response]: https://en.wikipedia.org/wiki/Request%E2%80%93response
66

7+
### 0.37 (14-Dec-2025)
8+
- [feature, asio, thread, ev] allow poll-duration to be set to zero save CPU cycles/battery
9+
- [cmake, breaking] increase cmake version requirement `3.15` -> `3.17`
10+
- [cmake] generate file for clangd langserv (thanks for @rymdbar)
11+
- [cosmetic] removed trailing spaces (thanks for @rymdbar)
12+
- [cosmetic] fixed identation to make sources more vim-folding friendly (thanks for @rymdbar)
13+
- [cosmetic] configure linters to project style (thanks for @rymdbar)
14+
715
### 0.36 (14-Oct-2025)
816
- [feature] add `route()` and `redirect()` high-level actor methods, which
917
provide convenient API over `make_routed_message()` introduced in `v0.32`

examples/boost-asio/ping-pong-2-threads.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,17 @@ struct ponger_t : public r::actor_base_t {
117117
};
118118

119119
int main(int argc, char **argv) {
120-
120+
using boost::conversion::try_lexical_convert;
121121
asio::io_context io_ctx1;
122122
asio::io_context io_ctx2;
123123
try {
124124
std::uint32_t count = 10000;
125+
std::uint32_t poll_us = 100;
125126
if (argc > 1) {
126-
boost::conversion::try_lexical_convert(argv[1], count);
127+
try_lexical_convert(argv[1], count);
128+
if (argc > 2) {
129+
try_lexical_convert(argv[2], poll_us);
130+
}
127131
}
128132

129133
auto sys_ctx1 = ra::system_context_asio_t::ptr_t{new ra::system_context_asio_t(io_ctx1)};
@@ -134,11 +138,13 @@ int main(int argc, char **argv) {
134138
auto sup1 = sys_ctx1->create_supervisor<ra::supervisor_asio_t>()
135139
.strand(strand1)
136140
.timeout(timeout)
141+
.poll_duration(r::pt::milliseconds{poll_us})
137142
.guard_context(true)
138143
.finish();
139144
auto sup2 = sys_ctx2->create_supervisor<ra::supervisor_asio_t>()
140145
.strand(strand2)
141146
.timeout(timeout)
147+
.poll_duration(r::pt::milliseconds{poll_us})
142148
.guard_context(true)
143149
.finish();
144150

examples/thread/ping-pong-thread.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,29 @@ struct ponger_t : public r::actor_base_t {
113113

114114
int main(int argc, char **argv) {
115115
try {
116+
using boost::conversion::try_lexical_convert;
116117
std::uint32_t count = 10000;
118+
std::uint32_t poll_us = 100;
117119
if (argc > 1) {
118-
boost::conversion::try_lexical_convert(argv[1], count);
120+
try_lexical_convert(argv[1], count);
121+
if (argc > 2) {
122+
try_lexical_convert(argv[2], poll_us);
123+
}
119124
}
120125

121126
rth::system_context_thread_t ctx_ping;
122127
rth::system_context_thread_t ctx_pong;
123128
auto timeout = boost::posix_time::milliseconds{100};
124-
auto sup_ping =
125-
ctx_ping.create_supervisor<rth::supervisor_thread_t>().timeout(timeout).create_registry().finish();
129+
auto sup_ping = ctx_ping.create_supervisor<rth::supervisor_thread_t>()
130+
.poll_duration(r::pt::milliseconds{poll_us})
131+
.timeout(timeout)
132+
.create_registry()
133+
.finish();
126134
auto pinger = sup_ping->create_actor<pinger_t>().autoshutdown_supervisor().timeout(timeout).finish();
127135
pinger->set_pings(count);
128136

129137
auto sup_pong = ctx_pong.create_supervisor<rth::supervisor_thread_t>()
138+
.poll_duration(r::pt::milliseconds{poll_us})
130139
.timeout(timeout)
131140
.registry_address(sup_ping->get_registry_address())
132141
.finish();

include/rotor/supervisor_config.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ struct supervisor_config_t : actor_config_t {
4949
* \brief How much time it will spend in polling inbound queue before switching into
5050
* sleep mode (i.e. waiting external messages).
5151
*
52-
* This value might affect I/O latency on event-loops, so set it to zero to
53-
* minimizer I/O latency on event-loops by the rising cross-thread rotor messaging
54-
* latency.
55-
*
52+
* Under the hood this value instructs how much time rotor spends in spin-locks
53+
* waiting messages (and burning CPU). If there is no large cross-thread
54+
* messages traffic (i.e. < 100k messages per second) or there is need to
55+
* save battery, set this value to zero for root supervisors.
5656
*/
5757
pt::time_duration poll_duration = pt::millisec{1};
5858

src/rotor/asio/supervisor_asio.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ void supervisor_asio_t::do_process() noexcept {
118118
enqueued_messages = supervisor_t::do_process();
119119
}
120120

121-
if (enqueued_messages) {
122-
auto deadline = clock_t::now() + time_units_t{poll_duration.total_microseconds()};
121+
auto total_microsecs = poll_duration.total_microseconds();
122+
if (total_microsecs && enqueued_messages) {
123+
auto deadline = clock_t::now() + time_units_t{total_microsecs};
123124
while (clock_t::now() < deadline && leader_queue.empty()) {
124125
while (inbound.pop(ptr)) {
125126
leader_queue.emplace_back(ptr, false);

src/rotor/ev/supervisor_ev.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
2+
// Copyright (c) 2019-2025 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
33
//
44
// Distributed under the MIT Software License
55
//
@@ -124,7 +124,7 @@ void supervisor_ev_t::on_async() noexcept {
124124
enqueued_messages = do_process();
125125
}
126126

127-
if (enqueued_messages) {
127+
if (poll_duration > 0 && enqueued_messages) {
128128
ev_now_update(loop);
129129
auto now = ev_now(loop);
130130
auto deadline = now + poll_duration;

src/rotor/thread/system_context_thread.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2021 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
2+
// Copyright (c) 2019-2025 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
33
//
44
// Distributed under the MIT Software License
55
//
@@ -52,19 +52,23 @@ void system_context_thread_t::run() noexcept {
5252
return false;
5353
};
5454

55-
auto delta = time_units_t{poll_duration.total_microseconds()};
55+
auto total_us = poll_duration.total_microseconds();
56+
auto delta = time_units_t{total_us};
5657
while (condition()) {
5758
root_sup.do_process();
5859
if (condition()) {
59-
using namespace std::chrono_literals;
6060
auto dealine = clock_t::now() + delta;
6161
if (!timer_nodes.empty()) {
6262
dealine = std::min(dealine, timer_nodes.front().deadline);
6363
}
64-
// fast stage, indirect spin-lock, cpu consuming
65-
while ((clock_t::now() < dealine) && !process()) {
64+
if (total_us) {
65+
// fast stage, indirect spin-lock, cpu consuming
66+
while ((clock_t::now() < dealine) && !process());
67+
} else {
68+
while (!process());
6669
}
6770
if (queue.empty()) {
71+
using namespace std::chrono_literals;
6872
std::unique_lock<std::mutex> lock(mutex);
6973
auto predicate = [&]() { return !inbound.empty(); };
7074
// wait notification, do not consume CPU

0 commit comments

Comments
 (0)