summaryrefslogtreecommitdiff
path: root/src/common/private_loop.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/private_loop.h')
-rw-r--r--src/common/private_loop.h225
1 files changed, 55 insertions, 170 deletions
diff --git a/src/common/private_loop.h b/src/common/private_loop.h
index 432bbc3..a70997a 100644
--- a/src/common/private_loop.h
+++ b/src/common/private_loop.h
@@ -1,168 +1,22 @@
/**
* @file
- * Optional event loop, file watches, and timers.
- *
- * Use the loop's owning thread for all calls and callbacks, except
- * yasl_private_loop_now_ns(), yasl_private_loop_kick(), and yasl_private_loop_post(), which any thread
- * may call. A display borrows a supplied loop. For window applications,
- * drive yasl_private_display_dispatch(), drain input, then yasl_private_display_flush(); the
- * standalone loop_run() function does not replace this cycle. Timer intervals are
- * nanoseconds; timeout_ms arguments are milliseconds. Do not recursively step/run
- * or destroy a loop from a callback.
+ * The internal parts of the loop. The loop itself is public: see yasl_loop_* in
+ * yasl.h. Use the loop's owning thread for all calls and callbacks, except
+ * yasl_private_loop_now_ns(), yasl_private_loop_kick(), yasl_private_loop_wake()
+ * and yasl_private_loop_post(), which any thread may call.
*/
#ifndef YASL_PRIVATE_LOOP_H
#define YASL_PRIVATE_LOOP_H
#include "common/types.h"
+#include "yasl/yasl.h"
#ifdef __cplusplus
extern "C" {
#endif
-/* Optional event loop. Use the display's loop when adding application timers.
- * A step waits at most timeout_ms: zero polls, a negative value waits indefinitely.
- * Calls and callbacks use the loop's owning thread. */
-/**
- * Create an owned standalone file-descriptor and timer loop.
- * @return A loop to destroy with yasl_private_loop_destroy(), or NULL on allocation failure.
- * Use on one owning thread. Passing it to yasl_private_display_open() only lends it to
- * the display; the caller retains ownership.
- */
-struct yasl_private_loop *yasl_private_loop_create(void);
-/**
- * Release a loop, its watches, its timers, and its signal watch.
- * @param l Loop, or NULL for no action.
- * Close displays borrowing this loop first. Must not run during a loop callback
- * or an active step/run. Watched file descriptors are not closed. Posted
- * functions that have not run are dropped; no thread may still post or kick.
- */
-void yasl_private_loop_destroy(struct yasl_private_loop *l);
-/**
- * Step a standalone loop until yasl_private_loop_quit() is called.
- * @param l Loop.
- * @return Zero after quit, or -1 on failure.
- * For a window application, use a dispatch, input-poll, flush cycle instead;
- * loop_run alone does not perform that full cycle on every backend.
- */
-int yasl_private_loop_run(struct yasl_private_loop *l);
-/**
- * Wait for file-descriptor readiness or a timer deadline and run callbacks.
- * @param l Loop.
- * @param timeout_ms Maximum wait: zero polls, negative waits indefinitely.
- * @return Number of callbacks handled, or -1 on failure.
- * Timer deadlines shorten the wait. Callbacks can add/delete sources, including
- * themselves. Do not recursively step/run this loop.
- */
-int yasl_private_loop_step(struct yasl_private_loop *l, int timeout_ms);
-/**
- * Ask the currently running yasl_private_loop_run() to return after this step.
- * @param l Loop, or NULL for no action.
- * Call on the owning thread, usually from a callback.
- */
-void yasl_private_loop_quit(struct yasl_private_loop *l);
-/**
- * Wake a loop that is waiting, without running any callback.
- * @param l Loop, or NULL for no action.
- * May be called from any thread and from a signal handler. The loop must stay
- * alive until the call returns. A waiting yasl_private_loop_step(), yasl_private_loop_run(), or
- * yasl_private_display_dispatch() on this loop returns early; a loop that is not
- * waiting returns early from its next wait instead. Kicks coalesce. This does
- * not schedule a redraw or enqueue an event; use yasl_private_loop_post() to run code
- * on the owning thread.
- */
-void yasl_private_loop_kick(struct yasl_private_loop *l);
-/**
- * Run a function on the loop's owning thread.
- * @param l Loop.
- * @param fn Required function, called once with ud during a later step.
- * @param ud Borrowed userdata until fn runs.
- * @return true if queued; false for NULL arguments, a loop without a wake
- * pipe, or allocation failure.
- * May be called from any thread, but not from a signal handler. Wakes the loop
- * like yasl_private_loop_kick(). Functions run in posting order, during a
- * yasl_private_loop_step() or display dispatch on the owning thread. They may post
- * again; a function posted while posts are running waits for a later step.
- * Stop posting before yasl_private_loop_destroy(), which drops functions that have
- * not run.
- */
-bool yasl_private_loop_post(struct yasl_private_loop *l, void (*fn)(void *ud), void *ud);
-/**
- * Deliver POSIX signals to a callback on the loop's owning thread.
- * @param l Loop.
- * @param signals Signal numbers to watch; the array is read during the call.
- * @param n Number of entries, at least one.
- * @param cb Required callback, given ud and one signal number per delivery.
- * @param ud Borrowed userdata until the watch is removed.
- * @return true if every signal is watched; false with errno set and no
- * dispositions changed. EINVAL means a NULL or invalid argument, including
- * SIGKILL and SIGSTOP. EBUSY means another loop watches one of the signals.
- * Replaces this loop's previous watch, if any. Installs one process-wide
- * handler per signal with SA_RESTART and an empty handler mask, and saves the
- * previous action. The handler only records the signal and wakes the loop,
- * so it may run on any thread. YASL does not change any thread's signal mask:
- * a signal blocked in every thread stays pending and is not delivered. Caught
- * signals reset to their default action across exec, so spawned programs
- * do not inherit the handler. Repeated deliveries of one signal before the
- * callback runs coalesce into one callback. SIGCHLD reports stopped and
- * continued children as well as exits. Callbacks run during yasl_private_loop_step()
- * or display dispatch, and may remove the watch.
- */
-bool yasl_private_loop_watch_signals(struct yasl_private_loop *l, const int *signals, int n,
- void (*cb)(void *ud, int signo), void *ud);
-/**
- * Stop watching signals and restore their previous actions.
- * @param l Loop, or NULL for no action.
- * Does nothing if the loop watches no signals. Signals that arrived but have
- * not reached the callback are dropped. yasl_private_loop_destroy() also unwatches.
- */
-void yasl_private_loop_unwatch_signals(struct yasl_private_loop *l);
-/**
- * Read the monotonic clock used by YASL timers and timing results.
- * @return Nanoseconds from CLOCK_MONOTONIC, unrelated to wall-clock time.
- * May be called from any thread.
- */
-uint64_t yasl_private_loop_now_ns(void);
-/**
- * Get the loop used for a display's file watches and application timers.
- * @param d Display, or NULL.
- * @return Borrowed loop, or NULL. Do not destroy a display-owned loop yourself.
- */
-struct yasl_private_loop *yasl_private_display_loop(struct yasl_private_display *d);
-/**
- * Register a borrowed file descriptor for poll-style readiness.
- * @param l Loop.
- * @param fd Open file descriptor; it remains owned by the caller.
- * @param events Bitmask from <poll.h>, for example POLLIN or POLLOUT.
- * @param fn Callback receiving poll revents (including errors/hangup); return value is ignored.
- * @param ud Borrowed userdata until watch removal or loop destruction.
- * @return Positive watch ID, or -1 on failure.
- * Delete the watch before closing fd. The callback must consume readiness or
- * change/remove its watch to avoid repeated immediate wakeups.
- */
-int yasl_private_loop_add_fd(struct yasl_private_loop *l, int fd, short events,
- int (*fn)(int fd, short revents, void *ud), void *ud);
-/**
- * Remove a file watch without closing its descriptor.
- * @param l Loop.
- * @param id Watch ID returned by yasl_private_loop_add_fd().
- * @return Zero if removed, or -1 for an invalid/missing watch.
- */
-int yasl_private_loop_del_fd(struct yasl_private_loop *l, int id);
-/**
- * Replace a watch's poll event mask.
- * @param l Loop.
- * @param id Watch ID.
- * @param events New <poll.h> mask; zero disables requested readiness (errors may still arrive).
- * @return Zero if updated, or -1 for an invalid/missing watch.
- */
-int yasl_private_loop_set_fd_events(struct yasl_private_loop *l, int id, short events);
-
-/* Timers use nanoseconds. Return the next interval to repeat/reschedule, or zero
- * to remove the timer. A zero ID indicates failure. Loop timers live until they
- * stop, are deleted, or the loop is destroyed. Surface timers are also canceled
- * when their surface is destroyed. */
-/** Timer identity scoped to its loop. Zero is invalid; do not reuse a retired ID. */
-typedef uint32_t yasl_private_timer_id;
+/** Timer identity scoped to its loop. Zero is invalid; IDs are never reissued. */
+typedef uint64_t yasl_private_timer_id;
/** Timer callback. interval_ns is the last scheduled delay; return the next delay or zero to stop. */
typedef uint64_t (*yasl_private_timer_cb)(void *ud, yasl_private_timer_id id, uint64_t interval_ns);
@@ -170,29 +24,60 @@ typedef uint64_t (*yasl_private_timer_cb)(void *ud, yasl_private_timer_id id, ui
#define YASL_PRIVATE_MS_TO_NS(ms) ((uint64_t)(ms) * 1000000ull)
/**
- * Schedule a timer on a loop.
- * @param l Loop.
- * @param interval_ns Nonzero delay in monotonic nanoseconds before first firing.
- * @param cb Required callback; returns a new nonzero interval to repeat, or zero to stop.
- * @param ud Borrowed userdata until the timer stops, is deleted, or the loop is destroyed.
- * @return Nonzero timer ID, or zero for invalid arguments or allocation failure.
- * Repeating timers coalesce missed deadlines; do not use them to count elapsed
- * wall time. The callback receives the last scheduled interval, not elapsed time.
+ * How a display drives the loop it runs on. Each step runs prepare, the wait,
+ * check, deliver, then descriptor callbacks and timers.
+ * prepare: dispatch what the backend already holds, draw due surfaces, flush
+ * requests, and arm the read. True when progress is possible now, so the
+ * wait must not block.
+ * wait: replaces poll(2) for platforms whose events do not arrive on a
+ * descriptor; NULL uses poll. The loop reads descriptor readiness after it.
+ * check: runs after every wait, failed or not, before any callback; it closes
+ * what prepare opened.
+ * deliver: optional; hands queued events to the application.
+ */
+struct yasl_private_loop_driver {
+ bool (*prepare)(void *ud);
+ int (*wait)(void *ud, int timeout_ms);
+ void (*check)(void *ud);
+ void (*deliver)(void *ud);
+ void *ud;
+};
+/** Install a driver, or remove it with NULL. False with EBUSY when one is set. */
+bool yasl_private_loop_set_driver(yasl_loop *l, const struct yasl_private_loop_driver *driver);
+/** True on the thread that created the loop. */
+bool yasl_private_loop_owned(const yasl_loop *l);
+/** True while a step runs. */
+bool yasl_private_loop_stepping(const yasl_loop *l);
+/** The revents the last wait reported for watch id, until its callback runs. */
+short yasl_private_loop_revents(const yasl_loop *l, int id);
+
+/** Wake a waiting loop from any thread or a signal handler. Kicks coalesce. */
+void yasl_private_loop_kick(yasl_loop *l);
+/** Kick, but only from another thread: the owner's next step sees its own work. */
+void yasl_private_loop_wake(yasl_loop *l);
+/**
+ * Run fn on the loop's owning thread during a later step. Any thread, not a
+ * signal handler. False for NULL arguments or allocation failure. Functions run
+ * in posting order; one posted while posts run waits for a later step.
*/
-yasl_private_timer_id yasl_private_loop_add_timer(struct yasl_private_loop *l, uint64_t interval_ns,
- yasl_private_timer_cb cb, void *ud);
+bool yasl_private_loop_post(yasl_loop *l, void (*fn)(void *ud), void *ud);
+/** CLOCK_MONOTONIC nanoseconds. Any thread. */
+uint64_t yasl_private_loop_now_ns(void);
+
/**
- * Cancel a loop timer, including from its own callback.
- * @param l Loop.
- * @param id Timer ID.
- * @return true if an armed timer was removed, false if invalid or already retired.
+ * Get the loop used for a display's file watches and application timers.
+ * @param d Display, or NULL.
+ * @return Borrowed loop, or NULL. Do not destroy a display-owned loop yourself.
*/
-bool yasl_private_loop_del_timer(struct yasl_private_loop *l, yasl_private_timer_id id);
+yasl_loop *yasl_private_display_loop(struct yasl_private_display *d);
+
+/** Whether id is armed: added, not deleted, and not retired by its callback. */
+bool yasl_private_loop_timer_armed(const yasl_loop *l, yasl_private_timer_id id);
/**
* Schedule a timer canceled automatically on surface destruction.
* @param s Surface whose display loop will run the timer.
- * @param interval_ns Nonzero initial delay in nanoseconds.
- * @param cb Required timer callback, with the same rules as yasl_private_loop_add_timer().
+ * @param interval_ns Initial delay in nanoseconds.
+ * @param cb Required timer callback, with the same rules as yasl_loop_add_timer().
* @param ud Borrowed userdata until the timer ends or the surface is destroyed.
* @return Nonzero timer ID, or zero on failure.
* The surface does not own userdata. Cancel with yasl_private_surface_del_timer().