]> mj.ucw.cz Git - libucw.git/blob - ucw/doc/mainloop.txt
Resource pools documented
[libucw.git] / ucw / doc / mainloop.txt
1 Mainloop
2 ========
3
4 Not every program is strictly sequential. Sometimes, an event-driven
5 model is much easier to grasp. A fine example of such a program could
6 be a railway server. It has a separate connection to each station
7 and also to each train, so that it knows where each of them is (and
8 that neither a train nor a station have got missing). So it has to wait
9 for events coming from these connections and handle them appropriately.
10 It also processes other events that it has itself generated -- for
11 example various timers telling that a train is scheduled to depart
12 from some station.
13
14 The mainloop module takes care of the low-level part of event-driven
15 programs: it provides an event loop (often called a main loop), which
16 watches for events requested by the rest of the program and calls
17 a supplied callback when an event happens.
18
19 More precisely, for each type of an event (file descriptor activity,
20 timer etc.), there is a +handler structure+, which contains the description
21 of the event (e.g., the time where the timer should fire), a pointer to
22 a +handler function+ (the event callback) and data for use by the handler
23 function. The handler is then registered with the main loop.
24
25 - <<simple,Simple use>>
26 - <<contexts,Using multiple contexts>>
27 - <<threads,Forking and threading>>
28 - <<basic,Basic operations>>
29 - <<time,Time and timers>>
30 - <<file,Activity on file descriptors>>
31 - <<blockio,Asynchronous block I/O>>
32 - <<hooks,Loop hooks>>
33 - <<process,Child processes>>
34 - <<signal,Synchronous delivery of signals>>
35
36 [[contexts]]
37 Simple use
38 ----------
39
40 Simple programs usually employ the main loop in a straightforward way:
41
42 - Call @main_init() to initialize the main loop machinery.
43 - Add an initial set of event handers (@file_add(), @timer_add(), etc.).
44 - Enter the event loop by calling @main_loop(). This function runs for
45   the rest of the lifetime of the program. It watches for events and
46   handles them by calling the appropriate handler functions. These functions
47   can of course add new events or modify/delete the existing ones.
48 - When the program decides it wants to stop, it calls @main_shut_down(),
49   or alternatively it returns <<enum_main_hook_return,`HOOK_SHUTDOWN`>> from some hook functions.
50   Soon after that, @main_loop() returns.
51 - Remove all event hooks and call @main_cleanup().
52
53 The event structures (like <<struct_main_file,`struct main_file`>>) are
54 always allocated by the user, but please touch only the fields marked
55 in this documentation with `[*]`. The other fields are used internally;
56 you should initialize them to zeroes before adding the event and avoid
57 accessing them afterwards.
58
59 [[contexts]]
60 Using multiple contexts
61 -----------------------
62
63 In a more complex program, it can be useful to keep several sets of events
64 and run a separate instance of the event loop for each such set. A typical
65 example would be a multi-threaded program or a function which needs to
66 communicate with a network server locally, ignoring all other events
67 before the operation is finished.
68
69 For such cases, you can create multiple instances of <<struct_main_context,`struct main_context`>>
70 by calling @main_new(). Each thread then keeps its own current context,
71 which can be changed by @main_switch_context(). All mainloop functions
72 then either take an explicit pointer to a context or (more typically)
73 they operate on the current context. When you no longer need the context, you
74 can delete it by @main_delete().
75
76 It is even possible to use nested main loops: in a hook called by the
77 top-level instance of @main_loop(), you can switch to a different context,
78 call @main_loop() recursively and when you are done, switch back and return
79 to the top-level loop.
80
81 *CAVEAT:* In the present implementation, only a single context per process
82 can handle process exit events. If you use @process_add() in multiple contexts,
83 it can happen that the current context catches the `SIGCHLD` signal and obtains
84 information about a child process associated with another context, which it does
85 not know how to handle. If you ever need this, please let us know.
86
87 [[threads]]
88 Forking and threading
89 ---------------------
90
91 Using the event loop in a multi-threaded or multi-process program is possible,
92 but it should be done very carefully.
93
94 Multiple threads can use the main loop, but each of them must use a separate
95 context (or contexts).
96
97 When you fork() a child process, either the parent or the child must give up
98 use of each main loop context. The @main_teardown() and @main_destroy() functions
99 can be useful for that. (The reason is that some parts of the main loop context,
100 like file descriptors used internally, become shared between the processes, so
101 the processes could influence each other in crazy ways. You do not want to hunt
102 for such bugs.)
103
104
105
106 !!ucw/mainloop.h