xref: /openbmc/sdeventplus/src/sdeventplus/source/base.hpp (revision 56dc78ba6babe928a1364d1f217edab29a872497)
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   protected:
127     Event event;
128 
129     /** @brief Constructs a basic event source wrapper
130      *         Owns the passed reference to the source
131      *         This ownership is exception safe and will properly free the
132      *         source in the case of an exception during construction
133      *
134      *  @param[in] event  - The event associated with the source
135      *  @param[in] source - The underlying sd_event_source wrapped
136      *  @param[in]        - Signifies that ownership is being transfered
137      */
138     Base(const Event& event, sd_event_source* source, std::false_type);
139 
140     /** @brief Constructs a basic non-owning event source wrapper
141      *         Does not own the passed reference to the source because
142      *         this is meant to be used only as a reference inside an event
143      *         source.
144      *  @internal
145      *
146      *  @param[in] other - The source wrapper to copy
147      *  @param[in]       - Signifies that this new copy is non-owning
148      */
149     Base(const Base& other, sdeventplus::internal::NoOwn);
150 
151     /** @brief Sets the userdata of the source to the passed in source
152      *         This needs to be called by all source implementors.
153      *
154      *  @param[in] data - The data stored in the userdata slot.
155      *  @throws SdEventError for underlying sd_event errors
156      */
157     void set_userdata(std::unique_ptr<detail::BaseData> data) const;
158 
159     /** @brief Get the heap allocated version of the Base
160      *
161      *  @return A reference to the Base
162      */
163     detail::BaseData& get_userdata() const;
164 
165     /** @brief Returns a reference to the prepare callback executed for this
166      *         source
167      *
168      *  @return A reference to the callback, this should be checked to make sure
169      *          the callback is valid as there is no guarantee
170      */
171     Callback& get_prepare();
172 
173     /** @brief A helper for subclasses to trivially wrap a c++ style callback
174      *         to be called from the sd-event c library
175      *
176      *  @param[in] name     - The name of the callback for use in error messages
177      *  @param[in] source   - The sd_event_source provided by sd-event
178      *  @param[in] userdata - The userdata provided by sd-event
179      *  @param[in] args...  - Extra arguments to pass to the callaback
180      *  @return An negative errno on error, or 0 on success
181      */
182     template <typename Callback, class Data, auto getter, typename... Args>
183     static int sourceCallback(const char* name, sd_event_source*,
184                               void* userdata, Args&&... args)
185     {
186         if (userdata == nullptr)
187         {
188             fprintf(stderr, "sdeventplus: %s: Missing userdata\n", name);
189             return -EINVAL;
190         }
191         Data& data =
192             static_cast<Data&>(*reinterpret_cast<detail::BaseData*>(userdata));
193         Callback& callback = std::invoke(getter, data);
194         return internal::performCallback(name, callback, std::ref(data),
195                                          std::forward<Args>(args)...);
196     }
197 
198   private:
199     static sd_event_source* ref(sd_event_source* const& source,
200                                 const internal::SdEvent*& sdevent, bool& owned);
201     static void drop(sd_event_source*&& source,
202                      const internal::SdEvent*& sdevent, bool& owned);
203 
204     stdplus::Copyable<sd_event_source*, const internal::SdEvent*,
205                       bool>::Handle<drop, ref>
206         source;
207 
208     /** @brief A wrapper around deleting the heap allocated base class
209      *         This is needed for calls from sd_event destroy callbacks.
210      *
211      * @param[in] userdata - The provided userdata for the source
212      */
213     static void destroy_userdata(void* userdata);
214 
215     /** @brief A wrapper around the callback that can be called from sd-event
216      *
217      * @param[in] source   - The sd_event_source associated with the call
218      * @param[in] userdata - The provided userdata for the source
219      * @return 0 on success or a negative errno otherwise
220      */
221     static int prepareCallback(sd_event_source* source, void* userdata);
222 };
223 
224 namespace detail
225 {
226 
227 class BaseData : public Base
228 {
229   private:
230     Base::Callback prepare;
231 
232   public:
233     BaseData(const Base& base);
234 
235     friend Base;
236 };
237 
238 } // namespace detail
239 
240 } // namespace source
241 } // namespace sdeventplus
242