summaryrefslogtreecommitdiffstats
path: root/doc/tevent_request.dox
diff options
context:
space:
mode:
Diffstat (limited to 'doc/tevent_request.dox')
-rw-r--r--doc/tevent_request.dox189
1 files changed, 189 insertions, 0 deletions
diff --git a/doc/tevent_request.dox b/doc/tevent_request.dox
new file mode 100644
index 0000000..bda6f76
--- /dev/null
+++ b/doc/tevent_request.dox
@@ -0,0 +1,189 @@
+/**
+@page tevent_request Chapter 4: Tevent request
+@section request Tevent request
+
+A specific feature of the library is the tevent request API that provides for
+asynchronous computation and allows much more interconnected working and
+cooperation among functions and events. When working with tevent request it
+is possible to nest one event under another and handle them bit by bit. This
+enables the creation of sequences of steps, and provides an opportunity to
+prepare for all problems which may unexpectedly happen within the different
+phases. One way or another, subrequests split bigger tasks into smaller ones
+which allow a clearer view of each task as a whole.
+
+@subsection name Naming conventions
+
+There is a naming convention which is not obligatory but it is followed in this
+tutorial:
+
+- Functions triggered before the event happens. These establish a request.
+- \b foo_send(...) - this function is called first and it includes the
+ creation of tevent request - tevent req structure. It does not block
+ anything, it simply creates a request, sets a callback (foo done) and lets
+ the program continue
+- Functions as a result of event.
+- \b foo_done(...) - this function contains code providing for handling itself
+ and based upon its results, the request is set either as a done or, if an
+ error occurs, the request is set as a failure.
+- \b foo_recv(...) - this function contains code which should, if demanded,
+ access the result data and make them further visible. The foo state should
+ be deallocated from memory when the request’s processing is over and
+ therefore all computed data up to this point would be lost.
+
+As was already mentioned, specific naming subsumes not only functions but also
+the data themselves:
+
+- \b foo_state - this is a structure. It contains all the data necessary for
+ the asynchronous task.
+
+@subsection cr_req Creating a New Asynchronous Request
+
+The first step for working asynchronously is the allocation of memory
+requirements. As in previous cases, the talloc context is required, upon which
+the asynchronous request will be tied. The next step is the creation of the
+request itself.
+
+@code
+struct tevent_req* tevent_req_create (TALLOC_CTX *mem_ctx, void **pstate, #type)
+@endcode
+
+The pstate is the pointer to the private data. The necessary amount of memory
+(based on data type) is allocated during this call. Within this same memory
+area all the data from the asynchronous request that need to be preserved for
+some time should be kept.
+
+<b>Dealing with a lack of memory</b>
+
+The verification of the returned pointer against NULL is necessary in order to
+identify a potential lack of memory. There is a special function which helps
+with this check tevent_req_nomem().
+
+It handles verification both of the talloc memory allocation and of the
+associated tevent request, and is therefore a very useful function for avoiding
+unexpected situations. It can easily be used when checking the availability of
+further memory resources that are required for a tevent request. Imagine an
+example where additional memory needs arise although no memory resources are
+currently available.
+
+@code
+bar = talloc(mem_ctx, struct foo);
+if(tevent_req_nomem (bar, req)) {
+ // handling a problem
+}
+@endcode
+
+This code ensures that the variable bar, which contains NULL as a result of the
+unsuccessful satisfaction of its memory requirements, is noticed, and also that
+the tevent request req declares it exceeds memory capacity, which implies the
+impossibility of finishing the request as originally programmed.
+
+
+@subsection fini_req Finishing a Request
+
+Marking each request as finished is an essential principle of the tevent
+library. Without marking the request as completed - either successfully or with
+an error - the tevent loop could not let the appropriate callback be triggered.
+It is important to understand that this would be a significant threat, because
+it is not usually a question of one single function which prints some text on a
+screen, but rather the request is itself probably just a link in a series of
+other requests. Stopping one request would stop the others, memory resources
+would not be freed, file descriptors might remain open, communication via
+socket could be interrupted, and so on. Therefore it is important to think
+about finishing requests, either successfully or not, and also to prepare
+functions for all possible scenarios, so that the the callbacks do not process
+data that are actually invalid or, even worse, in fact non-existent meaning
+that a segmentation fault may arise.
+
+<ul>
+<li>\b Manually - This is the most common type of finishing request. Calling
+this function sets the request as a TEVENT_REQ_DONE. This is the only purpose
+of this function and it should be used when everything went well. Typically it
+is used within the done functions.
+
+@code
+void tevent_req_done (struct tevent_req *req)
+@endcode
+Alternatively, the request can end up being unsuccessful.
+@code
+bool tevent_req_error (struct tevent_req *req, uint64_t error)
+@endcode
+
+The second argument takes the number of an error (declared by the programmer,
+for example in an enumerated variable). The function tevent_req_error() sets
+the status of the request as a TEVENT_REQ_USER_ERROR and also stores the code
+of error within the structure so it can be used, for example for debugging. The
+function returns true, if marking the request as an error was processed with no
+problem - value error passed to this function is not equal to 1.</li>
+
+<li>
+<b>Setting up a timeout for request</b> - A request can be finished virtually,
+or if the process takes too much time, it can be timed out. This is considered
+as an error of the request and it leads to calling callback. In the
+background, this timeout is set through a time event (described in
+@subpage tevent_events ) which eventually triggers an operation marking the
+request as a TEVENT_REQ_TIMED_OUT (can not be considered as successfully
+finished). In case a time out was already set, this operation will overwrite it
+with a new time value (so the timeout may be lengthened) and if everything is
+set properly, it returns true.
+
+@code
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime);
+@endcode
+</li>
+
+
+<li><b>Premature Triggering</b> - Imagine a situation in which some part of a
+nested subrequest ended up with a failure and it is still required to trigger a
+callback. Such as example might result from lack of memory leading to the
+impossibility of allocating enough memory requirements for the event to start
+processing another subrequest, or from a clear intention to skip other
+procedures and trigger the callback regardless of other progress. In these
+cases, the function tevent_req_post() is very handy and offers this option.
+
+@code
+struct tevent_req* tevent_req_post (struct tevent_req *req,
+ struct tevent_context *ev);
+@endcode
+
+A request finished in this way does not behave as a time event nor as a file
+descriptor event but as a immediately scheduled event, and therefore it will be
+treated according the description laid down in @subpage tevent_events .
+</li>
+</ul>
+
+
+@section nested Subrequests - Nested Requests
+
+To create more complex and interconnected asynchronous operations, it is
+possible to submerge a request into another and thus create a so-called
+subrequest. Subrequests are not represented by any other special structure but
+they are created from tevent_req_create(). This diagram shows the nesting and
+life time of each request. The table below describes the same in words, and
+shows the triggering of functions during the application run.
+
+<i>Wrapper</i> represents the trigger of the whole cascade of (sub)requests. It
+may be e.g. a time or file descriptor event, or another request that was
+created at a specific time by the function tevent_wakeup_send() which is a
+slightly exceptional method of creating
+
+@code
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time);
+@endcode
+
+By calling this function, it is possible to create a tevent request which is
+actually the return value of this function. In summary, it sets the time value
+of the tevent request’s creation. While using this function it is necessary to
+use another function in the subrequest’s callback to check for any problems
+tevent_wakeup_recv() )
+
+@image html tevent_subrequest.png
+
+A comprehensive example of nested subrequests can be found in the file
+echo_server.c. It implements a complete, self-contained echo server with no
+dependencies but libtevent and libtalloc.
+
+*/