20 #include <sys/epoll.h>
21 #include <sys/eventfd.h>
23 #include <sys/utsname.h>
26 #include <type_traits>
42 static int clock_gettime(clockid_t clock_id,
struct timespec* ts) noexcept
44 return ::clock_gettime(clock_id, ts);
47 static int nanosleep(
struct timespec
const* request,
48 struct timespec* remaining) noexcept
50 return ::nanosleep(request, remaining);
53 static FILE* fopen(
char const* path,
char const* mode) noexcept
55 return std::fopen(path, mode);
58 static int fgetc(FILE* file) noexcept
60 return std::fgetc(file);
63 static int fclose(FILE* file) noexcept
65 return std::fclose(file);
68 static int uname(
struct utsname* kernel) noexcept
70 return ::uname(kernel);
73 static pthread_t pthread_self() noexcept
75 return ::pthread_self();
78 static int pthread_setschedparam(pthread_t thread,
80 struct sched_param
const* param) noexcept
82 return ::pthread_setschedparam(thread,
policy, param);
85 static int pthread_setaffinity_np(pthread_t thread,
86 std::size_t cpusetsize,
87 cpu_set_t
const* cpuset) noexcept
89 return ::pthread_setaffinity_np(thread, cpusetsize, cpuset);
92 static int mlockall(
int flags) noexcept
94 return ::mlockall(flags);
97 static void perror(
char const* message) noexcept
102 static int eventfd(
unsigned int initval,
int flags) noexcept
104 return ::eventfd(initval, flags);
107 static int epoll_create1(
int flags) noexcept
109 return ::epoll_create1(flags);
112 static int epoll_ctl(
int epfd,
115 struct epoll_event* event) noexcept
117 return ::epoll_ctl(epfd, op, fd, event);
120 static int epoll_wait(
int epfd,
121 struct epoll_event* events,
123 int timeout) noexcept
125 return ::epoll_wait(epfd, events, maxevents, timeout);
128 static ssize_t read(
int fd,
void* buffer, std::size_t count) noexcept
130 return ::read(fd, buffer, count);
133 static ssize_t write(
int fd,
void const* buffer, std::size_t count) noexcept
135 return ::write(fd, buffer, count);
138 static int close(
int fd) noexcept
148 using duration = std::chrono::nanoseconds;
149 using period = duration::period;
150 using rep = duration::rep;
151 using time_point = std::chrono::time_point<AccurateClock>;
153 static constexpr
bool is_steady =
true;
155 static time_point now() noexcept
158 linux_syscalls::clock_gettime(CLOCK_MONOTONIC, &ts);
159 auto duration_since_epoch = std::chrono::seconds(ts.tv_sec) +
160 std::chrono::nanoseconds(ts.tv_nsec);
161 return time_point(duration(duration_since_epoch));
170 template<
typename Clock = std::chrono::steady_clock,
171 typename Duration =
typename Clock::duration>
174 using ClockType = Clock;
175 using DurationType = Duration;
178 start_time_ = Clock::now();
182 Duration elapsed()
const
187 auto now = Clock::now();
188 auto interval = now - start_time_;
189 return std::chrono::duration_cast<Duration>(interval);
192 template<
typename ToDuration = Duration>
193 Duration elapsed(ToDuration since)
const
195 auto now = Clock::now();
196 if constexpr (std::is_same<ToDuration, Duration>::value) {
197 return std::chrono::duration_cast<Duration>(now - since);
199 return std::chrono::duration_cast<ToDuration>(now - since);
203 template<
typename ToDuration>
204 ToDuration elapsed()
const
206 return std::chrono::duration_cast<ToDuration>(elapsed());
215 start_time_ = Clock::now();
223 typename Clock::time_point start_time_;
224 bool started_{
false };
227 template<
typename Clock = std::chrono::steady_clock,
228 typename Duration =
typename Clock::duration>
229 struct IntervalTimer :
public Timer<Clock, Duration>
237 auto now = Clock::now();
238 auto interval = now - this->start_time_;
239 this->start_time_ = now;
240 return std::chrono::duration_cast<Duration>(interval);
248 template<
typename Clock = AccurateClock,
249 typename Duration =
typename Clock::duration,
250 typename Sys = linux_syscalls>
251 struct PeriodicSleepTimer :
public Timer<Clock, Duration>
253 PeriodicSleepTimer(Duration period = Duration(1))
259 Timer<Clock, Duration>::start();
264 auto remaining = period_ - Timer<Clock, Duration>::elapsed();
267 std::chrono::duration_cast<std::chrono::seconds>(remaining).count();
269 std::chrono::duration_cast<std::chrono::nanoseconds>(remaining)
272 struct timespec remaining_ts;
273 while (Sys::nanosleep(&ts, &remaining_ts) != 0 && errno == EINTR) {
276 Timer<Clock, Duration>::reset();
279 Duration get_period()
const
289 template<
typename Sys>
290 struct basic_realtime_configurator
292 basic_realtime_configurator() =
default;
293 basic_realtime_configurator(
int priority, std::array<int, 4> affinity)
294 : PROCESS_PRIORITY(priority)
295 , CPU_AFFINITY(affinity)
299 static bool running_realtime_kernel()
301 if (
auto* realtime = Sys::fopen(
"/sys/kernel/realtime",
"r")) {
302 int value = Sys::fgetc(realtime);
303 Sys::fclose(realtime);
307 struct utsname kernel
309 if (Sys::uname(&kernel) != 0) {
312 return std::strstr(kernel.release,
"-rt") !=
nullptr ||
313 std::strstr(kernel.version,
"PREEMPT_RT") !=
nullptr;
316 void config_realtime_thread()
318 if (!running_realtime_kernel()) {
322 struct sched_param param;
323 param.sched_priority = PROCESS_PRIORITY - 3;
324 const auto sched_error =
325 Sys::pthread_setschedparam(Sys::pthread_self(), SCHED_RR, ¶m);
326 if (sched_error != 0 && sched_error != EPERM) {
327 Sys::perror(
"pthread_setschedparam");
332 for (
auto cpu : CPU_AFFINITY) {
333 CPU_SET(cpu, &cpuset);
336 if (Sys::pthread_setaffinity_np(
337 Sys::pthread_self(),
sizeof(cpu_set_t), &cpuset) != 0) {
338 Sys::perror(
"sched_setaffinity");
341 if (Sys::mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
342 Sys::perror(
"mlockall failed");
346 template<
typename Fn>
347 std::thread real_time_thread(Fn fn)
349 return std::thread([
this, fn] {
350 this->config_realtime_thread();
355 std::thread make_real_time(std::thread&& t)
357 config_realtime_thread();
362 int PROCESS_PRIORITY{ 98 };
363 std::array<int, 4> CPU_AFFINITY{ 0, 1, 2, 3 };
373 struct host_thread_policy
375 void configure_current_thread() {}
378 template<
typename TickPeriod = std::chrono::milliseconds>
386 template<
typename Sys = linux_syscalls>
387 struct basic_host_realtime_policy : basic_realtime_configurator<Sys>
389 using basic_realtime_configurator<Sys>::basic_realtime_configurator;
391 void configure_current_thread()
393 this->config_realtime_thread();
399 template<
typename ThreadPolicy,
typename Sys,
typename... Tasks>
400 class basic_thread_executor
403 explicit basic_thread_executor(Tasks&...
tasks)
406 event_fd_ = Sys::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
407 epoll_fd_ = Sys::epoll_create1(EPOLL_CLOEXEC);
408 if (event_fd_ >= 0 && epoll_fd_ >= 0) {
410 event.events = EPOLLIN;
411 event.data.fd = event_fd_;
413 Sys::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, event_fd_, &event));
417 basic_thread_executor(basic_thread_executor
const&) =
delete;
418 basic_thread_executor& operator=(basic_thread_executor
const&) =
delete;
420 ~basic_thread_executor()
423 if (event_fd_ >= 0) {
424 Sys::close(event_fd_);
426 if (epoll_fd_ >= 0) {
427 Sys::close(epoll_fd_);
433 if (worker_.joinable()) {
436 stop_requested_.store(
false);
437 worker_ = std::thread([
this] {
438 policy_.configure_current_thread();
439 while (!stop_requested_.load()) {
442 if (ready_.run_ready() == 0U) {
451 stop_requested_.store(
true);
453 if (worker_.joinable()) {
465 std::uint64_t value = 1U;
466 const auto written = Sys::write(event_fd_, &value,
sizeof(value));
467 static_cast<void>(written);
477 if (epoll_fd_ < 0 || event_fd_ < 0) {
484 const int ready = Sys::epoll_wait(epoll_fd_, &event, 1, 1);
485 if (ready > 0 && event.data.fd == event_fd_) {
486 std::uint64_t value{};
487 while (Sys::read(event_fd_, &value,
sizeof(value)) > 0) {}
491 [[nodiscard]]
bool step()
493 return ready_.step();
496 std::size_t run_ready()
498 return ready_.run_ready();
503 auto resumed = ready_.tick(elapsed_ticks);
512 return tick(elapsed_ticks.
count());
520 template<auto Entry, std::
size_t Instance = 0U>
523 auto result = ready_.template start<Entry, Instance>();
530 template<
auto Entry,
typename... Args>
533 auto result = ready_.template spawn<Entry>(std::forward<Args>(args)...);
540 [[nodiscard]] runtime::task_spawner<basic_thread_executor>
spawner()
542 return runtime::task_spawner<basic_thread_executor>{ *
this };
545 template<auto Entry, std::
size_t Instance = 0U>
548 return ready_.template task_status<Entry, Instance>();
551 template<auto Entry, std::
size_t Instance = 0U>
554 return ready_.template task_failure_reason<Entry, Instance>();
557 template<auto Entry, std::
size_t Instance = 0U>
558 [[nodiscard]]
bool cancel() noexcept
560 const bool cancelled = ready_.template cancel<Entry, Instance>();
567 void cancel_all() noexcept
574 ThreadPolicy policy_{};
576 std::thread worker_{};
577 std::atomic_bool stop_requested_{
true };
582 template<
typename... Tasks>
584 :
public basic_thread_executor<host_thread_policy, linux_syscalls, Tasks...>
587 basic_thread_executor<host_thread_policy, linux_syscalls, Tasks...>;
593 template<
typename... Tasks>
596 template<
typename... Tasks>
598 :
public basic_thread_executor<host_realtime_policy, linux_syscalls, Tasks...>
607 template<
typename... Tasks>
610 template<
typename... Tasks>
Helpers for converting measured durations into explicit HSM ticks.
Definition: chrono_ticks.h:137
Definition: executor.h:294
Target-independent executors for tsm runtimes.
tsm::sleep_ticks_awaitable sleep_for(tick_domain< TickPeriod > domain, Duration duration) noexcept
Definition: chrono_ticks.h:105
realtime_thread_executor(Tasks &...) -> realtime_thread_executor< Tasks... >
thread_executor(Tasks &...) -> thread_executor< Tasks... >
thread_executor< Tasks... > task_executor
Definition: linux.h:611
basic_realtime_configurator< linux_syscalls > RealtimeConfigurator
Definition: linux.h:366
basic_host_realtime_policy< linux_syscalls > host_realtime_policy
Definition: linux.h:397
task_spawner< Executor > spawner
Definition: executor.h:150
::tsm::runtime_policy< Topology, Storage, Scheduler, Overflow, Transport > policy
Definition: policy.h:119
task_failure_reason
Definition: coroutine.h:170
task_status
Definition: coroutine.h:160
spawn_result
Definition: coroutine.h:181
TSM_TICK_REP tick_rep
Definition: ticks.h:35
Definition: coroutine.h:1162
Strong value type for semantic scheduler ticks.
Definition: ticks.h:54
constexpr tick_rep count() const noexcept
Definition: ticks.h:73