1 #pragma once
2 
3 #include <cerrno>
4 #include <cstdint>
5 #include <cstdio>
6 #include <functional>
7 #include <sdeventplus/event.hpp>
8 #include <sdeventplus/internal/sdref.hpp>
9 #include <sdeventplus/internal/utils.hpp>
10 #include <systemd/sd-bus.h>
11 #include <type_traits>
12 
13 namespace sdeventplus
14 {
15 namespace source
16 {
17 
18 /** @class Enabled
19  *  @brief Mapping of sdeventplus source enable values to the sd-event
20  *         equivalent
21  */
22 enum class Enabled
23 {
24     Off = SD_EVENT_OFF,
25     On = SD_EVENT_ON,
26     OneShot = SD_EVENT_ONESHOT,
27 };
28 
29 /** @class Base
30  *  @brief The base class for all sources implementing common source methods
31  *         Not instantiated directly by end users
32  */
33 class Base
34 {
35   public:
36     using Callback = std::function<void(Base& source)>;
37 
38     virtual ~Base();
39 
40     /** @brief Gets the underlying sd_event_source
41      *
42      *  @return The sd_event_source
43      */
44     sd_event_source* get() const;
45 
46     /** @brief Gets the associated Event object
47      *
48      *  @return The Event
49      */
50     const Event& get_event() const;
51 
52     /** @brief Gets the description of the source
53      *
54      *  @throws SdEventError for underlying sd_event errors
55      *  @return The c-string description or a nullptr if none exists
56      */
57     const char* get_description() const;
58 
59     /** @brief Sets the description of the source
60      *
61      *  @param[in] description - The c-string description
62      *  @throws SdEventError for underlying sd_event errors
63      */
64     void set_description(const char* description) const;
65 
66     /** @brief Sets the callback associated with the source to be performed
67      *         before the event loop goes to sleep, waiting for new events
68      *
69      *  @param[in] callback - Function run for preparation of the source
70      *  @throws SdEventError for underlying sd_event errors
71      */
72     void set_prepare(Callback&& callback);
73 
74     /** @brief Whether or not the source has any pending events that have
75      *         not been dispatched yet.
76      *
77      *  @throws SdEventError for underlying sd_event errors
78      *  @return 'true' if the source has pending events
79      *          'false' otherwise
80      */
81     bool get_pending() const;
82 
83     /** @brief Gets the priority of the source relative to other sources
84      *         The lower the priority the more important the source
85      *
86      *  @throws SdEventError for underlying sd_event errors
87      *  @return A 64 bit integer representing the dispatch priority
88      */
89     int64_t get_priority() const;
90 
91     /** @brief Sets the priority of the source relative to other sources
92      *         The lower the priority the more important the source
93      *
94      *  @param[in] priority - A 64 bit integer representing the priority
95      *  @throws SdEventError for underlying sd_event errors
96      */
97     void set_priority(int64_t priority) const;
98 
99     /** @brief Determines the enablement value of the source
100      *
101      *  @throws SdEventError for underlying sd_event errors
102      *  @return The enabled status of the source
103      */
104     Enabled get_enabled() const;
105 
106     /** @brief Sets the enablement value of the source
107      *
108      *  @param[in] enabled - The new state of the source
109      *  @throws SdEventError for underlying sd_event errors
110      */
111     void set_enabled(Enabled enabled) const;
112 
113   protected:
114     Event event;
115     internal::SdRef<sd_event_source> source;
116 
117     /** @brief Constructs a basic event source wrapper
118      *         Adds a reference to the source
119      *
120      *  @param[in] event  - The event associated with the source
121      *  @param[in] source - The underlying sd_event_source wrapped
122      *  @throws SdEventError for underlying sd_event errors
123      */
124     Base(const Event& event, sd_event_source* source);
125 
126     /** @brief Constructs a basic event source wrapper
127      *         Owns the passed reference to the source
128      *         This ownership is exception safe and will properly free the
129      *         source in the case of an exception during construction
130      *
131      *  @param[in] event  - The event associated with the source
132      *  @param[in] source - The underlying sd_event_source wrapped
133      *  @throws SdEventError for underlying sd_event errors
134      */
135     Base(const Event& event, sd_event_source* source, std::false_type);
136 
137     // We can't ever copy an event_source because the callback
138     // data has to be unique.
139     Base(const Base& other) = delete;
140     Base& operator=(const Base& other) = delete;
141     // We don't want to allow any kind of slicing.
142     Base(Base&& other);
143     Base& operator=(Base&& other);
144 
145     /** @brief Returns a reference to the prepare callback executed for this
146      *         source
147      *
148      *  @return A reference to the callback, this should be checked to make sure
149      *          the callback is valid as there is no guarantee
150      */
151     const Callback& get_prepare() const;
152 
153     /** @brief A helper for subclasses to trivially wrap a c++ style callback
154      *         to be called from the sd-event c library
155      *
156      *  @param[in] name     - The name of the callback for use in error messages
157      *  @param[in] source   - The sd_event_source provided by sd-event
158      *  @param[in] userdata - The userdata provided by sd-event
159      *  @param[in] args...  - Extra arguments to pass to the callaback
160      *  @return An negative errno on error, or 0 on success
161      */
162     template <typename Callback, class Source,
163               const Callback& (Source::*getter)() const, typename... Args>
164     static int sourceCallback(const char* name, sd_event_source*,
165                               void* userdata, Args... args)
166     {
167         if (userdata == nullptr)
168         {
169             fprintf(stderr, "sdeventplus: %s: Missing userdata\n", name);
170             return -EINVAL;
171         }
172         Source* source = reinterpret_cast<Source*>(userdata);
173         return internal::performCallback(name, (source->*getter)(),
174                                          std::ref(*source), args...);
175     }
176 
177   private:
178     Callback prepare;
179 
180     /** @brief A helper used to make sure the userdata for the sd-event
181      *         callback is set to the current source c++ object
182      *
183      *  @throws SdEventError for underlying sd_event errors
184      */
185     void set_userdata();
186 
187     /** @brief A wrapper around the callback that can be called from sd-event
188      *
189      * @param[in] source   - The sd_event_source associated with the call
190      * @param[in] userdata - The provided userdata for the source
191      * @return 0 on success or a negative errno otherwise
192      */
193     static int prepareCallback(sd_event_source* source, void* userdata);
194 };
195 
196 } // namespace source
197 } // namespace sdeventplus
198