1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en" />
<title>s6: libftrig</title>
<meta name="Description" content="s6 libftrig" />
<meta name="Keywords" content="s6 libftrig" />
<!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
</head>
<body>
<p>
<a href="index.html">s6</a><br />
<a href="//skarnet.org/software/">Software</a><br />
<a href="//skarnet.org/">skarnet.org</a>
</p>
<h1> libftrig </h1>
<p>
<tt>libftrig</tt> is a portable Unix C programming interface allowing a
process (the <em>subscriber</em> or <em>listener</em>) to be instantly
notified when another process (the <em>notifier</em> or <em>writer</em>)
signals an event.
</p>
<a name="notification">
<h2> What is notification ? </h2>
</a>
<h3> Notification vs. polling </h3>
<p>
Process A is <em>notified</em> of an event E when it gets a instant
notice that event E has happened; the notice may disrupt A's execution
flow. Notification is the opposite of <em>polling</em>, where A has to
periodically (every T milliseconds) check whether E happened and has no
other way to be informed of it.
</p>
<p>
Polling is generally considered bad practice - and is inferior to
notification in practically every case - for three reasons:
</p>
<ul>
<li> Reaction time. When event E happens, process A does not know it
instantly. It will only learn of E, and be able to react to it, when
it explicitly checks for E; and if E happened right after A performed
the check, this can take as long as T milliseconds (the <em>polling
period</em>). Polling processes have reaction delays due to the polling
periods. </li>
<li> Resource consumption. Even if <em>no</em> event ever happens, process A
will still wake up needlessly every T milliseconds. This might not seem like
a problem, but it is a serious one in energy-critical environments. Polling
processes use more CPU time than is necessary and are not energy-friendly. </li>
<li> Conflict between the two above reasons. The longer the polling period,
the more energy-friendly the process, but the longer the reaction time. The
shorter the polling period, the shorter the reaction time, but the more
resource-consuming the process. A delicate balance has to be found, and
acceptable behaviour is different in every case, so there's no general rule
of optimization. </li>
</ul>
<p>
Notification, on the other hand, is generally optimal: reaction time is
zero, and resource consumption is minimal - a process can sleep as soon as
it's not handling an event, and only wake up when needed.
</p>
<p>
Of course, the problem of notification is that it's often more difficult
to implement. Notification frameworks are generally more complex, involving
lots of asynchronism; polling is widely used
<a href="https://lib.store.yahoo.net/lib/demotivators/mediocritydemotivationalposter.jpg">because
it's easy.</a>
</p>
<h3> Notifications and Unix </h3>
<p>
Unix provides several frameworks so that a process B (or the kernel) can
notify process A.
</p>
<ul>
<li> Signals. The simplest Unix notification mechanism. Sending events amounts
to a <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html">kill()</a>
call, and receiving events amounts to installing a signal handler (preferably
using a <a href="//skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a>
if mixing signals with an event loop). Unfortunately, Unix signals, even the more
recent and powerful real-time POSIX signals, have important limitations when it's
about generic notification:
<ul>
<li> non-root processes can only send signals to a very restricted and
implementation-dependent set of processes (roughly, processes with the same UID). This is a problem when
designing secure programs that make use of the Unix privilege separation. </li>
<li> you need to know the PID of a process to send it signals. This is generally
impractical; process management systems that do not use supervisor processes have
to do exactly that, and they resort to unreliable, ugly hacks (.pid files) to track
down process PIDs. </li>
</ul> </li>
<li> BSD-style IPCs, i.e. file descriptors to perform select()/poll() system
calls on, in an <em>asynchronous event loop</em>. This mechanism is very widely used,
and rightly so, because it's extremely generic and works in every ordinary situation;
you have to be doing <a href="http://www.kegel.com/c10k.html">very specific stuff</a>
to reach its limits. If process A is reading on
fd <em>f</em>, it is notified everytime another process makes <em>f</em> readable -
for instance by writing a byte to the other end if <em>f</em> is the reading end
of a pipe. And indeed, this is how libftrig works internally; but libftrig is needed
because direct use of BSD-style IPCs also has limitations.
<ul>
<li> Anonymous pipes are the simplest and most common BSD-style IPC. If there is a
pipe from process B to process A, then B can notify A by writing to the pipe. The
limitation is that A and B must have a common ancestor that created the pipe; two
unrelated processes cannot communicate this way. </li>
<li> Sockets are a good many-to-one notification system: once a server is up, it
can be notified by any client, and notify all its clients. The limitation of sockets
is that the server must be up before the client, which prevents us from using them
in a general notification scheme. </li>
</ul> </li>
<li> System V IPCs, i.e. message queues and semaphores. The interfaces to those IPCs
are quite specific and can't mix with select/poll loops, that's why nobody in their
right mind uses them. </li>
</ul>
<h3> What we want </h3>
<p>
We need a general framework to:
</p>
<ul>
<li> Allow an event-generating process to broadcast notifications to every process
that asked for one, without having to know their PIDs </li>
<li> Allow a process to subscribe to a "notification channel" and be instantly,
asynchronously notified when an event occurs on this channel. </li>
</ul>
<p>
This requires a many-to-many approach that Unix does not provide natively, and
that is what libftrig does.
</p>
<a name="bus">
<h2> That's what a bus is for. D-Bus already does all this. </h2>
</a>
<p>
Yes, a bus is a good many-to-many notification mechanism indeed. However,
a Unix bus can only be implemented via a daemon - you need a long-running
process, i.e. a <em>service</em>, to implement a bus. And s6 is a
<em>supervision suite</em>, i.e. a set of programs designed to manage
services; we would like to be able to use notifications in the supervision
suite, to be able to wait for a service to be up or down... <em>without</em>
relying on a particular service to be up. libftrig provides a notification
mechanism that <em>does not need</em> a bus service to be up, that's its
main advantage over a bus.
</p>
<p>
If you are not concerned with supervision and can depend on a bus service,
though, then yes, by all means, use a bus for your notification needs.
There is a <a href="//skarnet.org/software/skabus/">skabus</a>
project in the making, which aims to be simpler, smaller and more
maintainable than D-Bus.
</p>
<h2> How to use libftrig </h2>
<p>
<tt>libftrig</tt> is really a part of <a href="libs6/">libs6</a>: all the functions
are implemented in the <tt>libs6.a</tt> archive, or the <tt>libs6.so</tt>
dynamic shared object. However, the interfaces are different for notifiers
and listeners:
</p>
<ul>
<li> Notifiers use the <a href="libs6/ftrigw.html">ftrigw</a> interface. </li>
<li> Listeners use the <a href="libs6/ftrigr.html">ftrigr</a> interface. </li>
</ul>
</body>
</html>
|