2 @page tevent_request Chapter 4: Tevent request
3 @section request Tevent request
5 A specific feature of the library is the tevent request API that provides for
6 asynchronous computation and allows much more interconnected working and
7 cooperation among func- tions and events. When working with tevent request it
8 is possible to nest one event under another and handle them bit by bit. This
9 enables the creation of sequences of steps, and provides an opportunity to
10 prepare for all problems which may unexpectedly happen within the different
11 phases. One way or another, subrequests split bigger tasks into smaller ones
12 which allow a clearer view of each task as a whole.
14 @subsection name Naming conventions
16 There is a naming convention which is not obligatory but it is followed in this
19 - Functions triggered before the event happens. These establish a request.
20 - \b foo_send(...) - this function is called first and it includes the
21 creation of tevent request - tevent req structure. It does not block
22 anything, it simply creates a request, sets a callback (foo done) and lets
24 - Functions as a result of event.
25 - \b foo_done(...) - this function contains code providing for handling itself
26 and based upon its results, the request is set either as a done or, if an
27 error occurs, the request is set as a failure.
28 - \b foo_recv(...) - this function contains code which should, if demanded,
29 access the result data and make them further visible. The foo state should
30 be deallocated from memory when the request’s processing is over and
31 therefore all computed data up to this point would be lost.
33 As was already mentioned, specific naming subsumes not only functions but also
36 - \b foo_state - this is a structure. It contains all the data necessary for
37 the asynchronous task.
39 @subsection cr_req Creating a New Asynchronous Request
41 The first step for working asynchronously is the allocation of memory
42 requirements. As in previous cases, the talloc context is required, upon which
43 the asynchronous request will be tied. The next step is the creation of the
47 struct tevent_req* tevent_req_create (TALLOC_CTX *mem_ctx, void **pstate, #type)
50 The pstate is the pointer to the private data. The necessary amount of memory
51 (based on data type) is allocated during this call. Within this same memory
52 area all the data from the asynchronous request that need to be preserved for
53 some time should be kept.
55 <b>Dealing with a lack of memory</b>
57 The verification of the returned pointer against NULL is necessary in order to
58 identify a potential lack of memory. There is a special function which helps
59 with this check tevent_req_nomem().
61 It handles verification both of the talloc memory allocation and of the
62 associated tevent request, and is therefore a very useful function for avoiding
63 unexpected situations. It can easily be used when checking the availability of
64 further memory resources that are required for a tevent request. Imagine an
65 example where additional memory needs arise although no memory resources are
69 bar = talloc(mem_ctx, struct foo);
70 if(tevent_req_nomem (bar, req)) {
75 This code ensures that the variable bar, which contains NULL as a result of the
76 unsuccessful satisfaction of its memory requirements, is noticed, and also that
77 the tevent request req declares it exceeds memory capacity, which implies the
78 impossibility of finishing the request as originally programmed.
81 @subsection fini_req Finishing a Request
83 Marking each request as finished is an essential principle of the tevent
84 library. Without marking the request as completed - either successfully or with
85 an error - the tevent loop could not let the appropriate callback be triggered.
86 It is important to understand that this would be a significant threat, because
87 it is not usually a question of one single function which prints some text on a
88 screen, but rather the request is itself probably just a link in a series of
89 other requests. Stopping one request would stop the others, memory resources
90 would not be freed, file descriptors might remain open, communication via
91 socket could be interrupted, and so on. Therefore it is important to think
92 about finishing requests, either successfully or not, and also to prepare
93 functions for all possible scenarios, so that the the callbacks do not process
94 data that are actually invalid or, even worse, in fact non-existent meaning
95 that a segmentation fault may arise.
98 <li>\b Manually - This is the most common type of finishing request. Calling
99 this function sets the request as a TEVENT_REQ_DONE. This is the only purpose
100 of this function and it should be used when everything went well. Typically it
101 is used within the done functions.
104 void tevent_req_done (struct tevent_req *req)
106 Alternatively, the request can end up being unsuccessful.
108 bool tevent_req_error (struct tevent_req *req, uint64_t error)
111 The second argument takes the number of an error (declared by the programmer,
112 for example in an enumerated variable). The function tevent_req_error() sets
113 the status of the request as a TEVENT_REQ_USER_ERROR and also stores the code
114 of error within the structure so it can be used, for example for debugging. The
115 function returns true, if marking the request as an error was processed with no
116 problem - value error passed to this function is not equal to 1.</li>
119 <b>Setting up a timeout for request</b> - A request can be finished virtually,
120 or if the process takes too much time, it can be timed out. This is considered
121 as an error of the request and it leads to calling callback. In the
122 background, this timeout is set through a time event (described in
123 @subpage tevent_events ) which eventually triggers an operation marking the
124 request as a TEVENT_REQ_TIMED_OUT (can not be considered as successfully
125 finished). In case a time out was already set, this operation will overwrite it
126 with a new time value (so the timeout may be lengthened) and if everything is
127 set properly, it returns true.
130 bool tevent_req_set_endtime(struct tevent_req *req,
131 struct tevent_context *ev,
132 struct timeval endtime);
137 <li><b>Premature Triggering</b> - Imagine a situation in which some part of a
138 nested subrequest ended up with a failure and it is still required to trigger a
139 callback. Such as example might result from lack of memory leading to the
140 impossibility of allocating enough memory requirements for the event to start
141 processing another subrequest, or from a clear intention to skip other
142 procedures and trigger the callback regardless of other progress. In these
143 cases, the function tevent_req_post() is very handy and offers this option.
146 struct tevent_req* tevent_req_post (struct tevent_req *req,
147 struct tevent_context *ev);
150 A request finished in this way does not behave as a time event nor as a file
151 descriptor event but as a immediately scheduled event, and therefore it will be
152 treated according the description laid down in @subpage tevent_events .
157 @section nested Subrequests - Nested Requests
159 To create more complex and interconnected asynchronous operations, it is
160 possible to submerge a request into another and thus create a so-called
161 subrequest. Subrequests are not represented by any other special structure but
162 they are created from tevent_req_create(). This diagram shows the nesting and
163 life time of each request. The table below describes the same in words, and
164 shows the triggering of functions during the application run.
166 <i>Wrapper</i> represents the trigger of the whole cascade of (sub)requests. It
167 may be e.g. a time or file descriptor event, or another request that was
168 created at a specific time by the function tevent_wakeup_send() which is a
169 slightly exceptional method of creating
172 struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
173 struct tevent_context *ev,
174 struct timeval wakeup_time);
177 By calling this function, it is possible to create a tevent request which is
178 actually the return value of this function. In summary, it sets the time value
179 of the tevent request’s creation. While using this function it is necessary to
180 use another function in the subrequest’s callback to check for any problems
181 tevent_wakeup_recv() )
183 @image html tevent_subrequest.png
185 A comprehensive example of nested subrequests can be found in the file
186 echo_server.c. It implements a complete, self-contained echo server with no
187 dependencies but libevent and libtalloc.