From 35e5d32901c9a35700d3d8b046971dafc9bed5fe Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Sat, 13 Jun 2026 23:23:15 +0900 Subject: kernel: generalize the inotify watcher into a Host::watch_file service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hot-reload watcher was substrate-internal; expose it as a typed RAII primitive any extension can use (config hot-reload is the first consumer), per "the kernel owns the event/service bus; extensions never hold raw event-loop glue". - New public watch.hpp: `class FileWatch` (move-only RAII; ~/reset() stop the watch) + `Host::watch_file(path, on_change) -> FileWatch`. on_change fires on the event-loop thread, COALESCED (one save = one call), EDITOR-SAFE (dir-watch the basename across temp+rename), fires on CREATE of a not-yet-existing file, and is ERROR-ISOLATED to the calling extension (carries its id; a throw disables only that extension). UNGATED — works without UNBOX_DEV. - New src/file_watcher.{hpp,cpp}: ONE session-wide inotify instance on the wl_event_loop multiplexing all watched paths. The substrate's UI-asset hot-reload was refactored onto it (no second inotify); only the substrate's *decision* to watch UI assets stays UNBOX_DEV-gated. Created lazily on first watch; torn down leak-clean before the loop dies. host.hpp/kernel.md documented. kernel 58 cases/254 assertions green on build + build-asan (incl. the inotify path), no new suppressions. Edits confined to packages/kernel/. --- packages/kernel/src/server_impl.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'packages/kernel/src/server_impl.hpp') diff --git a/packages/kernel/src/server_impl.hpp b/packages/kernel/src/server_impl.hpp index bcdb693..61c073f 100644 --- a/packages/kernel/src/server_impl.hpp +++ b/packages/kernel/src/server_impl.hpp @@ -5,6 +5,7 @@ #include #include +#include "file_watcher.hpp" #include "listener.hpp" #include "ui_substrate.hpp" @@ -93,6 +94,16 @@ struct Server::Impl : detail::DisableSink { // per-extension facades (PerExtensionUi, one per HostImpl) borrow it. std::unique_ptr substrate; + // The ONE inotify-on-the-wl_event_loop file watcher for the session, shared + // by Host::watch_file (config + extensions) AND the substrate's asset + // hot-reload. Created lazily on the first watch (asset or watch_file) via + // file_watcher(); torn down in shutdown() BEFORE the display/loop dies (so + // its event source is removed while the loop is still alive). + std::unique_ptr watcher; + // Get-or-create the shared watcher (lazy). Returns nullptr only if there is + // no wl_event_loop (never in practice — the display always has one). + auto file_watcher() -> FileWatcher*; + std::list> outputs; std::list> keyboards; std::list> touch_devices; @@ -256,6 +267,14 @@ protected: } void adopt_hook(detail::HookBase& hook) override { server_->register_hook(hook); } auto surface_store() -> detail::PointerAssoc& override { return server_->surface_assoc; } + auto register_file_watch(std::string path, std::function on_change) + -> FileWatch override { + FileWatcher* w = server_->file_watcher(); + if (w == nullptr) { + return FileWatch{}; + } + return w->add(path, std::move(on_change), id_); + } private: Server::Impl* server_; -- cgit v1.2.3