[Libevent-users] [PATCH] relative timer with EV_PERSIST support + move event_del logic into event_active + regression tests

2007-11-13 Thread Christopher Layne
1. Make EV_PERSIST reschedule timeouts automatically.
2. New function: timeout_schedule: (nothing really new within it, just
   modular wrapping of timeout rescheduling).
3. New macro: evutil_timercpy: tv_dst = tv_src in one line type deal;
3. Regression tests for persistent timeouts, include read/write, signals,
   and timers.
4. Another regression test for signal handler restores (no problem, just
   added another one).

So what this means is that if you do the following:

event_set(ev, fd, EV_READ | EV_PERSIST, read_cb, obj);
event_add(ev, timeout);

read_cb() will be called whenever a read event happens, and it's timeout
as passed to event_add() will be reset to the original value you passed.
You do not have to call event_add() within the handler.

event_set(ev, -1, EV_TIMEOUT | EV_PERSIST, timer_cb, obj);
event_add(ev, cycle);

timer_cb() will be called when timeout (as passed via cycle) expires. It
will then reschedule itself with it's original timeout, e.g. periodic timer.
You do not have to call event_add() within the handler.

For the event_del() changes, it's just moving event_del() into event_active(),
when an event occurs. There is a feature request on sourceforge for this,
and this couples nicely with the EV_PERSIST change. It also allows us to
rexamine the logic tests within the various event dispatchers themselves, as
event_active() will only delete the same event once.

-cl

$ test/regress
Testing Priorities 1: OK
Testing Priorities 2: OK
Testing Priorities 3: OK
Testing Evbuffer: OK
Testing evbuffer_find 1: OK
Testing evbuffer_find 2: OK
Testing evbuffer_find 3: OK
Bufferevent: OK
Free active base: OK
Testing HTTP Server Event Base: OK
Testing HTTP Header filtering: OK
Testing Basic HTTP Server: OK
Testing Request Connection Pipeline : OK
Testing Request Connection Pipeline (persistent): OK
Testing Connection Close Detection: OK
Testing HTTP POST Request: OK
Testing Bad HTTP Request: OK
Testing HTTP Server with high port: OK
Testing HTTP Dispatcher: OK
Testing Basic RPC Support: OK
Testing Good RPC Post: OK
Testing RPC Client: OK
Testing RPC (Queued) Client: OK
Testing RPC Client Timeout: OK
DNS server support: OK
Simple DNS resolve: type: 1, count: 1, ttl: 300: 152.160.49.201 OK
IPv6 DNS resolve: type: 3, count: 1, ttl: 922: 2610:a0:c779:b::d1ad:35b4 OK
Simple read: OK
Simple write: OK
Multiple read/write: OK
Persist read/write: OK
Combined read/write: OK
Simple timeout: OK
Persistent timeout: OK
Persistent read/write timeout: OK
Persistent signal timeout: OK
Simple signal: OK
Immediate signal: OK
Loop exit: OK
Multiple events for same fd: OK
Want read only once: OK
Testing Tagging:
encoded 0x0af0 with 2 bytes
encoded 0x1000 with 3 bytes
encoded 0x0001 with 1 bytes
encoded 0xdeadbeef with 5 bytes
encoded 0x with 1 bytes
encoded 0x00bef000 with 4 bytes
evtag_int_test: OK
evtag_fuzz: OK
OK
Testing RPC: (1.9 us/add) OK
Signal dealloc: OK
Signal pipeloss: OK
Signal switchbase: OK
Signal handler restore: OK
Signal handler spread restore: OK
Signal handler assert: OK

$ make verify
cd test  make verify
make[1]: Entering directory `/home/clayne/project/libevent.build/test'
Running tests:
KQUEUE
Skipping test
DEVPOLL
Skipping test
POLL
 test-eof: OKAY
 test-weof: OKAY
 test-time: OKAY
 regress: type: 1, count: 1, ttl: 300: 152.160.49.201 type: 3, count: 1, ttl: 
238: 2610:a0:c779:b::d1ad:35b4 (1.9 us/add) OKAY
SELECT
 test-eof: OKAY
 test-weof: OKAY
 test-time: OKAY
 regress: type: 1, count: 1, ttl: 300: 152.160.49.201 type: 3, count: 1, ttl: 
1800: 2610:a0:c779:b::d1ad:35b4 (1.9 us/add) OKAY
EPOLL
 test-eof: OKAY
 test-weof: OKAY
 test-time: OKAY
 regress: type: 1, count: 1, ttl: 300: 152.160.49.201 type: 3, count: 1, ttl: 
1800: 2610:a0:c779:b::d1ad:35b4 (1.8 us/add) OKAY
EVPORT
Skipping test

Index: event.c
===
--- event.c (revision 526)
+++ event.c (working copy)
@@ -125,4 +125,6 @@ static int  timeout_next(struct event_bas
 static voidtimeout_process(struct event_base *);
 static voidtimeout_correct(struct event_base *, struct timeval *);
+static int timeout_schedule(struct event_base *, struct event *,
+struct timeval *);
 
 static void
@@ -615,4 +617,5 @@ event_add(struct event *ev, struct timev
const struct eventop *evsel = base-evsel;
void *evbase = base-evbase;
+   min_heap_t *mh = base-timeheap;
 
event_debug((
@@ -627,12 +630,4 @@ event_add(struct event *ev, struct timev
 
if (tv != NULL) {
-   struct timeval now;
-
-   if (ev-ev_flags  EVLIST_TIMEOUT)
-   event_queue_remove(base, ev, EVLIST_TIMEOUT);
-   else if (min_heap_reserve(base-timeheap,
-   1 + min_heap_size(base-timeheap)) == -1)
- 

Re: [Libevent-users] [PATCH] relative timer with EV_PERSIST support + move event_del logic into event_active + regression tests

2007-11-13 Thread William Ahern
On Tue, Nov 13, 2007 at 06:15:00PM -0800, Christopher Layne wrote:
 1. Make EV_PERSIST reschedule timeouts automatically.
 2. New function: timeout_schedule: (nothing really new within it, just
modular wrapping of timeout rescheduling).
 3. New macro: evutil_timercpy: tv_dst = tv_src in one line type deal;
 3. Regression tests for persistent timeouts, include read/write, signals,
and timers.
 4. Another regression test for signal handler restores (no problem, just
added another one).
 
 So what this means is that if you do the following:
 
   event_set(ev, fd, EV_READ | EV_PERSIST, read_cb, obj);
   event_add(ev, timeout);
 
 read_cb() will be called whenever a read event happens, and it's timeout
 as passed to event_add() will be reset to the original value you passed.
 You do not have to call event_add() within the handler.
 
   event_set(ev, -1, EV_TIMEOUT | EV_PERSIST, timer_cb, obj);
   event_add(ev, cycle);
 
 timer_cb() will be called when timeout (as passed via cycle) expires. It
 will then reschedule itself with it's original timeout, e.g. periodic timer.
 You do not have to call event_add() within the handler.

What was the original behavior? Did the timer disappear? If not, I fail to
see how the new behavior is more justificed than the old; meaning, instead
of changing it, why not add it as an option? If waiting to read an entire
line, but you are trickled one byte at a time, do you really want to reset
the timeout between bytes, or is the timeout meant to limit the time spent
on reading the line?

 For the event_del() changes, it's just moving event_del() into event_active(),
 when an event occurs. There is a feature request on sourceforge for this,
 and this couples nicely with the EV_PERSIST change. It also allows us to
 rexamine the logic tests within the various event dispatchers themselves, as
 event_active() will only delete the same event once.

Will this cause incompatabilities? What if you call event_add() anyhow? Will
it return failure? This could silently break code. Maybe the user set
EV_PERSIST, realized it didn't do what he wanted, but never removed it.

___
Libevent-users mailing list
Libevent-users@monkey.org
http://monkeymail.org/mailman/listinfo/libevent-users


Re: [Libevent-users] [PATCH] relative timer with EV_PERSIST support + move event_del logic into event_active + regression tests

2007-11-13 Thread Christopher Layne
On Tue, Nov 13, 2007 at 06:27:58PM -0800, William Ahern wrote:
  event_set(ev, fd, EV_READ | EV_PERSIST, read_cb, obj);
  event_add(ev, timeout);
  
  read_cb() will be called whenever a read event happens, and it's timeout
  as passed to event_add() will be reset to the original value you passed.
  You do not have to call event_add() within the handler.
  
  event_set(ev, -1, EV_TIMEOUT | EV_PERSIST, timer_cb, obj);
  event_add(ev, cycle);
  
  timer_cb() will be called when timeout (as passed via cycle) expires. It
  will then reschedule itself with it's original timeout, e.g. periodic timer.
  You do not have to call event_add() within the handler.
 
 What was the original behavior? Did the timer disappear? If not, I fail to
 see how the new behavior is more justificed than the old; meaning, instead
 of changing it, why not add it as an option? If waiting to read an entire
 line, but you are trickled one byte at a time, do you really want to reset
 the timeout between bytes, or is the timeout meant to limit the time spent
 on reading the line?

The original behaviour with EV_PERSIST was this:

1. Implicitly not delete our event, but do not reschedule the timer.
2. Merrily read/write/signal/etc. on an event and then out of the blue
   receive EV_TIMEOUT because the timeout was never rescheduled unless you
   explicitly did it (which one probably won't inutitively expect with 
EV_PERSIST).

We went over this one before though. The issue is that the attacker crafting
1 byte data to keep connection open for eternity thing, while valid - I don't
really see how it's a libevent issue. That's an application issue. Otherwise,
with EV_PERSIST, the timeout added to the event no longer plays the role of
a timeout once a single event happens on said event, and the timeout is not
rescheduled manually.

The concept of a timeout being tied to if we get a single unit of y bytes
means the timeout is then a sideband module within said event now. However,
receive 1 byte == event occured - and based on - that timeout should no longer
be relevant to the situation that already occured.

The example you bring up of wanting to read y units of bytes in a given time is
still possible without EV_PERSIST, or by using an associated timer event 
(probably
not preferred), etc. It's just that the previous example is so much an
exception to the standard idiom of:

wait_until_event_or_timeout(); do_stuff() || delete_myself(); reset_timeout();

With EV_PERSIST as it is, it's only convenient for exceptional cases rather than
the norm - and that's the focus of this patch - to reverse that.

-cl

 
  For the event_del() changes, it's just moving event_del() into 
  event_active(),
  when an event occurs. There is a feature request on sourceforge for this,
  and this couples nicely with the EV_PERSIST change. It also allows us to
  rexamine the logic tests within the various event dispatchers themselves, as
  event_active() will only delete the same event once.
 
 Will this cause incompatabilities? What if you call event_add() anyhow? Will
 it return failure? This could silently break code. Maybe the user set
 EV_PERSIST, realized it didn't do what he wanted, but never removed it.

event_add() will then reschedule the event based on the timeout you passed to
it. But since it's already implicit with EV_PERSIST, it would just be a
redudant but safe thing to do.

-cl
___
Libevent-users mailing list
Libevent-users@monkey.org
http://monkeymail.org/mailman/listinfo/libevent-users