mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-25 23:25:24 +00:00
107 lines
4.4 KiB
HTML
107 lines
4.4 KiB
HTML
|
<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
|
<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 name="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="http://libvirt.org/git/?p=libvirt-media.git;a=blob_plain;f=png/event_loop_simple.png;hb=HEAD"/>
|
||
|
|
||
|
<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 name="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 name="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="http://libvirt.org/git/?p=libvirt-media.git;a=blob_plain;f=png/event_loop_worker.png;hb=HEAD"/>
|
||
|
|
||
|
<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>
|