diff -ur gambc40b14/configure.ac gambc40b14.new/configure.ac
--- gambc40b14/configure.ac	2005-07-14 08:28:50.000000000 +0100
+++ gambc40b14.new/configure.ac	2005-08-19 14:27:17.668415996 +0100
@@ -232,6 +232,21 @@
 
 ###############################################################################
 #
+# Check if libevent should be used
+
+AC_ARG_ENABLE(libevent,
+              AC_HELP_STRING([--enable-libevent],
+                             [use libevent for faster IO on platforms which support it (default is NO)]),
+              ENABLE_LIBEVENT=$enableval,
+              ENABLE_LIBEVENT=no)
+
+if test "$ENABLE_LIBEVENT" = yes; then
+  AC_DEFINE(LIBEVENT)
+  AC_SEARCH_LIBS(event_abilities, event)
+fi
+
+###############################################################################
+#
 # Check if a shared library must be built.
 
 AC_ARG_ENABLE(shared,
diff -ur gambc40b14/include/config.h.in gambc40b14.new/include/config.h.in
--- gambc40b14/include/config.h.in	2005-01-04 16:47:42.000000000 +0000
+++ gambc40b14.new/include/config.h.in	2005-08-19 14:27:47.596514964 +0100
@@ -25,6 +25,9 @@
 /* Define as 1 if you want to compile as a shared library.  */
 #undef ___SHARED
 
+/* Define asd 1 if you want to use libevent */
+#undef LIBEVENT
+
 /* Define appropriately if "void*" is not the same width as "long".  */
 #undef ___VOIDSTAR_WIDTH
 
diff -ur gambc40b14/lib/os_io.c gambc40b14.new/lib/os_io.c
--- gambc40b14/lib/os_io.c	2005-07-13 22:12:17.000000000 +0100
+++ gambc40b14.new/lib/os_io.c	2005-08-19 14:27:20.532851205 +0100
@@ -18,6 +18,10 @@
 #include "setup.h"
 #include "c_intf.h"
 
+#ifdef LIBEVENT
+#include <event.h>
+#endif
+
 /*---------------------------------------------------------------------------*/
 
 
@@ -694,6 +698,101 @@
 
 /* Generic device operations. */
 
+/* Event handling in Gambit:
+ *
+ * When using select or Win32 APIs the following function (___device_select)
+ * is passed an array of device structs. The first nb_read_devs of these are
+ * waiting for read events and the rest are waiting for writes. This function
+ * performs a virtual call on each one (there's a table of function pointers
+ * in the struct) and those calls callback zero of more helper functions,
+ * below. These set events in the select bitmaps (or Win32 equiv) or update
+ * the timeout value. (___device_select_add_timeout, ___device_select_add_fd).
+ *
+ * A select is then performed on those values and then a second pass is made on
+ * each device. This uses the same virtual function call, but sets a flag to 
+ * indicate that the device should check the select bitmaps for interesting
+ * events. If the device considers itself ready it sets it's pointer in the
+ * devs struct to NULL.
+ *
+ * These NULL values are picked up in ___os_condvar_select. See the comments
+ * above that function.
+ *
+ * Edge IO
+ * -------
+ *
+ * Modern kernels allow edge triggered IO. See man epoll(4) (on Linux systems,
+ * otherwise google for it) for details on the difference between edge and
+ * level triggered IO.
+ *
+ * Edge io is performed using libevent[1], an abstraction layer which allows
+ * us to use epoll, kqueue (BSD) or (in the future) rt signals. At the time of
+ * writing edge support in libevent requires a small patch and only epoll is
+ * supported.
+ * [1] http://www.monkey.org/~provos
+ *
+ * In edge io mode this function does very little more than call the libevent
+ * dispatch handler. Rather than poll all the devices and ask them to set bits
+ * in a bitmap, the devices are responsible for making libevent calls in order
+ * to register persistant callbacks for fd and timeout events.
+ *
+ * This has several effects:
+ *   With select several devices can be waiting on the same fd since setting
+ *   the bit twice in the bitmap is a nop. However, with libevent the second
+ *   callback will override the first. (however, separate callbacks for read
+ *   and write events are possible).
+ */
+
+#ifdef LIBEVENT
+/* This is the callback function, called by libevent, whenever a device_stream
+ * has an event. */
+static void
+device_stream_event_callback(int fd, short events, void *arg) {
+	___device *d = ___CAST(___device *, arg);
+
+	if (events & EV_READ)  d->read_ready = 1;
+	if (events & EV_WRITE) d->write_ready = 1;
+	if (events & EV_TIMEOUT) {
+		d->read_ready = 1;
+		d->write_ready = 1;
+	}
+}
+#endif
+
+#ifdef LIBEVENT
+
+/* This callback is used for registering a timeout event in ___device_select
+ */
+static void
+null_callback(int fd, short events, void *arg) {}
+
+___SCMOBJ ___device_select
+   ___P((___time timeout),
+        (timeout)
+___time timeout;)
+{
+  if (timeout < 0) {
+	  event_loop(EVLOOP_NONBLOCK);
+  } else if (timeout == ___time_mod.time_pos_infinity) {
+	  event_loop(EVLOOP_ONCE);
+  } else {
+	  ___time delta;
+	  struct timeval tv, *p_tv = &tv;
+	  struct event timeout_event;
+	  
+	  ___absolute_time_to_relative_time(timeout, &delta);
+	  ___absolute_time_to_nonnegative_timeval(delta, &p_tv);
+	  event_set(&timeout_event, -1, EV_TIMEOUT, null_callback, NULL);
+	  event_add(&timeout_event, p_tv);
+
+	  event_loop(EVLOOP_ONCE);
+	  event_del(&timeout_event);
+  }
+	  
+  return ___FIX(___NO_ERR);
+}
+
+#else /* not LIBEVENT */
+
 ___SCMOBJ ___device_select
    ___P((___device **devs,
          int nb_read_devs,
@@ -1054,6 +1153,8 @@
 
 #endif
 
+#endif  /* LIBEVENT */
+
 
 ___SCMOBJ ___device_flush_write
    ___P((___device *self),
@@ -1182,7 +1283,11 @@
         return e;
 
       devs[0] = self;
+	  /* This appears to wait for the device to really close, but there
+	   * seems to be very little point. We can't get any using error
+	   * information from this can we? --agl
       e = ___device_select (devs, 1, 0, ___time_mod.time_pos_infinity);
+	  */
       if (e != ___FIX(___NO_ERR))
         return e;
     }
@@ -1196,7 +1301,9 @@
         return e;
 
       devs[0] = self;
+	  /* see above comments
       e = ___device_select (devs, 0, 1, ___time_mod.time_pos_infinity);
+	  */
       if (e != ___FIX(___NO_ERR))
         return e;
     }
@@ -1221,6 +1328,7 @@
   return ___TIMER_KIND;
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ device_timer_select_virt
    ___P((___device *self,
          ___BOOL for_writing,
@@ -1257,6 +1365,7 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ device_timer_release_virt
    ___P((___device *self),
@@ -1282,6 +1391,9 @@
 ___device *self;
 int direction;)
 {
+#ifdef LIBEVENT
+  event_del(&self->ev);
+#endif
   return ___FIX(___NO_ERR);
 }
 
@@ -1289,7 +1401,9 @@
 {
   {
     device_timer_kind,
+#ifndef LIBEVENT
     device_timer_select_virt,
+#endif
     device_timer_release_virt,
     device_timer_flush_write_virt,
     device_timer_close_virt
@@ -1335,6 +1449,16 @@
 ___device_timer *dev;
 ___time expiry;)
 {
+#ifdef LIBEVENT
+  struct timeval tv, *p_tv = &tv;
+
+  /* Note that this works because of the layout of this device structure
+   * means that it's a perfectly good device_stream as well --agl */
+  ___absolute_time_to_nonnegative_timeval(expiry, &p_tv);
+  event_set(&dev->base.ev, -1, EV_TIMEOUT, device_stream_event_callback, dev);
+  event_add(&dev->base.ev, p_tv);
+#endif
+
   dev->expiry = expiry;
 }
 
@@ -1479,6 +1603,7 @@
 
 #endif
 
+#ifndef LIBEVENT
 ___SCMOBJ ___device_stream_select_virt
    ___P((___device *self,
          ___BOOL for_writing,
@@ -1547,6 +1672,7 @@
             pass,
             state);
 }
+#endif  /* !LIBEVENT */
 
 
 ___SCMOBJ ___device_stream_release_virt
@@ -1916,6 +2042,11 @@
   dev->base.direction = direction;
   dev->base.read_stage = ___STAGE_CLOSED;
   dev->base.write_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+  /* By doing this we make sure that we always catch every event */
+  dev->base.read_ready = 1;
+  dev->base.write_ready = 1;
+#endif
 
 #ifdef USE_PUMPS
   dev->read_pump = NULL;
@@ -1995,6 +2126,10 @@
     pid_t pid;     /* pid of the process */
     int fd_stdin;  /* file descriptor corresponding to process' stdin */
     int fd_stdout; /* file descriptor corresponding to process' stdout */
+#ifdef LIBEVENT
+	/* The struct event in the ___device struct is used for stdin */
+	struct event stdout_event;
+#endif
   } ___device_process;
 
 typedef struct ___device_process_vtbl_struct
@@ -2021,11 +2156,19 @@
   ___device_process *d = ___CAST(___device_process*,self);
   int is_not_closed = 0;
 
-  if (d->base.base.read_stage != ___STAGE_CLOSED)
+  if (d->base.base.read_stage != ___STAGE_CLOSED) {
+#ifdef LIBEVENT
+    d->base.base.read_ready = 0;
+#endif
     is_not_closed |= ___DIRECTION_RD;
+  }
 
-  if (d->base.base.write_stage != ___STAGE_CLOSED)
+  if (d->base.base.write_stage != ___STAGE_CLOSED) {
+#ifdef LIBEVENT
+    d->base.base.write_ready = 0;
+#endif
     is_not_closed |= ___DIRECTION_WR;
+  }
 
   if (is_not_closed == 0)
     return ___FIX(___NO_ERR);
@@ -2035,6 +2178,9 @@
       /* Close process' stdout */
 
       d->base.base.read_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.read_ready = 0;
+#endif
 
       if (close (d->fd_stdout) < 0)
         return err_code_from_errno ();
@@ -2045,6 +2191,9 @@
       /* Close process' stdin */
 
       d->base.base.write_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.write_ready = 0;
+#endif
 
       if (close (d->fd_stdin) < 0)
         return err_code_from_errno ();
@@ -2054,6 +2203,9 @@
       d->base.base.write_stage == ___STAGE_CLOSED)
     {
       int status;
+#ifdef LIBEVENT
+	  event_del(&d->base.base.ev);
+#endif
       if (waitpid (d->pid, &status, 0) < 0)
         return err_code_from_errno ();
     }
@@ -2061,6 +2213,7 @@
   return ___FIX(___NO_ERR);
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_process_select_raw_virt
    ___P((___device_stream *self,
          ___BOOL for_writing,
@@ -2110,6 +2263,7 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ ___device_process_release_raw_virt
    ___P((___device_stream *self),
@@ -2182,10 +2336,16 @@
 #endif
 
       if (errno == EIO) errno = EAGAIN;
+#ifdef LIBEVENT
+	  if (errno == EAGAIN) d->base.base.read_ready = 0;
+#endif
       return err_code_from_errno ();
     }
 
   *len_done = n;
+#ifdef LIBEVENT
+  if (n < len) d->base.base.read_ready = 0;
+#endif
 
   return ___FIX(___NO_ERR);
 }
@@ -2219,11 +2379,17 @@
                errno);
 
 #endif
+#ifdef LIBEVENT
+	  if (errno == EAGAIN) d->base.base.write_ready = 0;
+#endif
 
       return err_code_from_errno ();
     }
 
   *len_done = n;
+#ifdef LIBEVENT
+  if (n < len) d->base.base.write_ready = 0;
+#endif
 
   return ___FIX(___NO_ERR);
 }
@@ -2271,12 +2437,16 @@
   {
     {
       ___device_process_kind,
+#ifndef LIBEVENT
       ___device_stream_select_virt,
+#endif
       ___device_stream_release_virt,
       ___device_stream_flush_write_virt,
       ___device_process_close_virt
     },
+#ifndef LIBEVENT
     ___device_process_select_raw_virt,
+#endif
     ___device_process_release_raw_virt,
     ___device_process_flush_write_raw_virt,
     ___device_process_seek_raw_virt,
@@ -2334,6 +2504,14 @@
   d->pid = pid;
   d->fd_stdin = fd_stdin;
   d->fd_stdout = fd_stdout;
+#ifdef LIBEVENT
+  event_set(&d->base.base.ev, d->fd_stdin, EV_WRITE | EV_EDGE | EV_PERSIST,
+            device_stream_event_callback, &d->base);
+  event_add(&d->base.base.ev, NULL);
+  event_set(&d->stdout_event, d->fd_stdout, EV_READ | EV_EDGE | EV_PERSIST,
+            device_stream_event_callback, &d->base.base);
+  event_add(&d->stdout_event, NULL);
+#endif
 
   *dev = d;
 
@@ -2479,6 +2657,11 @@
 
       d->base.base.read_stage = ___STAGE_CLOSED; /* avoid multiple closes */
       d->base.base.write_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.read_ready = 0;
+	  d->base.base.write_ready = 0;
+	  event_del(&d->base.base.ev);
+#endif
 
 #ifdef USE_WIN32
 
@@ -2502,6 +2685,9 @@
         }
 
       d->base.base.read_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.read_ready = 0;
+#endif
     }
   else if (direction & ___DIRECTION_WR)
     {
@@ -2515,11 +2701,15 @@
         }
 
       d->base.base.write_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.write_ready = 0;
+#endif
     }
 
   return ___FIX(___NO_ERR);
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_tcp_client_select_raw_virt
    ___P((___device_stream *self,
          ___BOOL for_writing,
@@ -2636,6 +2826,20 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
+
+#ifdef LIBEVENT
+___HIDDEN void ___device_tcp_client_timeout
+   ___P((___device_stream *self),
+		   (self)
+___device_stream *self;)
+{
+	___device_tcp_client *d = ___CAST(___device_tcp_client*,self);
+	if (d->try_connect_again) d->try_connect_again = 2;
+	d->base.base.read_ready = 1;
+	d->base.base.write_ready = 1;
+}
+#endif
 
 ___HIDDEN ___SCMOBJ ___device_tcp_client_release_raw_virt
    ___P((___device_stream *self),
@@ -2698,15 +2902,31 @@
         return ERR_CODE_FROM_SOCKET_CALL;
     }
 
-  if (SOCKET_CALL_ERROR(n = recv (d->s, ___CAST(char*,buf), len, 0)))
+#ifdef LIBEVENT
+  if (!d->base.base.read_ready) {
+	  /* If we know that the kernel buffer is almost certainly empty (because
+	   * we just got a short read then we don't bother with another read call
+	   * just to tell us EAGAIN */
+	  errno = EAGAIN;
+	  return ERR_CODE_FROM_SOCKET_CALL;
+  }
+#endif
+
+  if (SOCKET_CALL_ERROR(n = recv (d->s, ___CAST(char*,buf), len, 0))) {
+#ifdef LIBEVENT
+    if (errno == EAGAIN) d->base.base.read_ready = 0;
+#endif
     return ERR_CODE_FROM_SOCKET_CALL;
+  }
 
   *len_done = n;
+#ifdef LIBEVENT
+  if (n < len) d->base.base.read_ready = 0;
+#endif
 
   return ___FIX(___NO_ERR);
 }
 
-
 ___HIDDEN ___SCMOBJ ___device_tcp_client_write_raw_virt
    ___P((___device_stream *self,
          ___U8 *buf,
@@ -2738,15 +2958,31 @@
         return ERR_CODE_FROM_SOCKET_CALL;
     }
 
-  if (SOCKET_CALL_ERROR(n = send (d->s, ___CAST(char*,buf), len, 0)))
+#ifdef LIBEVENT
+  if (!d->base.base.write_ready) {
+	  /* If we know that the kernel buffer is almost certainly full (because
+	   * we just got a short write then we don't bother with another write call
+	   * just to tell us EAGAIN */
+	  errno = EAGAIN;
+	  return ERR_CODE_FROM_SOCKET_CALL;
+  }
+#endif
+
+  if (SOCKET_CALL_ERROR(n = send (d->s, ___CAST(char*,buf), len, 0))) {
+#ifdef LIBEVENT
+    if (errno == EAGAIN) d->base.base.read_ready = 0;
+#endif
     return ERR_CODE_FROM_SOCKET_CALL;
+  }
 
   *len_done = n;
+#ifdef LIBEVENT
+  if (n < len) d->base.base.write_ready = 0;
+#endif
 
   return ___FIX(___NO_ERR);
 }
 
-
 ___HIDDEN ___SCMOBJ ___device_tcp_client_width_virt
    ___P((___device_stream *self),
         (self)
@@ -2791,12 +3027,16 @@
   {
     {
       ___device_tcp_client_kind,
+#ifndef LIBEVENT
       ___device_stream_select_virt,
+#endif
       ___device_stream_release_virt,
       ___device_stream_flush_write_virt,
       ___device_tcp_client_close_virt
     },
+#ifndef LIBEVENT
     ___device_tcp_client_select_raw_virt,
+#endif
     ___device_tcp_client_release_raw_virt,
     ___device_tcp_client_flush_write_raw_virt,
     ___device_tcp_client_seek_raw_virt,
@@ -2886,6 +3126,12 @@
   d->server_addrlen = server_addrlen;
   d->try_connect_again = try_connect_again;
 
+#ifdef LIBEVENT
+  event_set(&d->base.base.ev, s, EV_READ | EV_WRITE | EV_EDGE | EV_PERSIST,
+		  device_stream_event_callback, &d->base);
+  event_add(&d->base.base.ev, NULL);
+#endif
+
 #ifdef USE_WIN32
 
   d->io_event =
@@ -3046,9 +3292,16 @@
         return ERR_CODE_FROM_SOCKET_CALL;
     }
 
+#ifdef LIBEVENT
+  d->base.read_ready = 0;
+  d->base.write_ready = 0;
+  event_del(&d->base.ev);
+#endif
+
   return ___FIX(___NO_ERR);
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_tcp_server_select_virt
    ___P((___device *self,
          ___BOOL for_writing,
@@ -3122,6 +3375,7 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ ___device_tcp_server_release_virt
    ___P((___device *self),
@@ -3143,7 +3397,9 @@
 {
   {
     ___device_tcp_server_kind,
+#ifndef LIBEVENT
     ___device_tcp_server_select_virt,
+#endif
     ___device_tcp_server_release_virt,
     ___device_tcp_server_flush_write_virt,
     ___device_tcp_server_close_virt
@@ -3234,6 +3490,14 @@
   *dev = d;
 
   device_add_to_group (dgroup, &d->base);
+  
+#ifdef LIBEVENT
+  event_set(&d->base.ev, s, EV_READ | EV_WRITE | EV_EDGE | EV_PERSIST,
+		  device_stream_event_callback, &d->base);
+  event_add(&d->base.ev, NULL);
+  d->base.read_ready = 1;
+  d->base.write_ready = 1;
+#endif
 
   return ___FIX(___NO_ERR);
 }
@@ -3261,8 +3525,12 @@
 
   if (SOCKET_CALL_ERROR2(s = accept (dev->s,
                                      ___CAST(struct sockaddr*,&addr),
-                                     &addrlen)))
+                                     &addrlen))) {
+#ifdef LIBEVENT
+    if (errno == EAGAIN) dev->base.read_ready = 0;
+#endif
     return ERR_CODE_FROM_SOCKET_CALL;
+  }
 
   return ___device_tcp_client_setup_from_socket
            (client,
@@ -3340,6 +3608,7 @@
   return ___FIX(___NO_ERR);
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_directory_select_virt
    ___P((___device *self,
          ___BOOL for_writing,
@@ -3369,6 +3638,7 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ ___device_directory_release_virt
    ___P((___device *self),
@@ -3390,7 +3660,9 @@
 {
   {
     ___device_directory_kind,
+#ifndef LIBEVENT
     ___device_directory_select_virt,
+#endif
     ___device_directory_release_virt,
     ___device_directory_flush_write_virt,
     ___device_directory_close_virt
@@ -3667,6 +3939,7 @@
   return ___FIX(___NO_ERR);
 }
 
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_file_select_raw_virt
    ___P((___device_stream *self,
          ___BOOL for_writing,
@@ -3732,6 +4005,7 @@
 
   return ___FIX(___NO_ERR);
 }
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ ___device_file_release_raw_virt
    ___P((___device_stream *self),
@@ -3971,12 +4245,16 @@
   {
     {
       ___device_file_kind,
+#ifndef LIBEVENT
       ___device_stream_select_virt,
+#endif
       ___device_stream_release_virt,
       ___device_stream_flush_write_virt,
       ___device_file_close_virt
     },
+#ifndef LIBEVENT
     ___device_file_select_raw_virt,
+#endif
     ___device_file_release_raw_virt,
     ___device_file_flush_write_raw_virt,
     ___device_file_seek_raw_virt,
@@ -4020,6 +4298,12 @@
   d->fd = fd;
 
   *dev = d;
+  
+  /* Note that the Linux VFS (at least) is not nonblocking in 
+   * normal operation, therefore waiting for events on those
+   * fds is pointless - they are `always' ready for reading and
+   * writing. The device_stream_setup call will set the read_ready
+   * and write_ready flags to 1 and they'll stay that way --agl */
 
   return ___device_stream_setup
            (&d->base,
@@ -5833,6 +6117,24 @@
 
 /* Waiting for I/O to become possible on a set of devices. */
 
+/* This is the main entry function for event handling. It's
+ * called in thread-schedule! and is passed the run-queue.
+ * The run-queue is a circular linked-list of threads
+ * with the condvars which they are waiting on and the 
+ * assoc devices.
+ *
+ * The ___FIX(1) of the condvar is set if the device is
+ * ready for the operation requested, which is determined by
+ * the ___FIX(2) bit. 1 == write.
+ *
+ * This calls ___device_select and notes which devices set
+ * their pointer to NULL during that operation and updates
+ * the condvars accordingly. (see the comments above
+ * ___device_select for details).
+ */
+
+#ifndef LIBEVENT
+
 ___SCMOBJ ___os_condvar_select
    ___P((___SCMOBJ run_queue,
          ___SCMOBJ timeout),
@@ -5943,6 +6245,87 @@
   return e;
 }
 
+#else  /* LIBEVENT */
+
+/* If we are using libevent then each device keeps track of read_ready and
+ * write_ready flags itself using the callbacks from libevent.
+ * This we use these flags to set the condvar variables. Sadly this is still
+ * an O(1) pass of the thread run-queue.
+ */
+
+___SCMOBJ ___os_condvar_select
+   ___P((___SCMOBJ run_queue,
+         ___SCMOBJ timeout),
+        (run_queue,
+         timeout)
+___SCMOBJ run_queue;
+___SCMOBJ timeout;)
+{
+  /////////////////////////////////////
+#define ___BTQ_DEQ_NEXT 1
+#define ___BTQ_DEQ_PREV 2
+#define ___BTQ_COLOR    3
+#define ___BTQ_PARENT   4
+#define ___BTQ_LEFT     5
+#define ___BTQ_RIGHT    6
+#define ___BTQ_LEFTMOST 6
+#define ___BTQ_OWNER    7
+#define ___CONDVAR_NAME 8
+
+  ___time to;
+  ___SCMOBJ condvar;
+  ___BOOL condition_triggered = 0;
+  ___SCMOBJ e = ___FIX(___NO_ERR);
+
+  if (timeout == ___FAL)
+    to = ___time_mod.time_neg_infinity;
+  else if (timeout == ___TRU)
+    to = ___time_mod.time_pos_infinity;
+  else {
+    ___time_from_seconds (&to, ___F64VECTORREF(timeout,___FIX(0)));
+  }
+
+  for (;;) {
+	  condvar = ___FIELD(run_queue,___BTQ_DEQ_NEXT);
+
+	  while (condvar != run_queue)
+		{
+		  ___device *dev = ___CAST(___device *,
+				  ___FIELD(___FIELD(condvar,___CONDVAR_NAME), ___FOREIGN_PTR));
+		  ___SCMOBJ owner = ___FIELD(condvar,___BTQ_OWNER);
+		  ___FIELD(condvar,___BTQ_OWNER) = owner & ~___FIX(1);
+		  if (owner & ___FIX(2)) {
+			  if (dev->write_ready) {
+				  ___FIELD(condvar,___BTQ_OWNER) = owner |= ___FIX(1);
+				  condition_triggered = 1;
+			  } else {
+				  ___FIELD(condvar,___BTQ_OWNER) = owner & ~___FIX(1);
+			  }
+		  } else {
+			  if (dev->read_ready) {
+				  ___FIELD(condvar,___BTQ_OWNER) = owner |= ___FIX(1);
+				  condition_triggered = 1;
+			  } else {
+				  ___FIELD(condvar,___BTQ_OWNER) = owner & ~___FIX(1);
+			  }
+		  }
+		  condvar = ___FIELD(condvar,___BTQ_DEQ_NEXT);
+		}
+
+	  if (!condition_triggered) {
+		  e = ___device_select(to);
+		  if (e != ___FIX(___NO_ERR)) return e;
+		  condition_triggered = 1;
+	  } else {
+		  break;
+	  }
+  }
+
+  return e;
+}
+
+#endif  /* LIBEVENT */
+
 
 /*   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   */
 
@@ -6764,6 +7147,14 @@
   ___SCMOBJ e;
 
   ////printf ("io_module_setup\n");fflush(stdout);/////////////////////////////
+  
+#ifdef LIBEVENT
+  event_init();
+  if (!(event_abilities() & EV_ABILITY_EDGE)) {
+	  fprintf(stderr, "Event interface does not support edge io.\n");
+	  abort();
+  }
+#endif
 
   if ((e = ___device_group_setup (&io_mod.dgroup)) == ___FIX(___NO_ERR))
     {
diff -ur gambc40b14/lib/os_io.h gambc40b14.new/lib/os_io.h
--- gambc40b14/lib/os_io.h	2005-01-13 23:29:06.000000000 +0000
+++ gambc40b14.new/lib/os_io.h	2005-08-19 14:27:20.538850022 +0100
@@ -9,6 +9,10 @@
 //////////////////////////////
 #include "os_time.h"
 
+#ifdef LIBEVENT
+#include <event.h>
+#endif
+
 /*---------------------------------------------------------------------------*/
 
 
@@ -77,8 +81,13 @@
     int direction;                 /* ___DIRECTION_RD and/or ___DIRECTION_WR */
     int read_stage;                /* ___STAGE_OPEN ... ___STAGE_CLOSED */
     int write_stage;               /* ___STAGE_OPEN ... ___STAGE_CLOSED */
+#ifdef LIBEVENT
+	struct event ev;
+	int read_ready, write_ready;
+#endif
   } ___device;
 
+#ifndef LIBEVENT
 
 typedef struct ___device_select_state_struct
   {
@@ -147,6 +156,7 @@
 
 #endif
 
+#endif  /* !LIBEVENT */
 
 typedef struct ___device_vtbl_struct
   {
@@ -155,6 +165,8 @@
 
     int (*kind) ___P((___device *self),());
 
+#ifndef LIBEVENT
+
 #define ___device_select_virt(self,for_writing,i,pass,state) \
 ___CAST(___device_vtbl*,(self)->vtbl)->select_virt(self,for_writing,i,pass,state)
 
@@ -166,6 +178,8 @@
              ___device_select_state *state),
             ());
 
+#endif  /* !LIBEVENT */
+
 #define ___device_release_virt(self) \
 ___CAST(___device_vtbl*,(self)->vtbl)->release_virt(self)
 
@@ -295,6 +309,8 @@
   {
     ___device_vtbl base;
 
+#ifndef LIBEVENT
+
 #define ___device_stream_select_raw_virt(self,for_writing,i,pass,state) \
 ___CAST(___device_stream_vtbl*,(self)->base.vtbl)->select_raw_virt(self,for_writing,i,pass,state)
 
@@ -306,6 +322,8 @@
              ___device_select_state *state),
             ());
 
+#endif  /* !LIBEVENT */
+
 #define ___device_stream_release_raw_virt(self) \
 ___CAST(___device_stream_vtbl*,(self)->base.vtbl)->release_raw_virt(self)
 
@@ -372,6 +390,8 @@
             ());
   } ___device_stream_vtbl;
 
+#ifndef LIBEVENT
+
 extern ___SCMOBJ ___device_stream_select_virt
    ___P((___device *self,
          ___BOOL for_writing,
@@ -380,6 +400,8 @@
          ___device_select_state *state),
         ());
 
+#endif  /* !LIBEVENT */
+
 extern ___SCMOBJ ___device_stream_release_virt
    ___P((___device *self),
         ());
@@ -444,13 +466,18 @@
 
 
 
-
+#ifdef LIBEVENT
+extern ___SCMOBJ ___device_select
+   ___P((___time timeout),
+        ());
+#else  /* LIBEVENT */
 extern ___SCMOBJ ___device_select
    ___P((___device **devs,
          int nb_read_devs,
          int nb_write_devs,
          ___time timeout),
         ());
+#endif
 
 extern ___SCMOBJ ___device_flush_write
    ___P((___device *self),
diff -ur gambc40b14/lib/os_tty.c gambc40b14.new/lib/os_tty.c
--- gambc40b14/lib/os_tty.c	2005-07-13 11:35:05.000000000 +0100
+++ gambc40b14.new/lib/os_tty.c	2005-08-19 14:27:20.556846474 +0100
@@ -18,6 +18,9 @@
 #include "setup.h"
 #include "c_intf.h"
 
+#ifdef LIBEVENT
+#include <event.h>
+#endif
 
 /*---------------------------------------------------------------------------*/
 
@@ -697,6 +700,21 @@
   return 0;
 }
 
+#ifdef LIBEVENT
+/* This is the callback function, called by libevent, whenever a device_stream
+ * has an event. */
+static void
+device_stream_event_callback(int fd, short events, void *arg) {
+	___device *d = ___CAST(___device *, arg);
+
+	if (events & EV_READ)  d->read_ready = 1;
+	if (events & EV_WRITE) d->write_ready = 1;
+	if (events & EV_TIMEOUT) {
+		d->read_ready = 1;
+		d->write_ready = 1;
+	}
+}
+#endif
 
 ___HIDDEN ___SCMOBJ ___device_tty_force_open
    ___P((___device_tty *self),
@@ -725,6 +743,11 @@
           return fnf_or_err_code_from_errno ();
 
         d->fd = fd;
+#ifdef LIBEVENT
+		event_set(&d->base.base.ev, d->fd, EV_READ | EV_WRITE | EV_EDGE | EV_PERSIST,
+				device_stream_event_callback, self);
+		event_add(&d->base.base.ev, NULL);
+#endif
 
 #endif
 
@@ -854,8 +877,16 @@
   {
     int n;
 
-    if ((n = write (d->fd, buf, len)) < 0)
+    if ((n = write (d->fd, buf, len)) < 0) {
+#ifdef LIBEVENT
+      if (errno == EAGAIN) self->base.base.write_ready = 0;
+#endif
       return err_code_from_errno ();
+	}
+
+#ifdef LIBEVENT
+	if (n < len) self->base.base.write_ready = 0;
+#endif
 
     *len_done = n;
   }
@@ -939,8 +970,16 @@
              len);
 #endif
 
-    if ((n = read (d->fd, buf, len)) < 0)
+    if ((n = read (d->fd, buf, len)) < 0) {
+#ifdef LIBEVENT
+      if (errno == EAGAIN) self->base.base.read_ready = 0;
+#endif 
       return err_code_from_errno ();
+	}
+	
+#ifdef LIBEVENT
+	if (n < len) self->base.base.read_ready = 0;
+#endif
 
 #ifdef ___DEBUG
 
@@ -6208,10 +6247,18 @@
        */
 
       ___time duration;
+#ifdef LIBEVENT
+	  struct timeval tv, *p_tv = &tv;
+#endif
 
       ___time_get_current_time (&d->current.paren_balance_end);
       ___time_from_nsecs (&duration, 0, d->paren_balance_duration_nsecs);
       ___time_add (&d->current.paren_balance_end, duration);
+#ifdef LIBEVENT
+	  ___absolute_time_to_nonnegative_timeval(duration, &p_tv);
+	  evtimer_set(&d->timeout_event, device_stream_event_callback, d);
+	  evtimer_add(&d->timeout_event, p_tv);
+#endif
 
       d->current.paren_balance_in_progress = 1;
     }
@@ -6315,19 +6362,38 @@
 
       d->base.base.read_stage = ___STAGE_CLOSED; /* avoid multiple closes */
       d->base.base.write_stage = ___STAGE_CLOSED;
+#ifdef LIBEVENT
+	  d->base.base.read_ready = 0;
+	  d->base.base.write_ready = 0;
+	  event_del(&d->base.base.ev);
+#endif
 
       if ((e = ___device_tty_cleanup (d)) != ___FIX(___NO_ERR))
         return e;
     }
-  else if (direction & ___DIRECTION_RD)
+  else if (direction & ___DIRECTION_RD) {
+#ifdef LIBEVENT
+    d->base.base.read_ready = 0;
+#endif
     d->base.base.read_stage = ___STAGE_CLOSED;
-  else if (direction & ___DIRECTION_WR)
+  } else if (direction & ___DIRECTION_WR) {
+#ifdef LIBEVENT
+    d->base.base.read_ready = 0;
+#endif
     d->base.base.write_stage = ___STAGE_CLOSED;
+  }
+
+#ifdef LIBEVENT
+  if (d->base.base.write_stage == ___STAGE_CLOSED &&
+      d->base.base.read_stage == ___STAGE_CLOSED) {
+	  event_del(&d->base.base.ev);
+  }
+#endif
 
   return ___FIX(___NO_ERR);
 }
 
-
+#ifndef LIBEVENT
 ___HIDDEN ___SCMOBJ ___device_tty_select_raw_virt
    ___P((___device_stream *self,
          ___BOOL for_writing,
@@ -6377,7 +6443,6 @@
 #endif
 
 #ifdef USE_LINEEDITOR
-
       if (!for_writing)
         {
           if (lineeditor_read_ready (d))
@@ -6391,7 +6456,6 @@
                i,
                d->current.paren_balance_end);
         }
-
 #endif
 
       return ___FIX(___SELECT_SETUP_DONE);
@@ -6444,7 +6508,7 @@
 
   return ___FIX(___NO_ERR);
 }
-
+#endif  /* !LIBEVENT */
 
 ___HIDDEN ___SCMOBJ ___device_tty_release_raw_virt
    ___P((___device_stream *self),
@@ -6804,12 +6868,16 @@
   {
     {
       ___device_tty_kind,
+#ifndef LIBEVENT
       ___device_stream_select_virt,
+#endif
       ___device_stream_release_virt,
       ___device_stream_flush_write_virt,
       ___device_tty_close_virt
     },
+#ifndef LIBEVENT
     ___device_tty_select_raw_virt,
+#endif
     ___device_tty_release_raw_virt,
     ___device_tty_flush_write_raw_virt,
     ___device_tty_seek_raw_virt,
@@ -6836,6 +6904,14 @@
 
 #endif
 
+#ifdef LIBEVENT
+  if (self->stage != TTY_STAGE_NOT_OPENED) {
+	event_set(&self->base.base.ev, self->fd, EV_READ | EV_WRITE | EV_EDGE | EV_PERSIST,
+	          device_stream_event_callback, self);
+	event_add(&self->base.base.ev, NULL);
+  }
+#endif
+
   return e;
 }
 
diff -ur gambc40b14/lib/os_tty.h gambc40b14.new/lib/os_tty.h
--- gambc40b14/lib/os_tty.h	2005-01-04 16:59:40.000000000 +0000
+++ gambc40b14.new/lib/os_tty.h	2005-08-19 14:27:20.560845686 +0100
@@ -374,6 +374,10 @@
     struct termios initial_termios;
     int initial_flags;
 
+#ifdef LIBEVENT
+	struct event timeout_event;
+#endif
+
 #endif
 
 #ifdef USE_WIN32
