xref: /openbmc/sdeventplus/src/sdeventplus/source/base.hpp (revision 43493b58f26b5ec90a14770ef63fae34130977d7)
1 #pragma once
2 
3 #include <cerrno>
4 #include <cstdint>
5 #include <cstdio>
6 #include <function2/function2.hpp>
7 #include <functional>
8 #include <memory>
9 #include <sdeventplus/event.hpp>
10 #include <sdeventplus/internal/utils.hpp>
11 #include <sdeventplus/types.hpp>
12 #include <stdplus/handle/copyable.hpp>
13 #include <systemd/sd-bus.h>
14 #include <type_traits>
15 #include <utility>
16 
17 namespace sdeventplus
18 {
19 namespace source
20 {
21 
22 /** @class Enabled
23  *  @brief Mapping of sdeventplus source enable values to the sd-event
24  *         equivalent
25  */
26 enum class Enabled
27 {
28     Off = SD_EVENT_OFF,
29     On = SD_EVENT_ON,
30     OneShot = SD_EVENT_ONESHOT,
31 };
32 
33 namespace detail
34 {
35 class BaseData;
36 } // namespace detail
37 
38 /** @class Base
39  *  @brief The base class for all sources implementing common source methods
40  *         Not instantiated directly by end users
41  */
42 class Base
43 {
44   public:
45     using Callback = fu2::unique_function<void(Base& source)>;
46 
47     Base(Base&& other) = default;
48     Base& operator=(Base&& other) = default;
49     Base(const Base& other) = default;
50     Base& operator=(const Base& other) = default;
51     virtual ~Base() = default;
52 
53     /** @brief Gets the underlying sd_event_source
54      *
55      *  @return The sd_event_source
56      */
57     sd_event_source* get() const;
58 
59     /** @brief Gets the associated Event object
60      *
61      *  @return The Event
62      */
63     const Event& get_event() const;
64 
65     /** @brief Gets the description of the source
66      *
67      *  @throws SdEventError for underlying sd_event errors
68      *  @return The c-string description or a nullptr if none exists
69      */
70     const char* get_description() const;
71 
72     /** @brief Sets the description of the source
73      *
74      *  @param[in] description - The c-string description
75      *  @throws SdEventError for underlying sd_event errors
76      */
77     void set_description(const char* description) const;
78 
79     /** @brief Sets the callback associated with the source to be performed
80      *         before the event loop goes to sleep, waiting for new events
81      *
82      *  @param[in] callback - Function run for preparation of the source
83      *  @throws SdEventError for underlying sd_event errors
84      */
85     void set_prepare(Callback&& callback);
86 
87     /** @brief Whether or not the source has any pending events that have
88      *         not been dispatched yet.
89      *
90      *  @throws SdEventError for underlying sd_event errors
91      *  @return 'true' if the source has pending events
92      *          'false' otherwise
93      */
94     bool get_pending() const;
95 
96     /** @brief Gets the priority of the source relative to other sources
97      *         The lower the priority the more important the source
98      *
99      *  @throws SdEventError for underlying sd_event errors
100      *  @return A 64 bit integer representing the dispatch priority
101      */
102     int64_t get_priority() const;
103 
104     /** @brief Sets the priority of the source relative to other sources
105      *         The lower the priority the more important the source
106      *
107      *  @param[in] priority - A 64 bit integer representing the priority
108      *  @throws SdEventError for underlying sd_event errors
109      */
110     void set_priority(int64_t priority) const;
111 
112     /** @brief Determines the enablement value of the source
113      *
114      *  @throws SdEventError for underlying sd_event errors
115      *  @return The enabled status of the source
116      */
117     Enabled get_enabled() const;
118 
119     /** @brief Sets the enablement value of the source
120      *
121      *  @param[in] enabled - The new state of the source
122      *  @throws SdEventError for underlying sd_event errors
123      */
124     void set_enabled(Enabled enabled) const;
125 
126     /** @brief Determines the floating nature of the source
127      *
128      *  @throws SdEventError for underlying sd_event errors
129      *  @return The enabled status of the source
130      */
131     bool get_floating() const;
132 
133     /** @brief Sets the floating nature of the source
134      *         If set to true, the source will continue to run after the
135      *         destruction of this handle.
136      *
137      *  @param[in] b - Whether or not the source should float
138      *  @throws SdEventError for underlying sd_event errors
139      */
140     void set_floating(bool b) const;
141 
142   protected:
143     Event event;
144 
145     /** @brief Constructs a basic event source wrapper
146      *         Owns the passed reference to the source
147      *         This ownership is exception safe and will properly free the
148      *         source in the case of an exception during construction
149      *
150      *  @param[in] event  - The event associated with the source
151      *  @param[in] source - The underlying sd_event_source wrapped
152      *  @param[in]        - Signifies that ownership is being transfered
153      */
154     Base(const Event& event, sd_event_source* source, std::false_type);
155 
156     /** @brief Constructs a basic non-owning event source wrapper
157      *         Does not own the passed reference to the source because
158      *         this is meant to be used only as a reference inside an event
159      *         source.
160      *  @internal
161      *
162      *  @param[in] other - The source wrapper to copy
163      *  @param[in]       - Signifies that this new copy is non-owning
164      */
165     Base(const Base& other, sdeventplus::internal::NoOwn);
166 
167     /** @brief Sets the userdata of the source to the passed in source
168      *         This needs to be called by all source implementors.
169      *
170      *  @param[in] data - The data stored in the userdata slot.
171      *  @throws SdEventError for underlying sd_event errors
172      */
173     void set_userdata(std::unique_ptr<detail::BaseData> data) const;
174 
175     /** @brief Get the heap allocated version of the Base
176      *
177      *  @return A reference to the Base
178      */
179     detail::BaseData& get_userdata() const;
180 
181     /** @brief Returns a reference to the prepare callback executed for this
182      *         source
183      *
184      *  @return A reference to the callback, this should be checked to make sure
185      *          the callback is valid as there is no guarantee
186      */
187     Callback& get_prepare();
188 
189     /** @brief A helper for subclasses to trivially wrap a c++ style callback
190      *         to be called from the sd-event c library
191      *
192      *  @param[in] name     - The name of the callback for use in error messages
193      *  @param[in] source   - The sd_event_source provided by sd-event
194      *  @param[in] userdata - The userdata provided by sd-event
195      *  @param[in] args...  - Extra arguments to pass to the callaback
196      *  @return An negative errno on error, or 0 on success
197      */
198     template <typename Callback, class Data, auto getter, typename... Args>
199     static int sourceCallback(const char* name, sd_event_source*,
200                               void* userdata, Args&&... args)
201     {
202         if (userdata == nullptr)
203         {
204             fprintf(stderr, "sdeventplus: %s: Missing userdata\n", name);
205             return -EINVAL;
206         }
207         Data& data =
208             static_cast<Data&>(*reinterpret_cast<detail::BaseData*>(userdata));
209         Callback& callback = std::invoke(getter, data);
210         return internal::performCallback(name, callback, std::ref(data),
211                                          std::forward<Args>(args)...);
212     }
213 
214   private:
215     static sd_event_source* ref(sd_event_source* const& source,
216                                 const internal::SdEvent*& sdevent, bool& owned);
217     static void drop(sd_event_source*&& source,
218                      const internal::SdEvent*& sdevent, bool& owned);
219 
220     stdplus::Copyable<sd_event_source*, const internal::SdEvent*,
221                       bool>::Handle<drop, ref>
222         source;
223 
224     /** @brief A wrapper around deleting the heap allocated base class
225      *         This is needed for calls from sd_event destroy callbacks.
226      *
227      * @param[in] userdata - The provided userdata for the source
228      */
229     static void destroy_userdata(void* userdata);
230 
231     /** @brief A wrapper around the callback that can be called from sd-event
232      *
233      * @param[in] source   - The sd_event_source associated with the call
234      * @param[in] userdata - The provided userdata for the source
235      * @return 0 on success or a negative errno otherwise
236      */
237     static int prepareCallback(sd_event_source* source, void* userdata);
238 };
239 
240 namespace detail
241 {
242 
243 class BaseData : public Base
244 {
245   private:
246     Base::Callback prepare;
247 
248   public:
249     BaseData(const Base& base);
250 
251     friend Base;
252 };
253 
254 } // namespace detail
255 
256 } // namespace source
257 } // namespace sdeventplus
258