]> granicus.if.org Git - libevent/commitdiff
r14931@tombo: nickm | 2007-11-17 17:21:09 -0500
authorNick Mathewson <nickm@torproject.org>
Sat, 17 Nov 2007 22:21:42 +0000 (22:21 +0000)
committerNick Mathewson <nickm@torproject.org>
Sat, 17 Nov 2007 22:21:42 +0000 (22:21 +0000)
 Patch from Scott Lamb: Implement event_{base_}loopbreak.  Includes documentation and tests.  From sf.net Feature Request 1826546.

svn:r535

ChangeLog
event-internal.h
event.3
event.c
event.h
test/regress.c

index 7429c476aa80b0f66ac4c1bac25e0425efb1e3ec..086a1df4e082beb072a0c39443cd2ec3f2161b4e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Changes in current version:
  o provide event_base_new() that does not set the current_base global  
  o bufferevent_write now uses a const source argument; report from Charles Kerr
  o improve documentation on event_base_loopexit; patch from Scott Lamb
+ o New function, event_{base_}loopbreak.  Like event_loopexit, it makes an event loop stop executing and return.  Unlike event_loopexit, it keeps subsequent pending events from getting executed.  Patch from Scott Lamb
 
 Changes in 1.4.0:
  o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
index de9c78790c524d169bf4d90e0cc36f3064afc9c9..56ef877be414c20a1ca5e7251dec4d676986e4f8 100644 (file)
@@ -42,6 +42,7 @@ struct event_base {
        int event_count_active; /* counts number of active events */
 
        int event_gotterm;              /* Set to terminate loop */
+       int event_break;                /* Set to terminate loop immediately */
 
        /* active event management */
        struct event_list **activequeues;
diff --git a/event.3 b/event.3
index d5717f22519e02a6463a8a1bd96928be4a5e55d6..5b33ec64a935baaa7aefc44f5ed48d0a139653f6 100644 (file)
--- a/event.3
+++ b/event.3
 .Nm event_dispatch ,
 .Nm event_loop ,
 .Nm event_loopexit ,
+.Nm event_loopbreak ,
 .Nm event_set ,
 .Nm event_base_dispatch ,
 .Nm event_base_loop ,
 .Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
 .Nm event_base_set ,
 .Nm event_base_free ,
 .Nm event_add ,
@@ -93,6 +95,8 @@
 .Fn "event_loop" "int flags"
 .Ft int
 .Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
 .Ft void
 .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
 .Ft int
 .Ft int
 .Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
 .Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
 .Fn "event_base_set" "struct event_base *base" "struct event *"
 .Ft void
 .Fn "event_base_free" "struct event_base *base"
@@ -419,7 +425,16 @@ given timer expires will complete normally (handling all queued events) then
 exit without blocking for events again. Subsequent invocations of
 .Fn event_loop
 will proceed normally.
-The parameter indicates the time after which the loop should terminate.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
 .Pp
 It is the responsibility of the caller to provide these functions with
 pre-allocated event structures.
diff --git a/event.c b/event.c
index 3e6295cbed7080a7a7d3a437e7985fb8079f6894..d0e8d6701c0708cf75e4214f37de6afc87077bcd 100644 (file)
--- a/event.c
+++ b/event.c
@@ -330,7 +330,7 @@ event_process_active(struct event_base *base)
                        ncalls--;
                        ev->ev_ncalls = ncalls;
                        (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
-                       if (event_gotsig)
+                       if (event_gotsig || base->event_break)
                                return;
                }
        }
@@ -374,6 +374,25 @@ event_base_loopexit(struct event_base *event_base, struct timeval *tv)
                    event_base, tv));
 }
 
+/* not thread safe */
+int
+event_loopbreak(void)
+{
+       return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+       if (event_base == NULL)
+               return (-1);
+
+       event_base->event_break = 1;
+       return (0);
+}
+
+
+
 /* not thread safe */
 
 int
@@ -405,6 +424,11 @@ event_base_loop(struct event_base *base, int flags)
                        break;
                }
 
+               if (base->event_break) {
+                       base->event_break = 0;
+                       break;
+               }
+
                /* You cannot use this interface for multi-threaded apps */
                while (event_gotsig) {
                        event_gotsig = 0;
diff --git a/event.h b/event.h
index 4685e936ae33b4b0823370f3af51c4c82fc9d069..e267308684d67151512544dc0c08a30afd51af12 100644 (file)
--- a/event.h
+++ b/event.h
@@ -407,6 +407,35 @@ int event_loopexit(struct timeval *);
  */
 int event_base_loopexit(struct event_base *, struct timeval *);
 
+/**
+  Abort the active event_loop() immediately.
+
+  event_loop() will abort the loop after the next event is completed;
+  event_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+  Abort the active event_base_loop() immediately.
+
+  event_base_loop() will abort the loop after the next event is completed;
+  event_base_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @param eb the event_base structure returned by event_init()
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
 
 /**
   Add a timer event.
index a153da48586a2a29f4f56f7fed951196ce51a735..274f62cb754ae31d73cbc22c01d6275d10ae3526 100644 (file)
@@ -699,6 +699,42 @@ test_loopexit(void)
        cleanup_test();
 }
 
+static void
+break_cb(int fd, short events, void *arg)
+{
+       test_ok = 1;
+       event_loopbreak();
+}
+
+static void
+fail_cb(int fd, short events, void *arg)
+{
+       test_ok = 0;
+}
+
+void
+test_loopbreak(void)
+{
+       struct event ev1, ev2;
+       struct timeval tv;
+
+       setup_test("Loop break: ");
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       evtimer_set(&ev1, break_cb, NULL);
+       evtimer_add(&ev1, &tv);
+       evtimer_set(&ev2, fail_cb, NULL);
+       evtimer_add(&ev2, &tv);
+
+       event_dispatch();
+
+       evtimer_del(&ev1);
+       evtimer_del(&ev2);
+
+       cleanup_test();
+}
+
 void
 test_evbuffer(void) {
 
@@ -1201,6 +1237,7 @@ main (int argc, char **argv)
        test_immediatesignal();
 #endif
        test_loopexit();
+       test_loopbreak();
 
        test_multiple_events_for_same_fd();