From bdaf9249a723c04aaea196208aadb256d5bec480 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 27 Feb 2011 12:30:18 +0100 Subject: [PATCH] Main: Updated documentation --- ucw/doc/mainloop.txt | 21 ++++++++++------- ucw/mainloop.h | 54 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/ucw/doc/mainloop.txt b/ucw/doc/mainloop.txt index d39a84c1..c747beca 100644 --- a/ucw/doc/mainloop.txt +++ b/ucw/doc/mainloop.txt @@ -12,10 +12,15 @@ example various timers telling that a train is scheduled to depart from some station. The mainloop module takes care of the low-level part of event-driven -programs: it calls the OS to monitor file activity, to interrupt -the program at the right moment to serve a timer, and so on. The -programmer only defines hooks that should be called to handle -the events and calls mainloop functions to schedule them. +programs: it provides an event loop (often called a main loop), which +watches for events requested by the rest of the program and calls +a supplied callback when an event happens. + +More precisely, for each type of an event (file descriptor activity, +timer etc.), there is a +handler structure+, which contains the description +of the event (e.g., the time where the timer should fire), a pointer to +a +handler function+ (the event callback) and data for use by the handler +function. The handler is then registered with the main loop. - <> - <> @@ -26,7 +31,7 @@ the events and calls mainloop functions to schedule them. - <> - <> - <> -- <> +- <> [[contexts]] Simple use @@ -35,13 +40,13 @@ Simple use Simple programs usually employ the main loop in a straightforward way: - Call @main_init() to initialize the main loop machinery. -- Add an initial set of event hooks (@file_add(), @timer_add(), etc.). +- Add an initial set of event handers (@file_add(), @timer_add(), etc.). - Enter the event loop by calling @main_loop(). This function runs for the rest of the lifetime of the program. It watches for events and - handles them by calling the appropriate hook functions. These functions + handles them by calling the appropriate handler functions. These functions can of course add new events or modify/delete the existing ones. - When the program decides it wants to stop, it calls @main_shut_down(), - or alternatively it returns <> from some hook callback. + or alternatively it returns <> from some hook functions. Soon after that, @main_loop() returns. - Remove all event hooks and call @main_cleanup(). diff --git a/ucw/mainloop.h b/ucw/mainloop.h index e1a09ef9..a1d4e24d 100644 --- a/ucw/mainloop.h +++ b/ucw/mainloop.h @@ -24,10 +24,10 @@ /** The main loop context **/ struct main_context { - timestamp_t now; /** [*] Current time in milliseconds since the UNIX epoch. See @main_get_time(). **/ - ucw_time_t now_seconds; /** [*] Current time in seconds since the epoch. **/ - timestamp_t idle_time; /** [*] Total time in milliseconds spent by waiting for events. **/ - uns shutdown; /** [*] Setting this to nonzero forces the @main_loop() function to terminate. **/ + timestamp_t now; /* [*] Current time in milliseconds since the UNIX epoch. See @main_get_time(). */ + ucw_time_t now_seconds; /* [*] Current time in seconds since the epoch. */ + timestamp_t idle_time; /* [*] Total time in milliseconds spent by waiting for events. */ + uns shutdown; /* [*] Setting this to nonzero forces the @main_loop() function to terminate. */ clist file_list; clist file_active_list; clist hook_list; @@ -244,6 +244,7 @@ struct main_file { * The file descriptor is automatically set to the non-blocking mode. **/ void file_add(struct main_file *fi); + /** * Tell the main loop that the file structure has changed. Call it whenever you * change any of the handlers. @@ -251,6 +252,7 @@ void file_add(struct main_file *fi); * Can be called only on active files (only the ones added by @file_add()). **/ void file_chg(struct main_file *fi); + /** * Removes a file from the watched set. If you want to close a descriptor, * please use this function first. @@ -258,6 +260,7 @@ void file_chg(struct main_file *fi); * Can be called from a handler. **/ void file_del(struct main_file *fi); + /** Show current state of a file. Available only if LibUCW has been compiled with `CONFIG_DEBUG`. **/ void file_debug(struct main_file *fi); @@ -410,11 +413,13 @@ enum main_hook_return { * May be called from inside a hook handler too. **/ void hook_add(struct main_hook *ho); + /** * Removes an existing hook from the loop. - * May be called from inside a hook handler (to delete itself or other hook). + * May be called from inside a hook handler (to delete itself or another hook). **/ void hook_del(struct main_hook *ho); + /** Show current state of a hook. Available only if LibUCW has been compiled with `CONFIG_DEBUG`. **/ void hook_debug(struct main_hook *ho); @@ -447,12 +452,14 @@ struct main_process { * if you removed the process previously by @process_del(). **/ void process_add(struct main_process *mp); + /** * Removes the process from the watched set. This is done * automatically, when the process terminates, so you need it only * when you do not want to watch a running process any more. */ void process_del(struct main_process *mp); + /** * Forks and fills the @mp with information about the new process. * @@ -472,17 +479,46 @@ int process_fork(struct main_process *mp); /** Show current state of a process. Available only if LibUCW has been compiled with `CONFIG_DEBUG`. **/ void process_debug(struct main_process *pr); -/* FIXME: Docs */ +/*** + * [[signal]] + * Synchronous delivery of signals + * ------------------------------- + * + * UNIX signals are delivered to processes in an asynchronous way: when a signal + * arrives (and it is not blocked), the process is interrupted and the corresponding + * signal handler function is called. However, most data structures and even most + * system library calls are not safe with respect to interrupts, so most program + * using signals contain subtle race conditions and may fail once in a long while. + * + * To avoid this problem, the event loop can be asked for synchronous delivery + * of signals. When a signal registered with @signal_add() arrives, it wakes up + * the loop (if it is not already awake) and it is processed in the same way + * as all other events. + * + * When used in a multi-threaded program, the signals are delivered to the thread + * which is currently using the particular main loop context. If the context is not + * current in any thread, the signals are blocked. + * + * As usually with UNIX signals, multiple instances of a single signal can be + * merged and delivered only once. (Some implementations of the main loop can even + * drop a signal completely during very intensive signal traffic, when an internal + * signal queue overflows.) + ***/ +/** Description of a signal to catch. **/ struct main_signal { cnode n; - int signum; - void (*handler)(struct main_signal *ms); - void *data; + int signum; /* [*] Signal to catch */ + void (*handler)(struct main_signal *ms); /* [*] Called when the signal arrives */ + void *data; /* [*] For use by the handler */ }; +/** Request a signal to be caught and delivered synchronously. **/ void signal_add(struct main_signal *ms); + +/** Cancel a request for signal catching. **/ void signal_del(struct main_signal *ms); + /** Show current state of a signal catcher. Available only if LibUCW has been compiled with `CONFIG_DEBUG`. **/ void signal_debug(struct main_signal *sg); -- 2.39.2