Blame | Last modification | View Log | RSS feed
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>liboop: Why?</title><link rel="stylesheet" type="text/css" href="style.css"></head><body><h2>Why use liboop?</h2><h4>The problem.</h4>Developers often wish to write applications which serve as a mediator betweenseveral logical interfaces simultaneously; in fact, most applications workthis way. For example, a browser application might wish to maintain a userinterface while also managing a network connection and occasionally exchangingdata with the local filesystem. A server application might be communicatingwith several clients at once while also occasionally receiving a signal fromthe administrator directing it to reload its configuration. A multiplayer gamemight want to maintain several active user interfaces at once.<p>Furthermore, each of these interfaces may be quite complex, sufficiently so tomerit shared code modules which specialize in managing the interface.Widget sets deal with the details of the X protocol and graphical userinterface management; "curses" deals with the arcana of character-basedterminals; WWW libraries offer high-level access to whole families of Internettransfer protocols; standard I/O and database routines manage filesystem data.<p>However, the existing techniques available for multiplexing interface code arevery poor. Most of these libraries work in "blocking" fashion; onceinstructed to complete a task (such as downloading a file, or presenting adialog to the user), they do not return until the task is complete (or failed),even though this may mean waiting an arbitrary amount of time for some externalagent (such as the user or the network) to respond. Some of the better systemsare able to manage several concurrent tasks internally, but cannot work withother components.<p>Developers are thus left with several unpalatable choices:<ol><li>Accept "blocking" operation. User interfaces stop functioning while theapplication waits for the network; one network client's access is stalledwhile another client performs a transaction. As more data moves from localstorage (where access is fast enough that blocking is acceptable) todelay-prone networked media, this is becoming less and less acceptable.<li>Use multiple threads for concurrency. While this is a good solution forsome problems, developers who choose this route must struggle with relativelyimmature and unportable threading models, and deal with the many librarieswhich are not thread-safe; furthermore, threaded programming requiresthought-intensive and error-prone synchronization.<li>Use multiple processes ("forking") for concurrency. This can also work,but requires all communication between modules to use some form ofinter-process communication, which increases complexity and decreasesperformance. Forking itself is a slow operation, leading to complex"pre-forking" schemes for better performance. Worst of all, each processmust somehow multiplex IPC from other processes with whatever I/O task it hadto accomplish in the first place; this brings back the very problem forkingwas designed to address.<li>Attempt to multiplex each library's I/O operations directly in a master"select loop". This requires the developer to understand intimately theexact details of each library's I/O interactions, thus breaking modularity,fostering unhealthy dependency and leading to a single central snarl throughwhich all I/O must pass.</ol>The paucity of options is reflected in the quality of applications. How manyprograms hang unpleasantly while performing simple network operations likehostname resolution? How many user interfaces are unnecessarily "modal"?How many simple servers fork for no good reason? How many network applicationssimply don't exist because it's so difficult to write them?<h4>The solution.</h4>Liboop offers a single, simple, central event loop. Modules wishing to performI/O without blocking request <em>callbacks</em> from the central <em>eventsource</em>. These callbacks may be tied to file-descriptor activity, thesystem time, or process signals. Liboop is responsible for invoking thesecallbacks as appropriate.<p>With this system, each module "owns" its own I/O; it can perform arbitrarilycomplex operations without blocking anything else in the program. But sincecallbacks are executed purely sequentially, there is no complex concurrent codeto manage. From the application developer's point of view, working with liboopis very simple; the developer simply makes calls to libraries which work theirmagic and call the application back when they finish. Applications can easilymanage an arbitrary amount of multiplexed I/O operations using as manyinterface libraries as they like without blocking.<p>To work with this system, libraries and applications must be liboop-aware.Development with legacy code uses <em>adapters</em> which translate the I/Omodel of an application or library into liboop's model. This does requireknowledge of the code's I/O structure, but can at least keep the modules inan application independent of each other.<p>For more about liboop, see the <a href="how">documentation</a>.<h4>Q&A</h4><dl><dt><em>Why don't you just use (favorite widget set), which lets you registercallbacks on file descriptors and all that good stuff?</em><dd>Because not everyone might want to be tied to that widget set. Inparticular, the developer of a general-purpose I/O library would want toallow everyone to use it, without requiring a particular widget set.Liboop lets the library developer write to a standard interface,which can then be used with most widget sets and other event loops.<p><a name="glib"></a><dt><em>Doesn't GLib's <ahref="http://developer.gnome.org/doc/API/glib/glib-the-main-event-loop.html">MainEvent Loop</a> do all this, and more?</em><dd>Not quite. GLib is a fine implementation of an event loop (withbells and whistles) that supports some extensibility (such as the ability toadd extra sources). However, I'm doubtful that it extends far enough thatit could run on top of someone else's event loop (such as the Tk event loop).Furthermore, the GLib event loop doesn't manage signals; synchronous handlingof asynchronous signals is very difficult to do properly and safely in mostexisting systems (without kludges like polling).<p>In any case, we do have a<a href="oop_glib">GLib source adapter</a> so you can use the GLib event loopwith the liboop interface.</p><dt><em>How does liboop compare to Niels Provos' <ahref="http://www.monkey.org/~provos/libevent/">libevent</a>?</em><dd>Like GLib, libevent is a concrete implementation of an event loop, notan abstract interface for many event loops; also like GLib, libevent does notmanage signals. Libevent is smaller and simpler than either liboop or Glib.While liboop and GLib are both licensed under the<a href="http://www.fsf.org/copyleft/lesser.html">Lesser GPL</a>, libeventappears to be licensed under the original BSD license, including theadvertising clause. Note that the advertising clause renders libeventincompatible with GPL software!<p>It is entirely possible to imagine a libevent source adapter for liboop.If anyone is interested in such an adapter, please contact me.</p></dl><hr><a href="">liboop home</a></body></html>