Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
manual_reset_event.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SYNCHRONIZATION_MANUAL_RESET_EVENT_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SYNCHRONIZATION_MANUAL_RESET_EVENT_HPP_
7
8#include <semaphore.h>
9
10#include <atomic>
11#include <cerrno>
12#include <mutex>
13#include <system_error>
14
15// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
16#include "arene/base/compiler_support/attributes.hpp"
17// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
18
19// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
20
21namespace arene {
22namespace base {
23
24// parasoft-begin-suppress AUTOSAR-A15_4_5-a-2 "Confusing std::__1::system_error and std::system_error"
25// parasoft-begin-suppress AUTOSAR-A17_1_1-a-2 "False positive: this function encapsulates the ues of errno"
26// parasoft-begin-suppress AUTOSAR-M19_3_1-a-2 "Errno used to report errors that cannot be checked in advance"
27/// @brief Throw @c std::system_error based on the value of @c errno
28/// @throw std::system_error
29ARENE_NORETURN inline void throw_errno_as_system_error() { throw std::system_error(errno, std::system_category()); }
30// parasoft-end-suppress AUTOSAR-M19_3_1-a-2
31// parasoft-end-suppress AUTOSAR-A17_1-1-a-2
32// parasoft-end-suppress AUTOSAR-A15_4_5-a-2
33
34/// @brief An event class that allows blocking waits from an arbitrary number of
35/// threads that are then woken when the event is signalled. Additional calls to
36/// @c wait while the event is signalled will return immediately. If there are
37/// no waiting threads, the event can be reset to an unsignalled state.
39 public:
40 /// @brief Initialize the event to an unsignalled state
41 constexpr manual_reset_event() noexcept = default;
42
43 /// @brief Destroy the event; destroy the semaphore if it is initialized.
45 if (initialized_) {
46 static_cast<void>(sem_destroy(&sem_));
47 }
48 }
49 // parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
50 /// @brief Not copyable
52 /// @brief Not copyable
54 /// @brief Not movable
56 /// @brief Not movable
58 // parasoft-end-suppress CERT_C-EXP37-a-3
59
60 /// @brief Signal the event and wake any blocked waiters.
61 /// @throw std::system_error on error.
62 void signal() {
63 if (!signalled_.exchange(true, std::memory_order_release)) {
64 ensure_semaphore_initialized();
65 post_semaphore();
66 }
67 }
68
69 /// @brief Reset the event to an unsignalled state.
70 /// @pre There must be no threads blocked in @c wait.
71 /// @throw std::system_error on error.
72 void reset() {
73 if (signalled_.load(std::memory_order_acquire)) {
74 signalled_.store(false, std::memory_order_release);
75 wait_on_semaphore();
76 }
77 }
78
79 /// @brief Wait for the event to be signalled. Return immediately if it is already
80 /// signalled.
81 /// @throw std::system_error on error.
82 void wait() const;
83
84 private:
85 /// @brief Wait for the semaphore;
86 /// @throw std::system_error on error.
87 void wait_on_semaphore() const {
88 if (sem_wait(&sem_) != 0) {
90 }
91 }
92
93 /// @brief Post the semaphore;
94 /// @throw std::system_error on error.
95 void post_semaphore() const {
96 if (sem_post(&sem_) != 0) {
98 }
99 }
100
101 /// @brief Ensure the semaphore is initialized. Can safely be called from multiple
102 /// threads concurrently. Does not return until the semaphore is initialized.
103 void ensure_semaphore_initialized() const {
104 std::call_once(init_flag_, [this]() {
105 if (sem_init(&sem_, 0, 0) != 0) {
106 throw_errno_as_system_error();
107 }
108 initialized_ = true;
109 });
110 }
111
112 /// @brief The signalling state of the event
113 std::atomic<bool> signalled_{false};
114 /// @brief Is the semaphore initialized?
115 mutable bool initialized_{false};
116 /// @brief Flag to ensure the semaphore is initialized exactly once
117 mutable std::once_flag init_flag_{};
118 /// @brief The semaphore
119 mutable sem_t sem_{};
120};
121
122/// @brief Wait for the event to be signalled. Return immediately if it is already
123/// signalled.
124/// @throw std::system_error if an error occurs in the underlying OS facilities
125inline void manual_reset_event::wait() const {
126 if (!signalled_.load(std::memory_order_acquire)) {
127 ensure_semaphore_initialized();
128 if (!signalled_.load(std::memory_order_acquire)) {
129 wait_on_semaphore();
130 post_semaphore();
131 }
132 }
133}
134
135} // namespace base
136} // namespace arene
137
138#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SYNCHRONIZATION_MANUAL_RESET_EVENT_HPP_
An event class that allows blocking waits from an arbitrary number of threads that are then woken whe...
Definition manual_reset_event.hpp:38
manual_reset_event(manual_reset_event &&)=delete
Not movable.
void signal()
Signal the event and wake any blocked waiters.
Definition manual_reset_event.hpp:62
constexpr manual_reset_event() noexcept=default
Initialize the event to an unsignalled state.
auto operator=(manual_reset_event const &) -> manual_reset_event &=delete
Not copyable.
void wait() const
Wait for the event to be signalled. Return immediately if it is already signalled.
Definition manual_reset_event.hpp:125
manual_reset_event(manual_reset_event const &)=delete
Not copyable.
auto operator=(manual_reset_event &&) -> manual_reset_event &=delete
Not movable.
~manual_reset_event()
Destroy the event; destroy the semaphore if it is initialized.
Definition manual_reset_event.hpp:44
void reset()
Reset the event to an unsignalled state.
Definition manual_reset_event.hpp:72
Definition array_exceptions_disabled.cpp:11
ARENE_NORETURN void throw_errno_as_system_error()
Throw std::system_error based on the value of errno.
Definition manual_reset_event.hpp:29
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10