]> mj.ucw.cz Git - libucw.git/commitdiff
Main: Updated documentation
authorMartin Mares <mj@ucw.cz>
Sun, 27 Feb 2011 11:30:18 +0000 (12:30 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 27 Feb 2011 11:30:18 +0000 (12:30 +0100)
ucw/doc/mainloop.txt
ucw/mainloop.h

index d39a84c1d2bbe97acd7e7531a4706f927afedba6..c747beca615e5d468eec9204c32aaca459c63312 100644 (file)
@@ -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.
 
 - <<simple,Simple use>>
 - <<contexts,Using multiple contexts>>
@@ -26,7 +31,7 @@ the events and calls mainloop functions to schedule them.
 - <<blockio,Asynchronous block I/O>>
 - <<hooks,Loop hooks>>
 - <<process,Child processes>>
-- <<control,Control of the mainloop>>
+- <<signal,Synchronous delivery of signals>>
 
 [[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 <<enum_main_hook_return,`HOOK_SHUTDOWN`>> from some hook callback.
+  or alternatively it returns <<enum_main_hook_return,`HOOK_SHUTDOWN`>> from some hook functions.
   Soon after that, @main_loop() returns.
 - Remove all event hooks and call @main_cleanup().
 
index e1a09ef990a6b0cc6c2ba57107c54c970c29a0fb..a1d4e24de000d639b229ae9d2ddbf8d84bdf8891 100644 (file)
 
 /** 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);