From 2f7630dd5985ef6fa237d0c79f820fcf128a97e5 Mon Sep 17 00:00:00 2001 From: Michal Vaner Date: Thu, 30 Oct 2008 15:35:21 +0100 Subject: [PATCH] ucw docs: Mainloop * May still need an example * File descriptors need to be described --- ucw/doc/Makefile | 2 +- ucw/doc/index.txt | 1 + ucw/doc/mainloop.txt | 21 ++++++ ucw/mainloop.h | 164 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 ucw/doc/mainloop.txt diff --git a/ucw/doc/Makefile b/ucw/doc/Makefile index 5fdf0375..71e002f9 100644 --- a/ucw/doc/Makefile +++ b/ucw/doc/Makefile @@ -2,7 +2,7 @@ DIRS+=ucw/doc -UCW_DOCS=fastbuf index basecode hash docsys conf mempool +UCW_DOCS=fastbuf index basecode hash docsys conf mempool mainloop UCW_INDEX=$(o)/ucw/doc/def_index.html UCW_DOCS_HTML=$(addprefix $(o)/ucw/doc/,$(addsuffix .html,$(UCW_DOCS))) diff --git a/ucw/doc/index.txt b/ucw/doc/index.txt index 3b51ec17..18559cc4 100644 --- a/ucw/doc/index.txt +++ b/ucw/doc/index.txt @@ -21,6 +21,7 @@ Modules - <> - <> - <> +- <> Other features -------------- diff --git a/ucw/doc/mainloop.txt b/ucw/doc/mainloop.txt new file mode 100644 index 00000000..916692ca --- /dev/null +++ b/ucw/doc/mainloop.txt @@ -0,0 +1,21 @@ +Mainloop +======== + +Not every program is sequential. You may need an event driven program +sometime, lets say a railway server. It has a connection to each +station and train to know, where each one is, some things happen at +given times, like train is scheduled to leave as station and so on. + +With the mainloop module you can write just the hooks and tell it to +watch over a set of file descriptors, timers and running processes. + +// TODO Example? + +- <> +- <> +- <> +- <> +- <> +- <> + +!!ucw/mainloop.h diff --git a/ucw/mainloop.h b/ucw/mainloop.h index 9d668859..b7824db8 100644 --- a/ucw/mainloop.h +++ b/ucw/mainloop.h @@ -12,28 +12,79 @@ #include "ucw/clists.h" -extern timestamp_t main_now; /* Current time in milliseconds since UNIX epoch */ -extern ucw_time_t main_now_seconds; /* Current time in seconds since the epoch */ -extern uns main_shutdown; -extern clist main_timer_list, main_file_list, main_hook_list, main_process_list; - -/* User-defined fields are marked with [*], all other fields must be initialized to zero. */ +/*** + * [[conventions]] + * Conventions + * ----------- + * + * The description of structures contain some fields marked as `[*]`. + * These are the only ones that are user defined. The rest is for + * internal use and you must initialize it to zeroes. + ***/ + +/*** + * [[time]] + * Time manipulation + * ----------------- + * + * This part allows you to know the current time and request + * to have your function called when the time comes. + ***/ -/* Timers */ +extern timestamp_t main_now; /** Current time in milliseconds since UNIX epoch. See @main_get_time(). **/ +extern ucw_time_t main_now_seconds; /** Current time in seconds since the epoch. **/ +extern clist main_timer_list, main_file_list, main_hook_list, main_process_list; +/** + * This is a description of a timer. + * You fill it with a handler function, any user-defined data and + * add it using @timer_add(). + * + * The handler() function must add it again or delete it with + * @timer_del(). + **/ struct main_timer { cnode n; timestamp_t expires; - void (*handler)(struct main_timer *tm); /* [*] Function to be called when the timer expires. Must re-add/del the timer.*/ + void (*handler)(struct main_timer *tm); /* [*] Function to be called when the timer expires. */ void *data; /* [*] Data for use by the handler */ }; -void timer_add(struct main_timer *tm, timestamp_t expires); /* Can modify a running timer, too */ +/** + * Adds a new timer into the mainloop to be watched and called, + * when it expires. It can be used to modify an already running + * timer. + * + * The @expire parameter is absolute -- you may use + * <>, if you need it relative to now. + **/ +void timer_add(struct main_timer *tm, timestamp_t expires); +/** + * Removes a timer from the watched ones. You need to call this, when + * the timer expires and you do not want to use it any more. It can be + * used to remove a still active timer too. + **/ void timer_del(struct main_timer *tm); -void main_get_time(void); /* Refresh main_now */ - -/* Files to poll */ +/** + * Forces refresh of <>. You do not usually + * need to call this, since it is called every time the loop polls for + * changes. It is here if you need extra precision or some of the + * hooks takes a long time. + **/ +void main_get_time(void); + +/*** + * [[file]] + * Activity on file descriptors + * ---------------------------- + * + * You can let the mainloop watch over a set of file descriptors + * for changes. + * + * //TODO: This probably needs some example how the handlers can be + * //used, describe the use of this part of module. + ***/ struct main_file { cnode n; @@ -66,14 +117,32 @@ void file_write(struct main_file *fi, void *buf, uns len); void file_set_timeout(struct main_file *fi, timestamp_t expires); void file_close_all(void); /* Close all known main_file's; frequently used after fork() */ -/* Hooks to be called in each iteration of the main loop */ +/*** + * [[hooks]] + * Loop hooks + * ---------- + * + * The hooks can be called whenever the mainloop perform an iteration. + * You can shutdown the mainloop from within them or request next call + * only when the loop is idle (for background operations). + ***/ +/** + * A hook. It contains the function to call and some user data. + * + * The handler() must return one value from + * <>. + **/ struct main_hook { cnode n; int (*handler)(struct main_hook *ho); /* [*] Hook function; returns HOOK_xxx */ void *data; /* [*] For use by the handler */ }; +/** + * Return value of the hook handler(). + * Specifies what should happen next. + **/ enum main_hook_return { HOOK_IDLE, /* Call again when the main loop becomes idle again */ HOOK_RETRY, /* Call again as soon as possible */ @@ -81,11 +150,29 @@ enum main_hook_return { HOOK_SHUTDOWN = -2 /* Shut down the main loop immediately */ }; +/** + * Inserts a new hook into the loop. + **/ void hook_add(struct main_hook *ho); +/** + * Removes an existing hook from the loop. + **/ void hook_del(struct main_hook *ho); -/* Processes to watch */ - +/*** + * [[process]] + * Child processes + * --------------- + * + * The main loop can watch child processes and notify you, + * when some of them terminates. + ***/ + +/** + * Description of a watched process. + * You fill in the handler() and `data`. + * The rest is set with @process_fork(). + **/ struct main_process { cnode n; int pid; /* Process id (0=not running) */ @@ -95,14 +182,53 @@ struct main_process { void *data; /* [*] For use by the handler */ }; +/** + * Asks the mainloop to watch this process. + * As it is done automatically in @process_fork(), you need this only + * 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. + * + * If the fork() succeeds, it: + * + * - Returns 0 in the child. + * - Returns 1 in the parent and calls @process_add() on it. + * + * In the case of unsuccessful fork(), it: + * + * - Fills in the `status_msg` and sets `status` to -1. + * - Calls the handler() as if the process terminated. + * - Returns 1. + **/ int process_fork(struct main_process *mp); -/* The main loop */ - -void main_init(void); +/*** + * [[control]] + * Control of the mainloop + * ----------------------- + * + * These functions control the mainloop as a whole. + ***/ + +extern uns main_shutdown; /** Setting this to nonzero forces the @main_loop() function to terminate. **/ +void main_init(void); /** Initializes the mainloop structures. Call before any `*_add` function. **/ +/** + * Start the mainloop. + * It will watch the provided objects and call callbacks. + * Terminates when someone sets <> + * to nonzero, when all <> return + * <> or at last one <> + * returns <>. + **/ void main_loop(void); -void main_debug(void); +void main_debug(void); /** Prints a lot of debug information about current status of the mainloop. **/ #endif -- 2.39.5