+/** The main loop context **/
+struct main_context {
+ timestamp_t now; /* [*] Current time in milliseconds since an unknown epoch. See main_get_time(). */
+ timestamp_t idle_time; /* [*] Total time in milliseconds spent by waiting for events. */
+ uint shutdown; /* [*] Setting this to nonzero forces the main_loop() function to terminate. */
+ clist file_list;
+ clist file_active_list;
+ clist hook_list;
+ clist hook_done_list;
+ clist process_list;
+ clist signal_list;
+ uint file_cnt;
+ uint single_step;
+#ifdef CONFIG_UCW_EPOLL
+ int epoll_fd; /* File descriptor used for epoll */
+ struct epoll_event *epoll_events;
+ clist file_recalc_list;
+#else
+ uint poll_table_obsolete;
+ struct pollfd *poll_table;
+ struct main_file **poll_file_table;
+#endif
+ struct main_timer **timer_table; /* Growing array containing the heap of timers */
+ sigset_t want_signals;
+ int sig_pipe_send;
+ int sig_pipe_recv;
+ struct main_file *sig_pipe_file;
+ struct main_signal *sigchld_handler;
+};
+
+struct main_context *main_new(void); /** Create a new context. **/
+
+/**
+ * Delete a context, assuming it does have any event handlers attached. Does nothing if @m is NULL.
+ * It is allowed to call @main_delete() from a hook function of the same context, but you must
+ * never return to the main loop -- e.g., you can exit() the process instead.
+ **/
+void main_delete(struct main_context *m);
+
+/**
+ * Delete a context. If there are any event handlers attached, they are deactivated
+ * (but the responsibility to free the memory there were allocated from lies upon you).
+ * If there are any file handlers, the corresponding file descriptors are closed.
+ **/
+void main_destroy(struct main_context *m);
+
+/** Switch the current context of the calling thread. Returns the previous current context. **/
+struct main_context *main_switch_context(struct main_context *m);
+
+/** Return the current context. Dies if there is none or if the context has been deleted. **/
+struct main_context *main_current(void);
+
+/** Initialize the main loop module and create a top-level context. **/
+void main_init(void);
+
+/** Deinitialize the main loop module, calling @main_delete() on the top-level context. **/
+void main_cleanup(void);
+
+/**
+ * Deinitialize the main loop module, calling @main_destroy() on the top-level context.
+ * This is especially useful in a freshly forked-off child process.
+ **/
+void main_teardown(void);
+
+/**
+ * Start the event loop on the current context.
+ * It will watch the provided objects and call callbacks.
+ * Terminates when someone calls @main_shut_down(),
+ * or when all <<hook,hooks>> return <<enum_main_hook_return,`HOOK_DONE`>>
+ * or at last one <<hook,hook>> returns <<enum_main_hook_return,`HOOK_SHUTDOWN`>>.
+ **/
+void main_loop(void);
+
+/**
+ * Perform a single iteration of the main loop.
+ * Check if there are any events ready and process them.
+ * If there are none, do not wait.
+ **/
+void main_step(void);
+
+/** Ask the main loop to terminate at the nearest occasion. **/
+static inline void main_shut_down(void)
+{
+ main_current()->shutdown = 1;
+}
+
+/**
+ * Show the current state of a given context (use @main_debug() for the current context).
+ * Available only if LibUCW has been compiled with `CONFIG_UCW_DEBUG`.
+ **/
+void main_debug_context(struct main_context *m);
+
+static inline void main_debug(void)
+{
+ main_debug_context(main_current());
+}
+