#pragma once #include #include #include #include #include #include #include namespace sdbus { class IConnection; }; class DBusDispatcher { DBusDispatcher(const DBusDispatcher&) = delete; public: DBusDispatcher(bool systemBus = true); ~DBusDispatcher(); void Run(); // Stop everything, shutting down gracefully. void Stop(); void Wait(); bool IsFinished(); // Stop, but don't wait. Suitable for use in a signal handler. // The callback is executed by the dispatcher thread, and can therefore call non-signal-safe functions. void SignalStop(std::function &&callback); bool IsStopping(); using PostHandle = uint64_t; using PostCallback = std::function; PostHandle Post(PostCallback&&fn); using clock = std::chrono::steady_clock; template DBusDispatcher::PostHandle PostDelayed(const std::chrono::duration&delay,PostCallback&&fn) { return PostDelayed( std::chrono::duration_cast(delay), std::move(fn)); } DBusDispatcher::PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn); bool CancelPost(DBusDispatcher::PostHandle handle); sdbus::IConnection&Connection() { return *busConnection;} private: std::atomic isFinished; std::atomic signalStopRequested; bool signalStopExecuted = false; std::function signalStopCallback; uint64_t NextHandle() { return nextHandle.fetch_add(1); } int GetEventTimeoutMs(); std::atomic nextHandle; int eventFd = -1; bool closed = false; void ThreadProc(); void WakeThread(); std::unique_ptr busConnection; struct CallbackEntry { PostCallback callback; clock::time_point time; PostHandle handle; }; std::atomic stopping; std::vector postedEvents; bool threadJoined; std::thread serviceThread; std::mutex postMutex; };