docs: Convert 'internals/eventloop' page to rst and move it to 'kbase/internals'

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Peter Krempa 2022-04-05 13:58:56 +02:00
parent 879546fdd4
commit dc57ae6fe1
6 changed files with 88 additions and 110 deletions

View File

@ -154,9 +154,6 @@ Project development
`API extensions <api_extension.html>`__
Adding new public libvirt APIs
`Event loop and worker pool <internals/eventloop.html>`__
Libvirt's event loop and worker pool mode
`RPC protocol & APIs <internals/rpc.html>`__
RPC protocol information and API / dispatch guide

View File

@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h1>Libvirt's event loop</h1>
<ul id="toc"></ul>
<p>
This page describes the event loop approach used in
libvirt. Both server and client.
</p>
<h2><a id="event_loop">Event driven programming</a></h2>
<p>Traditionally, a program simply ran once, then terminated.
This type of program was very common in the early days of
computing, and lacked any form of user interactivity. This is
still used frequently, particularly in small one purpose
programs.</p>
<p>However, that approach is not suitable for all the types
of applications. For instance graphical applications spend
most of their run time waiting for an input from user. Only
after it happened (in our example a button was clicked, a key
pressed, etc.) an event is generated to which they respond
by executing desired function. If generalized, this is how
many long running programs (daemons) work. Even those who are
not waiting for direct user input and have no graphical
interface. Such as Libvirt.</p>
<img alt="event loop" src="../images/event_loop_simple.png"/>
<p>In Libvirt this approach is used in combination with
<code>poll(2)</code> as all the communication with its
clients (and domains it manages too) happens through sockets.
Therefore whenever new client connects, it is given exclusive
file descriptor which is then watched for incoming events,
e.g. messages. </p>
<h2><a id="api">The event loop API</a></h2>
<p>To work with event loop from our code we have plenty of
APIs.</p>
<ul>
<li><code>virEventAddHandle</code>: Registers a
callback for monitoring file handle events.</li>
<li><code>virEventUpdateHandle</code>: Change set of events
monitored file handle is being watched for.</li>
<li><code>virEventRemoveHandle</code>: Unregisters
previously registered file handle so that it is no
longer monitored for any events.</li>
<li><code>virEventAddTimeout</code>: Registers a
callback for timer event.</li>
<li><code>virEventUpdateTimeout</code>: Changes frequency
for a timer.</li>
<li><code>virEventRemoveTimeout</code>: Unregisters
a timer.</li>
</ul>
<p>For more information on these APIs continue reading <a
href="../html/libvirt-libvirt-event.html">here</a>.</p>
<h2><a id="worker_pool">Worker pool</a></h2>
<p>Looking back at the image above we can see one big
limitation. While processing a message event loop is blocked
and for an outside observer unresponsive. This is not
acceptable for Libvirt. Therefore we have came up with the
following solution.</p>
<img alt="event loop" src="../images/event_loop_worker.png"/>
<p>The event loop does only necessary minimum and hand over
message processing to another thread. In fact, there can be
as many processing threads as configured increasing
processing power.</p>
<p>To break this high level description into smaller pieces,
here is what happens when user calls an API:</p>
<ol>
<li>User (or management application) calls a Libvirt API.
Depending on the connection URI, this may or may not
involve server. Well, for the sake of our
demonstration we assume the former.</li>
<li>Remote driver encodes the API among it's arguments
into an <a href="rpc.html">RPC message</a> and sends
it to the server.</li>
<li>Here, server is waiting in <code>poll(2)</code> for
an event, like incoming message.</li>
<li>As soon as the first bytes of message are received,
even loop wakes up and server starts reading the
whole message.</li>
<li>Once fully read, the event loop notifies threads
known as worker threads from which one picks the incoming
message, decodes and process it.</li>
<li>As soon as API execution is finished, a reply is sent
to the client.</li>
</ol>
<p>In case that there's no free worker to process an incoming
message in step 5, message is placed at the end of a message
queue and is processed in next iteration.</p>
</body>
</html>

View File

@ -1,5 +1,4 @@
internals_in_files = [
'eventloop',
'locking',
'rpc',
]

View File

@ -88,3 +88,6 @@ Internals
`Spawning commands <internals/command.html>`__
Spawning commands from libvirt driver code
`Event loop and worker pool <internals/eventloop.html>`__
Libvirt's event loop and worker pool mode

View File

@ -0,0 +1,84 @@
====================
Libvirt's event loop
====================
.. contents::
This page describes the event loop approach used in libvirt. Both server and
client.
Event driven programming
------------------------
Traditionally, a program simply ran once, then terminated. This type of program
was very common in the early days of computing, and lacked any form of user
interactivity. This is still used frequently, particularly in small one purpose
programs.
However, that approach is not suitable for all the types of applications. For
instance graphical applications spend most of their run time waiting for an
input from user. Only after it happened (in our example a button was clicked, a
key pressed, etc.) an event is generated to which they respond by executing
desired function. If generalized, this is how many long running programs
(daemons) work. Even those who are not waiting for direct user input and have no
graphical interface. Such as Libvirt.
.. image:: ../images/event_loop_simple.png
:alt: event loop
In Libvirt this approach is used in combination with ``poll(2)`` as all the
communication with its clients (and domains it manages too) happens through
sockets. Therefore whenever new client connects, it is given exclusive file
descriptor which is then watched for incoming events, e.g. messages.
The event loop API
------------------
To work with event loop from our code we have plenty of APIs.
- ``virEventAddHandle``: Registers a callback for monitoring file handle
events.
- ``virEventUpdateHandle``: Change set of events monitored file handle is being
watched for.
- ``virEventRemoveHandle``: Unregisters previously registered file handle so
that it is no longer monitored for any events.
- ``virEventAddTimeout``: Registers a callback for timer event.
- ``virEventUpdateTimeout``: Changes frequency for a timer.
- ``virEventRemoveTimeout``: Unregisters a timer.
For more information on these APIs continue reading
`here <../html/libvirt-libvirt-event.html>`__.
Worker pool
-----------
Looking back at the image above we can see one big limitation. While processing
a message event loop is blocked and for an outside observer unresponsive. This
is not acceptable for Libvirt. Therefore we have came up with the following
solution.
.. image:: ../images/event_loop_worker.png
:alt: event loop
The event loop does only necessary minimum and hand over message processing to
another thread. In fact, there can be as many processing threads as configured
increasing processing power.
To break this high level description into smaller pieces, here is what happens
when user calls an API:
#. User (or management application) calls a Libvirt API. Depending on the
connection URI, this may or may not involve server. Well, for the sake of our
demonstration we assume the former.
#. Remote driver encodes the API among it's arguments into an `RPC
message <rpc.html>`__ and sends it to the server.
#. Here, server is waiting in ``poll(2)`` for an event, like incoming message.
#. As soon as the first bytes of message are received, even loop wakes up and
server starts reading the whole message.
#. Once fully read, the event loop notifies threads known as worker threads from
which one picks the incoming message, decodes and process it.
#. As soon as API execution is finished, a reply is sent to the client.
In case that there's no free worker to process an incoming message in step 5,
message is placed at the end of a message queue and is processed in next
iteration.

View File

@ -1,5 +1,6 @@
docs_kbase_internals_files = [
'command',
'eventloop',
'incremental-backup',
'migration',
]