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