Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- docs/docs.rst | 3 - docs/internals/eventloop.html.in | 106 ----------------------------- docs/internals/meson.build | 1 - docs/kbase/index.rst | 3 + docs/kbase/internals/eventloop.rst | 84 +++++++++++++++++++++++ docs/kbase/internals/meson.build | 1 + 6 files changed, 88 insertions(+), 110 deletions(-) delete mode 100644 docs/internals/eventloop.html.in create mode 100644 docs/kbase/internals/eventloop.rst diff --git a/docs/docs.rst b/docs/docs.rst index a92c7c26ab..4496206d6a 100644 --- a/docs/docs.rst +++ b/docs/docs.rst @@ -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 diff --git a/docs/internals/eventloop.html.in b/docs/internals/eventloop.html.in deleted file mode 100644 index 1a24254fc5..0000000000 --- a/docs/internals/eventloop.html.in +++ /dev/null @@ -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> diff --git a/docs/internals/meson.build b/docs/internals/meson.build index e5f4bb0a4b..5baf444bf9 100644 --- a/docs/internals/meson.build +++ b/docs/internals/meson.build @@ -1,5 +1,4 @@ internals_in_files = [ - 'eventloop', 'locking', 'rpc', ] diff --git a/docs/kbase/index.rst b/docs/kbase/index.rst index 01ec5a070d..47cfc0505c 100644 --- a/docs/kbase/index.rst +++ b/docs/kbase/index.rst @@ -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 diff --git a/docs/kbase/internals/eventloop.rst b/docs/kbase/internals/eventloop.rst new file mode 100644 index 0000000000..f25e97ab14 --- /dev/null +++ b/docs/kbase/internals/eventloop.rst @@ -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. diff --git a/docs/kbase/internals/meson.build b/docs/kbase/internals/meson.build index 3486b21852..5f61f5dba4 100644 --- a/docs/kbase/internals/meson.build +++ b/docs/kbase/internals/meson.build @@ -1,5 +1,6 @@ docs_kbase_internals_files = [ 'command', + 'eventloop', 'incremental-backup', 'migration', ] -- 2.35.1