Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 3 | magnus | 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| 2 | <html><head> |
||
| 3 | <title>liboop: Why?</title> |
||
| 4 | <link rel="stylesheet" type="text/css" href="style.css"> |
||
| 5 | </head><body> |
||
| 6 | |||
| 7 | <h2>Why use liboop?</h2> |
||
| 8 | |||
| 9 | <h4>The problem.</h4> |
||
| 10 | |||
| 11 | Developers often wish to write applications which serve as a mediator between |
||
| 12 | several logical interfaces simultaneously; in fact, most applications work |
||
| 13 | this way. For example, a browser application might wish to maintain a user |
||
| 14 | interface while also managing a network connection and occasionally exchanging |
||
| 15 | data with the local filesystem. A server application might be communicating |
||
| 16 | with several clients at once while also occasionally receiving a signal from |
||
| 17 | the administrator directing it to reload its configuration. A multiplayer game |
||
| 18 | might want to maintain several active user interfaces at once. |
||
| 19 | <p> |
||
| 20 | Furthermore, each of these interfaces may be quite complex, sufficiently so to |
||
| 21 | merit shared code modules which specialize in managing the interface. |
||
| 22 | Widget sets deal with the details of the X protocol and graphical user |
||
| 23 | interface management; "curses" deals with the arcana of character-based |
||
| 24 | terminals; WWW libraries offer high-level access to whole families of Internet |
||
| 25 | transfer protocols; standard I/O and database routines manage filesystem data. |
||
| 26 | <p> |
||
| 27 | However, the existing techniques available for multiplexing interface code are |
||
| 28 | very poor. Most of these libraries work in "blocking" fashion; once |
||
| 29 | instructed to complete a task (such as downloading a file, or presenting a |
||
| 30 | dialog to the user), they do not return until the task is complete (or failed), |
||
| 31 | even though this may mean waiting an arbitrary amount of time for some external |
||
| 32 | agent (such as the user or the network) to respond. Some of the better systems |
||
| 33 | are able to manage several concurrent tasks internally, but cannot work with |
||
| 34 | other components. |
||
| 35 | <p> |
||
| 36 | Developers are thus left with several unpalatable choices: |
||
| 37 | <ol> |
||
| 38 | <li>Accept "blocking" operation. User interfaces stop functioning while the |
||
| 39 | application waits for the network; one network client's access is stalled |
||
| 40 | while another client performs a transaction. As more data moves from local |
||
| 41 | storage (where access is fast enough that blocking is acceptable) to |
||
| 42 | delay-prone networked media, this is becoming less and less acceptable. |
||
| 43 | <li>Use multiple threads for concurrency. While this is a good solution for |
||
| 44 | some problems, developers who choose this route must struggle with relatively |
||
| 45 | immature and unportable threading models, and deal with the many libraries |
||
| 46 | which are not thread-safe; furthermore, threaded programming requires |
||
| 47 | thought-intensive and error-prone synchronization. |
||
| 48 | <li>Use multiple processes ("forking") for concurrency. This can also work, |
||
| 49 | but requires all communication between modules to use some form of |
||
| 50 | inter-process communication, which increases complexity and decreases |
||
| 51 | performance. Forking itself is a slow operation, leading to complex |
||
| 52 | "pre-forking" schemes for better performance. Worst of all, each process |
||
| 53 | must somehow multiplex IPC from other processes with whatever I/O task it had |
||
| 54 | to accomplish in the first place; this brings back the very problem forking |
||
| 55 | was designed to address. |
||
| 56 | <li>Attempt to multiplex each library's I/O operations directly in a master |
||
| 57 | "select loop". This requires the developer to understand intimately the |
||
| 58 | exact details of each library's I/O interactions, thus breaking modularity, |
||
| 59 | fostering unhealthy dependency and leading to a single central snarl through |
||
| 60 | which all I/O must pass. |
||
| 61 | </ol> |
||
| 62 | The paucity of options is reflected in the quality of applications. How many |
||
| 63 | programs hang unpleasantly while performing simple network operations like |
||
| 64 | hostname resolution? How many user interfaces are unnecessarily "modal"? |
||
| 65 | How many simple servers fork for no good reason? How many network applications |
||
| 66 | simply don't exist because it's so difficult to write them? |
||
| 67 | |||
| 68 | <h4>The solution.</h4> |
||
| 69 | |||
| 70 | Liboop offers a single, simple, central event loop. Modules wishing to perform |
||
| 71 | I/O without blocking request <em>callbacks</em> from the central <em>event |
||
| 72 | source</em>. These callbacks may be tied to file-descriptor activity, the |
||
| 73 | system time, or process signals. Liboop is responsible for invoking these |
||
| 74 | callbacks as appropriate. |
||
| 75 | <p> |
||
| 76 | With this system, each module "owns" its own I/O; it can perform arbitrarily |
||
| 77 | complex operations without blocking anything else in the program. But since |
||
| 78 | callbacks are executed purely sequentially, there is no complex concurrent code |
||
| 79 | to manage. From the application developer's point of view, working with liboop |
||
| 80 | is very simple; the developer simply makes calls to libraries which work their |
||
| 81 | magic and call the application back when they finish. Applications can easily |
||
| 82 | manage an arbitrary amount of multiplexed I/O operations using as many |
||
| 83 | interface libraries as they like without blocking. |
||
| 84 | <p> |
||
| 85 | To work with this system, libraries and applications must be liboop-aware. |
||
| 86 | Development with legacy code uses <em>adapters</em> which translate the I/O |
||
| 87 | model of an application or library into liboop's model. This does require |
||
| 88 | knowledge of the code's I/O structure, but can at least keep the modules in |
||
| 89 | an application independent of each other. |
||
| 90 | <p> |
||
| 91 | For more about liboop, see the <a href="how">documentation</a>. |
||
| 92 | |||
| 93 | <h4>Q&A</h4> |
||
| 94 | |||
| 95 | <dl> |
||
| 96 | <dt><em>Why don't you just use (favorite widget set), which lets you register |
||
| 97 | callbacks on file descriptors and all that good stuff?</em> |
||
| 98 | <dd>Because not everyone might want to be tied to that widget set. In |
||
| 99 | particular, the developer of a general-purpose I/O library would want to |
||
| 100 | allow everyone to use it, without requiring a particular widget set. |
||
| 101 | Liboop lets the library developer write to a standard interface, |
||
| 102 | which can then be used with most widget sets and other event loops.<p> |
||
| 103 | |||
| 104 | <a name="glib"></a> |
||
| 105 | <dt><em>Doesn't GLib's <a |
||
| 106 | href="http://developer.gnome.org/doc/API/glib/glib-the-main-event-loop.html">Main |
||
| 107 | Event Loop</a> do all this, and more?</em> |
||
| 108 | <dd>Not quite. GLib is a fine implementation of an event loop (with |
||
| 109 | bells and whistles) that supports some extensibility (such as the ability to |
||
| 110 | add extra sources). However, I'm doubtful that it extends far enough that |
||
| 111 | it could run on top of someone else's event loop (such as the Tk event loop). |
||
| 112 | Furthermore, the GLib event loop doesn't manage signals; synchronous handling |
||
| 113 | of asynchronous signals is very difficult to do properly and safely in most |
||
| 114 | existing systems (without kludges like polling). |
||
| 115 | |||
| 116 | <p>In any case, we do have a |
||
| 117 | <a href="oop_glib">GLib source adapter</a> so you can use the GLib event loop |
||
| 118 | with the liboop interface.</p> |
||
| 119 | |||
| 120 | <dt><em>How does liboop compare to Niels Provos' <a |
||
| 121 | href="http://www.monkey.org/~provos/libevent/">libevent</a>?</em> |
||
| 122 | <dd>Like GLib, libevent is a concrete implementation of an event loop, not |
||
| 123 | an abstract interface for many event loops; also like GLib, libevent does not |
||
| 124 | manage signals. Libevent is smaller and simpler than either liboop or Glib. |
||
| 125 | While liboop and GLib are both licensed under the |
||
| 126 | <a href="http://www.fsf.org/copyleft/lesser.html">Lesser GPL</a>, libevent |
||
| 127 | appears to be licensed under the original BSD license, including the |
||
| 128 | advertising clause. Note that the advertising clause renders libevent |
||
| 129 | incompatible with GPL software! |
||
| 130 | |||
| 131 | <p>It is entirely possible to imagine a libevent source adapter for liboop. |
||
| 132 | If anyone is interested in such an adapter, please contact me.</p> |
||
| 133 | |||
| 134 | </dl> |
||
| 135 | |||
| 136 | <hr><a href="">liboop home</a></body></html> |