X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fdoc%2Fmainloop.txt;h=c747beca615e5d468eec9204c32aaca459c63312;hb=bfca2c42bc0e749f8611339568be502f22ac5e9c;hp=6a196281edba0f8abe69cb30de28dbec09f8d028;hpb=a4fe009d3366b0a3e119713b0ecc7fc0070efdfa;p=libucw.git diff --git a/ucw/doc/mainloop.txt b/ucw/doc/mainloop.txt index 6a196281..c747beca 100644 --- a/ucw/doc/mainloop.txt +++ b/ucw/doc/mainloop.txt @@ -12,18 +12,95 @@ 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. -// TODO Example? +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. -- <> +- <> +- <> +- <> +- <> - <> - <> +- <> - <> - <> -- <> +- <> + +[[contexts]] +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 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 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 functions. + Soon after that, @main_loop() returns. +- Remove all event hooks and call @main_cleanup(). + +The event structures (like <>) are +always allocated by the user, but please touch only the fields marked +in this documentation with `[*]`. The other fields are used internally; +you should initialize them to zeroes before adding the event and avoid +accessing them afterwards. + +[[contexts]] +Using multiple contexts +----------------------- + +In a more complex program, it can be useful to keep several sets of events +and run a separate instance of the event loop for each such set. A typical +example would be a multi-threaded program or a function which needs to +communicate with a network server locally, ignoring all other events +before the operation is finished. + +For such cases, you can create multiple instances of <> +by calling @main_new(). Each thread then keeps its own current context, +which can be changed by @main_switch_context(). All mainloop functions +then either take an explicit pointer to a context or (more typically) +they operate on the current context. When you no longer need the context, you +can delete it by @main_delete(). + +It is even possible to use nested main loops: in a hook called by the +top-level instance of @main_loop(), you can switch to a different context, +call @main_loop() recursively and when you are done, switch back and return +to the top-level loop. + +*CAVEAT:* In the present implementation, only a single context per process +can handle process exit events. If you use @process_add() in multiple contexts, +it can happen that the current context catches the `SIGCHLD` signal and obtains +information about a child process associated with another context, which it does +not know how to handle. If you ever need this, please let us know. + +[[threads]] +Forking and threading +--------------------- + +Using the event loop in a multi-threaded or multi-process program is possible, +but it should be done very carefully. + +Multiple threads can use the main loop, but each of them must use a separate +context (or contexts). + +When you fork() a child process, either the parent or the child must give up +use of each main loop context. The @main_teardown() and @main_destroy() functions +can be useful for that. (The reason is that some parts of the main loop context, +like file descriptors used internally, become shared between the processes, so +the processes could influence each other in crazy ways. You do not want to hunt +for such bugs.) + + !!ucw/mainloop.h