[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r10677: Worked on sa_bufferevent timeouts. Code is written and being (in libevent-urz/trunk: . doc test)



Author: Urz
Date: 2007-06-25 08:10:45 -0400 (Mon, 25 Jun 2007)
New Revision: 10677

Added:
   libevent-urz/trunk/test/test-sa_bufferevents.c
Modified:
   libevent-urz/trunk/buffer.c
   libevent-urz/trunk/doc/plan.txt
   libevent-urz/trunk/sa_evbuffer.c
   libevent-urz/trunk/test/Makefile.am
   libevent-urz/trunk/test/regress.c
Log:
Worked on sa_bufferevent timeouts. Code is written and being debugged. Current problem appears to be a stack corruption issue. Minor timeline shifts to the plan. Fixed bug in evbuffer_add_vsnprintf on windows. Tried to make regression testing build, but it's horribly broken on windows. Rolled my own, and is working, besides timeouts as mentioned above.

Modified: libevent-urz/trunk/buffer.c
===================================================================
--- libevent-urz/trunk/buffer.c	2007-06-25 07:44:58 UTC (rev 10676)
+++ libevent-urz/trunk/buffer.c	2007-06-25 12:10:45 UTC (rev 10677)
@@ -216,6 +216,21 @@
     
     evbuffer_lock(buf, __func__);
 
+    /* on Windows, the buffer[space - 1] = '\0'; will segfault if
+    the buffer has not had expand called on it ever before (because
+    the buffer is null). Note also :
+    "If buffer or format is NULL, ...
+    these functions return -1 and set errno to EINVAL."
+    http://msdn2.microsoft.com/en-us/library/1kt27hek(VS.80).aspx
+    */
+    space = buf->totallen - buf->misalign - buf->off;
+    if(space == 0) {
+        if (evbuffer_expand(buf, 100) == -1) {
+            evbuffer_unlock(buf, __func__);
+			return (-1);
+        }
+    }
+    
 	for (;;) {
 		buffer = (char *)buf->buffer + buf->off;
 		space = buf->totallen - buf->misalign - buf->off;
@@ -234,9 +249,10 @@
 
 		va_end(aq);
 
-		if (sz == -1)
+		if (sz == -1) {
             evbuffer_unlock(buf, __func__);
 			return (-1);
+        }
 		if (sz < space) {
 			buf->off += sz;
 			if (buf->cb != NULL)
@@ -244,9 +260,10 @@
             evbuffer_unlock(buf, __func__);
 			return (sz);
 		}
-		if (evbuffer_expand(buf, sz + 1) == -1)
+		if (evbuffer_expand(buf, sz + 1) == -1) {
             evbuffer_unlock(buf, __func__);
 			return (-1);
+        }
 
 	}
 	/* NOTREACHED */

Modified: libevent-urz/trunk/doc/plan.txt
===================================================================
--- libevent-urz/trunk/doc/plan.txt	2007-06-25 07:44:58 UTC (rev 10676)
+++ libevent-urz/trunk/doc/plan.txt	2007-06-25 12:10:45 UTC (rev 10677)
@@ -21,35 +21,11 @@
 It it more generally useful than 1) or 3), and can stand alone better.
 
 Coding:
-Alter evbuffer (event.h:212) struct.
-    - Mutex added. Most of the data is stored in the bufferevent struct now, as per
-        IRC conversation with nickm.
-    
-Add a new event_add / event_del for delayed evbuffer events
-(so the user doesn't have to know about the socketpair trick).
-    - Done by sa_bufferevent_new, at sa_evbuffer.c:270
+Everything is done, except:
+Regression Tests
+Timeout
+Man pages
 
-Alter the evbuffer functions (add, drain, etc) to use the mutex on the evbuffer struct,
-to set the bufferevent flags to let the main thread know callbacks are ready, and to call
-a function to ensure the main event-loop is notified of events.
-    - Mutex work is done.
-    - Notification function written, used as needed.
-    - bufferevent pending callback flags set as needed.
-    
-Write a short read event handler for the event_loop half of the socketpair which
-simply reads all there is to be read (no blocking!) and calls the real read/write callbacks
-depending on what it reads.
-    - Done
-
-
-TODOs for tomorrow:
-Write regression tests.
-Compile and Test.
-Write sample code
-Talk to nickm, re:
-    - Timeouts
-    - Automake
-
 Testing:
 Add test cases to libevent testing code... test/regress.c I believe
 
@@ -65,6 +41,9 @@
 Should be done by 10th June.
 I have 3 big assignments due 30th May, 31st May, and 1st June, but I would still like to
 have most of it done by the 3rd of June.
+Well that didn't quite happen. Re-baselined: 26th June.
+This probably seems like a huge slip, but considering the exam placement (No Tor work
+done at all between 9th and 20th of June) it's not that big a slip.
 
 /////////////// Item 2: ///////////////////////////
 Do 1) Second
@@ -94,7 +73,7 @@
 
 Schedule:
 This is not a big section, but I have 4 exams shortly after the 10th, (12th, 18th, 18th, 20th)
-so I will say the 1st July.
+so I will say the 9th July.
 (Note: First evaluation begins 9th July)
 
 //////////////////////// Item 3: //////////////////////
@@ -136,8 +115,5 @@
 //////////////////////////////////////////////////////////////
 
 Random notes:
-event.h has a whole lot of bufferevent stuff, but I can't find the functions themselves. 
-Where are they? do they even exist? are they related to this?
-
 What about closing the connection? How will this be done in a connection independent way?
-When the buffer is freed?
\ No newline at end of file
+When the buffer is freed?

Modified: libevent-urz/trunk/sa_evbuffer.c
===================================================================
--- libevent-urz/trunk/sa_evbuffer.c	2007-06-25 07:44:58 UTC (rev 10676)
+++ libevent-urz/trunk/sa_evbuffer.c	2007-06-25 12:10:45 UTC (rev 10677)
@@ -123,6 +123,28 @@
     }
 }
 
+static int
+timeout_reset(struct event *ev, int timeout)
+{
+	struct timeval tv, *ptv = NULL;
+    
+    event_del(ev);
+
+	if (timeout) {
+		timerclear(&tv);
+		tv.tv_sec = timeout;
+		ptv = &tv;
+	} else {
+        /* 
+        For sa_bufferevents it does not make any sense to
+        set events without timeouts
+        */
+        return -1;
+    }
+
+	return (event_add(ev, ptv));
+}
+
 /* Code to do setup / initialization of the evbuffer delayed callbacks 
  * Initially copied from ev_signal_init, then modified.
  */
@@ -135,7 +157,7 @@
     /* printf("sa_evbuffer initializing\n"); */
     
     if(del_notifier_status != NOTIFIER_UNINIT) {
-        printf("Initialized already, returning\n");
+        /* printf("Initialized already, returning\n"); */
         return;
     } else {
         status_mutex = CreateMutex(NULL, FALSE, NULL);
@@ -193,7 +215,12 @@
 {
 	int res = 0;
     size_t toload;
-
+    
+    evbuffer_lock(bufev->input, __func__);
+    
+    if(size)
+        timeout_reset(&(bufev->ev_read), bufev->timeout_read);
+        
 	/*
 	 * If we have a high watermark configured then we don't want to
 	 * read more data than would make us reach the watermark.
@@ -206,6 +233,7 @@
 
     res = evbuffer_add(bufev->input, data, toload);
 	if (res == -1) {
+        evbuffer_unlock(bufev->input, __func__);
 		return 0;
 	}
 
@@ -222,6 +250,9 @@
 		bufev->del_read_event_set = 1;
         notify();
     }
+    
+    evbuffer_unlock(bufev->input, __func__);
+    
 	return toload;
 
 }
@@ -243,6 +274,9 @@
     
     evbuffer_lock(bufev->output, __func__);
     
+    if(size)
+        timeout_reset(&(bufev->ev_read), bufev->timeout_read);
+    
     if(EVBUFFER_LENGTH(bufev->output) < size) {
         copysize = EVBUFFER_LENGTH(bufev->output);
     } else {

Modified: libevent-urz/trunk/test/Makefile.am
===================================================================
--- libevent-urz/trunk/test/Makefile.am	2007-06-25 07:44:58 UTC (rev 10676)
+++ libevent-urz/trunk/test/Makefile.am	2007-06-25 12:10:45 UTC (rev 10677)
@@ -6,7 +6,8 @@
 
 EXTRA_DIST = regress.rpc
 
-noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench
+#noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench
+noinst_PROGRAMS = regress
 
 BUILT_SOURCES = regress.gen.c regress.gen.h
 test_init_SOURCES = test-init.c
@@ -23,7 +24,8 @@
 DISTCLEANFILES = *~
 CLEANFILES = regress.gen.h regress.gen.c
 
-test: test-init test-eof test-weof test-time regress
+#test: test-init test-eof test-weof test-time regress
+test: regress
 
 verify: test
 	@./test.sh

Modified: libevent-urz/trunk/test/regress.c
===================================================================
--- libevent-urz/trunk/test/regress.c	2007-06-25 07:44:58 UTC (rev 10676)
+++ libevent-urz/trunk/test/regress.c	2007-06-25 12:10:45 UTC (rev 10677)
@@ -535,6 +535,36 @@
 }
 
 void
+sa_readcb(struct sa_bufferevent *bev, void *arg)
+{
+    char buffer[8333];
+    size_t bufsize;
+    bufsize sa_bufferevent_read(bev, buffer, 8333);
+	
+    if (bufsize == 8333) {
+		sa_bufferevent_disable(bev, EV_READ);
+		test_ok++;
+	}
+    
+    sa_bufferevent_write(bev, buffer, bufsize);
+}
+
+void
+sa_writecb(struct sa_bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0) {
+		test_ok++;
+        sa_bufferevent_disable(bev, EV_WRITE);
+    }
+}
+
+void
+sa_errorcb(struct sa_bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+}
+
+void
 test_bufferevent(void)
 {
 	struct bufferevent *bev1, *bev2;
@@ -552,8 +582,8 @@
 	for (i = 0; i < sizeof(buffer); i++)
 		buffer[0] = i;
 
-	bufferevent_write(bev1, buffer, sizeof(buffer));
-
+	sa_bufferevent_write(bev1, buffer, sizeof(buffer));
+    
 	event_dispatch();
 
 	bufferevent_free(bev1);
@@ -565,6 +595,39 @@
 	cleanup_test();
 }
 
+void
+test_sa_bufferevent(void)
+{
+	struct sa_bufferevent *bev1;
+	char buffer[8333];
+	int i;
+
+	setup_test("SemiAutomatic Bufferevent: ");
+
+	bev1 = sa_bufferevent_new(sa_readcb, writecb, errorcb, NULL);
+
+	sa_bufferevent_enable(bev1, EV_READ);
+    sa_bufferevent_enable(bev1, EV_WRITE);
+
+	for (i = 0; i < sizeof(buffer); i++)
+		buffer[0] = i;
+
+	sa_bufferevent_load(bev1, buffer, sizeof(buffer));
+
+	event_loop(EVLOOP_ONCE);
+    
+    sa_bufferevent_unload(bev1, buffer, sizeof(buffer));
+    
+    event_loop(EVLOOP_ONCE);
+
+	bufferevent_free(bev1);
+
+	if (test_ok != 2)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
 struct test_pri_event {
 	struct event ev;
 	int count;
@@ -920,6 +983,8 @@
 	test_evbuffer();
 	
 	test_bufferevent();
+    
+    test_sa_bufferevent();
 
 	test_priorities(1);
 	test_priorities(2);

Added: libevent-urz/trunk/test/test-sa_bufferevents.c
===================================================================
--- libevent-urz/trunk/test/test-sa_bufferevents.c	                        (rev 0)
+++ libevent-urz/trunk/test/test-sa_bufferevents.c	2007-06-25 12:10:45 UTC (rev 10677)
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2003, 2004 Niels Provos <provos@xxxxxxxxxxxxxx>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#else
+#include "../WIN32-Code/misc.h"
+#include <Windows.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event.h"
+#include "log.h"
+
+#include "regress.h"
+
+int pair[2];
+int test_ok;
+static int called;
+static struct event_base *event_base;
+
+int
+setup_test(char *name)
+{
+
+	fprintf(stdout, "%s", name);
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+		fprintf(stderr, "%s: socketpair\n", __func__);
+		exit(1);
+	}
+
+#ifdef HAVE_FCNTL
+        if (fcntl(pair[0], F_SETFL, O_NONBLOCK) == -1)
+		fprintf(stderr, "fcntl(O_NONBLOCK)");
+
+        if (fcntl(pair[1], F_SETFL, O_NONBLOCK) == -1)
+		fprintf(stderr, "fcntl(O_NONBLOCK)");
+#endif
+
+	test_ok = 0;
+	called = 0;
+	return (0);
+}
+
+int
+cleanup_test(void)
+{
+#ifndef WIN32
+	close(pair[0]);
+	close(pair[1]);
+#else
+	CloseHandle((HANDLE)pair[0]);
+	CloseHandle((HANDLE)pair[1]);
+#endif
+	if (test_ok)
+		fprintf(stdout, "OK\n");
+	else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	return (0);
+}
+
+void
+test_evbuffer(void) {
+	setup_test("Evbuffer: ");
+
+	struct evbuffer *evb = evbuffer_new();
+
+	evbuffer_add_printf(evb, "%s/%d", "hello", 1);
+
+	if (EVBUFFER_LENGTH(evb) == 7 &&
+	    strcmp(EVBUFFER_DATA(evb), "hello/1") == 0)
+	    test_ok = 1;
+	
+	cleanup_test();
+}
+
+void
+sa_readcb(struct sa_bufferevent *bev, void *arg)
+{
+    char buffer[8333];
+    size_t bufsize;
+    bufsize = sa_bufferevent_read(bev, buffer, 8333);
+	
+    if (bufsize == 8333) {
+		sa_bufferevent_disable(bev, EV_READ);
+		test_ok++;
+	}
+    
+    sa_bufferevent_write(bev, buffer, bufsize);
+}
+
+void
+sa_writecb(struct sa_bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0) {
+		test_ok++;
+        sa_bufferevent_disable(bev, EV_WRITE);
+    }
+}
+
+void
+sa_errorcb(struct sa_bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+}
+
+void
+sa_timecb(int fd, short what, void *arg)
+{
+	test_ok++;
+}
+
+void
+test_sa_bufferevent(void)
+{
+	struct sa_bufferevent *bev1;
+	char buffer[8333];
+	int i;
+
+	setup_test("SemiAutomatic Bufferevents: ");
+
+	bev1 = sa_bufferevent_new(sa_readcb, sa_writecb, sa_errorcb, NULL);
+
+	sa_bufferevent_enable(bev1, EV_READ);
+    sa_bufferevent_enable(bev1, EV_WRITE);
+
+	for (i = 0; i < sizeof(buffer); i++)
+		buffer[0] = i;
+
+	sa_bufferevent_load(bev1, buffer, sizeof(buffer));
+
+	event_loop(EVLOOP_ONCE);
+    
+    sa_bufferevent_unload(bev1, buffer, sizeof(buffer));
+    
+    event_loop(EVLOOP_ONCE);
+
+	sa_bufferevent_free(bev1);
+
+	if (test_ok != 2)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+void
+test_sa_bufferevent_timeouts(void)
+{
+	struct sa_bufferevent *bev1;
+	char buffer[8333];
+	int i;
+
+	setup_test("SemiAutomatic Bufferevent Timeouts: ");
+
+	bev1 = sa_bufferevent_new(sa_readcb, sa_writecb, sa_errorcb, NULL);
+
+	sa_bufferevent_enable(bev1, EV_READ);
+    sa_bufferevent_enable(bev1, EV_WRITE);
+    
+    sa_bufferevent_settimeout(bev1, 1, 1);
+    event_set(&bev1->ev_write, -1, EV_TIMEOUT, sa_timecb, NULL);
+
+	for (i = 0; i < sizeof(buffer); i++)
+		buffer[0] = i;
+
+	sa_bufferevent_load(bev1, buffer, sizeof(buffer));
+
+	event_loop(EVLOOP_ONCE);
+    
+    event_loop(EVLOOP_ONCE);
+
+	sa_bufferevent_free(bev1);
+
+	if (test_ok != 2)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+int
+main (int argc, char **argv)
+{
+#ifdef WIN32
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	int	err;
+
+	wVersionRequested = MAKEWORD( 2, 2 );
+
+	err = WSAStartup( wVersionRequested, &wsaData );
+#endif
+
+	setvbuf(stdout, NULL, _IONBF, 0);
+
+	/* Initalize the event library */
+	event_base = event_init();
+
+	test_evbuffer();
+    
+    test_sa_bufferevent();
+    
+    test_sa_bufferevent_timeouts();
+
+	return (0);
+}
+