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