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