From phil at ultimate.com Tue May 6 21:52:26 2008 From: phil at ultimate.com (Phil Budne) Date: Tue May 6 21:52:31 2008 Subject: [Libevent-users] patch to libevent 1.3e rtsig.c Message-ID: <200805070152.m471qQLx021738@ultimate.com> The ChangeLog file mentioned that rtsig support was removed in 1.40-beta: Changes in 1.4.0-beta: .... o Remove support for the rtsig method: it hasn't compiled for a while ... With the patch against libevent 1.3e included below, rtsig.c compiles. I only noticed that RT signals were supported because the 1.4.3 man page had the (obsolete) note: Support for real-time signals is due to Taral. NOTE! I have not yet tested it. A client of mine is looking at converting an application from RT signals to epoll, and I wanted to benchmark the performance of the two mechanisms (no paper I've found covers both), and libevent looked like a good way to test the two head on, and perhaps the ideal new API to use). Suggestions on testing/benchmarking methods would be most welcome (ie; programs/scripts to generate graphs found on the libevent home page)! Phil *** rtsig.c.orig 2007-07-30 23:41:04.000000000 -0400 --- rtsig.c 2008-05-06 21:23:00.000000000 -0400 *************** *** 176,190 **** #include "event.h" #include "event-internal.h" #include "log.h" - extern struct event_list signalqueue; - #include #ifndef __NR_gettid #define gettid() getpid() #else - #if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3))) _syscall0(pid_t,gettid) #endif #endif --- 176,193 ---- #include "event.h" #include "event-internal.h" #include "log.h" #ifndef __NR_gettid #define gettid() getpid() #else #if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3))) + #ifdef _syscall0 _syscall0(pid_t,gettid) + #else + pid_t gettid(void) { + return syscall(__NR_gettid); + } + #endif #endif #endif *************** *** 544,550 **** } while (0) void * ! rtsig_init(struct event_base *) { struct rtsigop *op; int sockets[2]; --- 547,553 ---- } while (0) void * ! rtsig_init(struct event_base *base) { struct rtsigop *op; int sockets[2]; *************** *** 866,873 **** } else if (sigismember(&op->sigs, signum)) { /* managed signals are queued */ ! ev = TAILQ_FIRST(&signalqueue); ! while (ev != TAILQ_END(&signalqueue)) { next_ev = TAILQ_NEXT(ev, ev_signal_next); if (EVENT_SIGNAL(ev) == signum) activate(ev, EV_SIGNAL); --- 869,876 ---- } else if (sigismember(&op->sigs, signum)) { /* managed signals are queued */ ! ev = TAILQ_FIRST(&base->sig.signalqueue); ! while (ev != TAILQ_END(&base->sig.signalqueue)) { next_ev = TAILQ_NEXT(ev, ev_signal_next); if (EVENT_SIGNAL(ev) == signum) activate(ev, EV_SIGNAL); From libev at schmorp.de Wed May 7 11:42:38 2008 From: libev at schmorp.de (Marc Lehmann) Date: Wed May 7 11:42:48 2008 Subject: [Libevent-users] FYI: libevent/libev benchmark updated for libevent-1.4.3 Message-ID: <20080507154238.GA9421@schmorp.de> As version 1.4.3-stable of libevent uses a more efficient binary heap over the red-black tree used before, the benchmark at: http://libev.schmorp.de/bench.html was quite outdated. I therefore updated it by benchmarking libev-3.31 vs. libevent-1.4.3. The main difference is that the growth characteristics of libevent are now similar to libev (and the factor of 2-3 remains). (Note that the upcoming 3.33 version of libev uses a more cache-friendly 4-heap, but the benchmark still uses 3.31). Enjoy, -- The choice of a Deliantra, the free code+content MORPG -----==- _GNU_ http://www.deliantra.net ----==-- _ generation ---==---(_)__ __ ____ __ Marc Lehmann --==---/ / _ \/ // /\ \/ / pcg@goof.com -=====/_/_//_/\_,_/ /_/\_\ From dan at sunsaturn.com Thu May 8 01:03:06 2008 From: dan at sunsaturn.com (Dan) Date: Thu May 8 01:03:20 2008 Subject: [Libevent-users] FYI: libevent/libev benchmark updated for libevent-1.4.3 In-Reply-To: <20080507154238.GA9421@schmorp.de> References: <20080507154238.GA9421@schmorp.de> Message-ID: Think I tried Ev once, to many bugs, hell couldn't even set a timer within a timer as I remember, This EV stuff just meant to undermine the hardwork of the folks at libevent? Dan. On Wed, 7 May 2008, Marc Lehmann wrote: > As version 1.4.3-stable of libevent uses a more efficient binary heap > over the red-black tree used before, the benchmark at: > > http://libev.schmorp.de/bench.html > > was quite outdated. I therefore updated it by benchmarking libev-3.31 vs. > libevent-1.4.3. > > The main difference is that the growth characteristics of libevent are now > similar to libev (and the factor of 2-3 remains). > > (Note that the upcoming 3.33 version of libev uses a more cache-friendly > 4-heap, but the benchmark still uses 3.31). > > Enjoy, > > -- > The choice of a Deliantra, the free code+content MORPG > -----==- _GNU_ http://www.deliantra.net > ----==-- _ generation > ---==---(_)__ __ ____ __ Marc Lehmann > --==---/ / _ \/ // /\ \/ / pcg@goof.com > -=====/_/_//_/\_,_/ /_/\_\ > _______________________________________________ > Libevent-users mailing list > Libevent-users@monkey.org > http://monkeymail.org/mailman/listinfo/libevent-users > From msimoni at gmail.com Thu May 8 02:31:01 2008 From: msimoni at gmail.com (Manuel Simoni) Date: Thu May 8 02:31:22 2008 Subject: [Libevent-users] Patch: useful sendfile for HTTP servers (1.4.3-stable) Message-ID: <37707ed10805072331t2b4bf45dreea273c33a779fc7@mail.gmail.com> [Resending because apparently it didn't get through yesterday.] Hi, my HTTP server thingy came to a screeching halt when serving many large files, so I added a form of Linux sendfile support that requires just a few changes and supports some interesting uses (e.g. sending the HTTP headers normally but the HTTP body via sendfile). The server now runs very fast, with very little CPU and RAM. This is preliminary, probably buggy, and I don't understand the evbuffer functionality very well (e.g. draining). In addition to the normal data evbuffers, this patch adds two types of evbuffers: (1) sendfile buffers, and (2) data buffers to which a sendfile buffer has been added. This distinction is recorded in the sf_fd field. There are two additonal fields, sf_off and sf_buf. *** libevent-1.4.3-stable/event.h 2008-02-23 02:36:12.000000000 +0100 --- libevent-1.4.3-stable-sendfile/event.h 2008-05-07 15:40:32.000000000 +0200 *************** *** 724,729 **** --- 724,746 ---- size_t totallen; size_t off; + /* + sf_fd == -1. A standard data buffer. sf_off and sf_buf are + unused. + + sf_fd == -2. A buffer to which a sendfile buffer has been + added at the end (sf_buf). off holds the combined size of + the RAM data of this buffer and the added sendfile buffer. + sf_off is unused. + + sf_fd >= 0. A pure sendfile buffer. sf_fd, sf_off, and off + are the arguments in_fd, offset, and count to sendfile(), + respectively. sf_buf is unused. + */ + int sf_fd; + off_t sf_off; + struct evbuffer *sf_buf; + void (*cb)(struct evbuffer *, size_t, size_t, void *); void *cbarg; }; The adding and writing of buffers (evbuffer_add_buffer, evbuffer_write) is changed: To keep it simple this system only allows adding a sendfile buffer to a data buffer. So, the sendfile buffer must be the last step in the chain, which works fine for e.g. many HTTP uses cases. You cannot add a sendfile buffer to another sendfile buffer, or add a data buffer to a sendfile buffer. I think these things would theoretically be possible, but require a lot more housekeeping than the current solution, which plugs directly into the existing draining code. When a sendfile buffer is added after a data buffer, we trick and increment the data buffer's length by the length of the sendfile buffer, without actually copying the data to the buffer (which would completely defeat the purpose of sendfile, of course). Then, later when it comes to writing this combined buffer, we just need to check whether all "normal" data has been written, and then switch over to writing the sendfile data. This *seems* to work nicely but I am not 100% sure that every situation is handled OK. *** libevent-1.4.3-stable/buffer.c 2007-11-12 03:37:32.000000000 +0100 --- libevent-1.4.3-stable-sendfile/buffer.c 2008-05-07 16:36:44.000000000 +0200 *************** *** 61,66 **** --- 61,68 ---- #include #endif + #include + #include "event.h" #include "config.h" *************** *** 71,76 **** --- 73,81 ---- buffer = calloc(1, sizeof(struct evbuffer)); + /* Make all buffers non-sendfile buffers initially. */ + buffer->sf_fd = -1; + return (buffer); } *************** *** 100,105 **** --- 105,130 ---- { int res; + if (outbuf->sf_fd == -1) { + /* The output buffer is a data buffer. */ + if (inbuf->sf_fd >= 0) { + /* The input buffer is a sendfile buffer. + Mark this buffer as containing a sendfile + buffer and "virtually" extend the buffer by + the size of the sendfile buffer. */ + outbuf->sf_fd = -2; + outbuf->sf_buf = inbuf; + outbuf->off += inbuf->off; + return 0; + } + } else { + /* No support for nested or concatenated sendfile + buffers, i.e. if the output buffer is or contains a + sendfile buffer, we cannot add another sendfile + buffer to it. */ + return -1; + } + /* Short cut for better performance */ if (outbuf->off == 0) { struct evbuffer tmp; *************** *** 415,421 **** int n; #ifndef WIN32 ! n = write(fd, buffer->buffer, buffer->off); #else n = send(fd, buffer->buffer, buffer->off, 0); #endif --- 440,467 ---- int n; #ifndef WIN32 ! switch(buffer->sf_fd) { ! case -1: ! /* A data buffer. */ ! n = write(fd, buffer->buffer, buffer->off); ! break; ! case -2: ! /* A data buffer with a sendfile buffer at the end. ! First write the actual data in the buffer, then ! switch to the sendfile data. */ ! if (buffer->off > buffer->sf_buf->off) { ! n = write(fd, ! buffer->buffer, ! buffer->off - buffer->sf_buf->off); ! } else { ! n = evbuffer_write(buffer->sf_buf, fd); ! } ! break; ! default: ! /* A sendfile buffer. */ ! n = sendfile(fd, buffer->sf_fd, &buffer->sf_off, buffer->off); ! break; ! } #else n = send(fd, buffer->buffer, buffer->off, 0); #endif Here's a simple web server that uses sendfile: /* A libevent sendfile webserver. Opens a single file, stats it to get its size, and serves it via a sendfile evbuffer. Compile with cc -levent sfhttpd.c -o sfhttpd The run sfhttpd where file is a large file. Then point apachebench at it, e.g. ab -n 10000 -c 1000 localhost:8080/ */ #include #include #include #include #include int fd; off_t size; static void http_callback(struct evhttp_request *req, void *ign) { /* To turn an existing, empty evbuffer into a sendfile buffer, assign it a sendfile fd (sf_fd) and set length and offset of the data. */ req->output_buffer->sf_fd = fd; req->output_buffer->sf_off = 0; req->output_buffer->off = size; evhttp_send_reply(req, HTTP_OK, "OK", NULL); } int main(int argc, char **argv) { char *file = argv[1]; fd = open(file, O_RDONLY); struct stat stat; fstat(fd, &stat); size = stat.st_size; event_init(); struct evhttp *httpd = evhttp_new(NULL); evhttp_bind_socket(httpd, "127.0.0.1", 8080); evhttp_set_gencb(httpd, http_callback, NULL); event_dispatch(); } Whaddaya think? Manuel Simoni From provos at citi.umich.edu Thu May 8 02:47:09 2008 From: provos at citi.umich.edu (Niels Provos) Date: Thu May 8 02:47:25 2008 Subject: [Libevent-users] Patch: useful sendfile for HTTP servers (1.4.3-stable) In-Reply-To: <37707ed10805072331t2b4bf45dreea273c33a779fc7@mail.gmail.com> References: <37707ed10805072331t2b4bf45dreea273c33a779fc7@mail.gmail.com> Message-ID: <850f7cbe0805072347x3a2f4862ua465365e997f1157@mail.gmail.com> Hi Manual, this is a good suggestion. Nick and I are currently working on how buffers and http work in libevent 2.0. You might want to check out trunk to see some of the progress there. In any case, it seems that your sendfile changes would be a good fit there. BTW, sendfile is available on a large number of platforms now. Niels. On Wed, May 7, 2008 at 11:31 PM, Manuel Simoni wrote: > [Resending because apparently it didn't get through yesterday.] > > Hi, > > my HTTP server thingy came to a screeching halt when serving many > large files, so I added a form of Linux sendfile support that requires > just a few changes and supports some interesting uses (e.g. sending > the HTTP headers normally but the HTTP body via sendfile). > > The server now runs very fast, with very little CPU and RAM. This is > preliminary, probably buggy, and I don't understand the evbuffer > functionality very well (e.g. draining). > > > In addition to the normal data evbuffers, this patch adds two types of > evbuffers: (1) sendfile buffers, and (2) data buffers to which a > sendfile buffer has been added. This distinction is recorded in the > sf_fd field. There are two additonal fields, sf_off and sf_buf. > > > *** libevent-1.4.3-stable/event.h 2008-02-23 02:36:12.000000000 +0100 > --- libevent-1.4.3-stable-sendfile/event.h 2008-05-07 > 15:40:32.000000000 +0200 > *************** > *** 724,729 **** > --- 724,746 ---- > size_t totallen; > size_t off; > > + /* > + sf_fd == -1. A standard data buffer. sf_off and sf_buf are > + unused. > + > + sf_fd == -2. A buffer to which a sendfile buffer has been > + added at the end (sf_buf). off holds the combined size of > + the RAM data of this buffer and the added sendfile buffer. > + sf_off is unused. > + > + sf_fd >= 0. A pure sendfile buffer. sf_fd, sf_off, and off > + are the arguments in_fd, offset, and count to sendfile(), > + respectively. sf_buf is unused. > + */ > + int sf_fd; > + off_t sf_off; > + struct evbuffer *sf_buf; > + > void (*cb)(struct evbuffer *, size_t, size_t, void *); > void *cbarg; > }; > > > > > The adding and writing of buffers (evbuffer_add_buffer, > evbuffer_write) is changed: > > To keep it simple this system only allows adding a sendfile buffer to > a data buffer. So, the sendfile buffer must be the last step in the > chain, which works fine for e.g. many HTTP uses cases. You cannot add > a sendfile buffer to another sendfile buffer, or add a data buffer to > a sendfile buffer. I think these things would theoretically be > possible, but require a lot more housekeeping than the current > solution, which plugs directly into the existing draining code. > > When a sendfile buffer is added after a data buffer, we trick and > increment the data buffer's length by the length of the sendfile > buffer, without actually copying the data to the buffer (which would > completely defeat the purpose of sendfile, of course). Then, later > when it comes to writing this combined buffer, we just need to check > whether all "normal" data has been written, and then switch over to > writing the sendfile data. This *seems* to work nicely but I am not > 100% sure that every situation is handled OK. > > > *** libevent-1.4.3-stable/buffer.c 2007-11-12 03:37:32.000000000 +0100 > --- libevent-1.4.3-stable-sendfile/buffer.c 2008-05-07 > 16:36:44.000000000 +0200 > *************** > *** 61,66 **** > --- 61,68 ---- > #include > #endif > > + #include > + > #include "event.h" > #include "config.h" > > *************** > *** 71,76 **** > --- 73,81 ---- > > buffer = calloc(1, sizeof(struct evbuffer)); > > + /* Make all buffers non-sendfile buffers initially. */ > + buffer->sf_fd = -1; > + > return (buffer); > } > > *************** > *** 100,105 **** > --- 105,130 ---- > { > int res; > > + if (outbuf->sf_fd == -1) { > + /* The output buffer is a data buffer. */ > + if (inbuf->sf_fd >= 0) { > + /* The input buffer is a sendfile buffer. > + Mark this buffer as containing a sendfile > + buffer and "virtually" extend the buffer by > + the size of the sendfile buffer. */ > + outbuf->sf_fd = -2; > + outbuf->sf_buf = inbuf; > + outbuf->off += inbuf->off; > + return 0; > + } > + } else { > + /* No support for nested or concatenated sendfile > + buffers, i.e. if the output buffer is or contains a > + sendfile buffer, we cannot add another sendfile > + buffer to it. */ > + return -1; > + } > + > /* Short cut for better performance */ > if (outbuf->off == 0) { > struct evbuffer tmp; > *************** > *** 415,421 **** > int n; > > #ifndef WIN32 > ! n = write(fd, buffer->buffer, buffer->off); > #else > n = send(fd, buffer->buffer, buffer->off, 0); > #endif > --- 440,467 ---- > int n; > > #ifndef WIN32 > ! switch(buffer->sf_fd) { > ! case -1: > ! /* A data buffer. */ > ! n = write(fd, buffer->buffer, buffer->off); > ! break; > ! case -2: > ! /* A data buffer with a sendfile buffer at the end. > ! First write the actual data in the buffer, then > ! switch to the sendfile data. */ > ! if (buffer->off > buffer->sf_buf->off) { > ! n = write(fd, > ! buffer->buffer, > ! buffer->off - buffer->sf_buf->off); > ! } else { > ! n = evbuffer_write(buffer->sf_buf, fd); > ! } > ! break; > ! default: > ! /* A sendfile buffer. */ > ! n = sendfile(fd, buffer->sf_fd, &buffer->sf_off, buffer->off); > ! break; > ! } > #else > n = send(fd, buffer->buffer, buffer->off, 0); > #endif > > > > Here's a simple web server that uses sendfile: > > > /* > A libevent sendfile webserver. Opens a single file, stats it to get > its size, and serves it via a sendfile evbuffer. > > Compile with > cc -levent sfhttpd.c -o sfhttpd > > The run > sfhttpd > where file is a large file. > > Then point apachebench at it, e.g. > ab -n 10000 -c 1000 localhost:8080/ > */ > #include > #include > #include > #include > #include > > int fd; > off_t size; > > static void > http_callback(struct evhttp_request *req, void *ign) > { > /* To turn an existing, empty evbuffer into a sendfile buffer, > assign it a sendfile fd (sf_fd) and set length and offset > of the data. */ > req->output_buffer->sf_fd = fd; > req->output_buffer->sf_off = 0; > req->output_buffer->off = size; > evhttp_send_reply(req, HTTP_OK, "OK", NULL); > } > > int > main(int argc, char **argv) > { > char *file = argv[1]; > fd = open(file, O_RDONLY); > struct stat stat; > fstat(fd, &stat); > size = stat.st_size; > event_init(); > struct evhttp *httpd = evhttp_new(NULL); > evhttp_bind_socket(httpd, "127.0.0.1", 8080); > evhttp_set_gencb(httpd, http_callback, NULL); > event_dispatch(); > } > > > Whaddaya think? > > Manuel Simoni > _______________________________________________ > Libevent-users mailing list > Libevent-users@monkey.org > http://monkeymail.org/mailman/listinfo/libevent-users > > From jass.zhao at gmail.com Thu May 8 06:00:12 2008 From: jass.zhao at gmail.com (Jass Zhao) Date: Thu May 8 06:00:34 2008 Subject: [Libevent-users] Error of evsigcaught Message-ID: <15b237c40805080300v5cc2363v70ee8dbb28a6b247@mail.gmail.com> Hi, I ran into some problem when I try to call event_init(). Not sure what the following evsigcaught value indicates? An error? evsigcaught = {0, 0, 0, 0, 0, 0, 0, -1208486080, 0, 134305, 0 } Thanks, Peng -------------- next part -------------- An HTML attachment was scrubbed... URL: http://monkeymail.org/archives/libevent-users/attachments/20080508/96038cc5/attachment.htm From nickm at freehaven.net Thu May 8 10:33:21 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 8 10:35:35 2008 Subject: [Libevent-users] Patch: useful sendfile for HTTP servers (1.4.3-stable) In-Reply-To: <850f7cbe0805072347x3a2f4862ua465365e997f1157@mail.gmail.com> References: <37707ed10805072331t2b4bf45dreea273c33a779fc7@mail.gmail.com> <850f7cbe0805072347x3a2f4862ua465365e997f1157@mail.gmail.com> Message-ID: <20080508143321.GQ1379@moria.seul.org> On Wed, May 07, 2008 at 11:47:09PM -0700, Niels Provos wrote: > Hi Manual, > > this is a good suggestion. Nick and I are currently working on how > buffers and http work in libevent 2.0. You might want to check out > trunk to see some of the progress there. In any case, it seems that > your sendfile changes would be a good fit there. BTW, sendfile is > available on a large number of platforms now. In fact, this fits pretty well into the newer evbuffer implementation. Whereas the old implementation used a big chunk of memory for the entire buffer, the new code uses a linked list of small chunks. (This removes the need for big memmov operations, and generally makes writing big files more efficient.) All we'd need to do to support sendfile is add another chunk type whose contents were a file rather than a chunk of ram. We'd probably want at least two ways to "add a file at this point in the stream": one taking a filename and one taking an fd. Of course, we'd need to make sure to fall back on mmap() for systems lacking sendfile(), and maybe on a series of read() operations on systems lacking mmap(). yrs, -- Nick From lyesjob at gmail.com Thu May 8 11:23:27 2008 From: lyesjob at gmail.com (Lyes Amazouz) Date: Thu May 8 11:24:12 2008 Subject: [Libevent-users] how to compile under cygwin Message-ID: <60d886530805080823lcb086cdv382bdce0d93211bd@mail.gmail.com> Hello list, I want to make running my application, which is a sipmle file server, under cygwin. It compiles well and I can run it. But when I try to make a request on it, it makes a "segementation fault" error. Have I missed something in the compilation? how can I correct this. This application has ran very well under Linux system. Has the libevent missed some considerations under cygwin? -- =========== | Lyes Amazouz | USTHB, Algiers =========== -------------- next part -------------- An HTML attachment was scrubbed... URL: http://monkeymail.org/archives/libevent-users/attachments/20080508/996ff258/attachment.htm From nickm at freehaven.net Thu May 8 11:29:00 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 8 11:29:33 2008 Subject: [Libevent-users] how to compile under cygwin In-Reply-To: <60d886530805080823lcb086cdv382bdce0d93211bd@mail.gmail.com> References: <60d886530805080823lcb086cdv382bdce0d93211bd@mail.gmail.com> Message-ID: <20080508152900.GT1379@moria.seul.org> On Thu, May 08, 2008 at 05:23:27PM +0200, Lyes Amazouz wrote: > Hello list, > I want to make running my application, which is a sipmle file server, under > cygwin. It compiles well and I can run it. But when I try to make a request > on it, it makes a "segementation fault" error. > Have I missed something in the compilation? how can I correct this. > > This application has ran very well under Linux system. Has the libevent > missed some considerations under cygwin? I haven't tried cygwin in a while, but it used to work fine. To learn more about where the bug is here, it might help if you can get a stack trace (using gdb) to figure out where the segfault is occurring. Also, if you can send a very small example thing that reproduces the bug for you, that would help too. Finally, make sure you're using Libevent 1.4.3 (or wait for Libevent 1.4.4, which should come out in the next 48 hours): they should be way less buggy than many older versions. yrs, -- Nick From lyesjob at gmail.com Thu May 8 12:14:37 2008 From: lyesjob at gmail.com (Lyes Amazouz) Date: Thu May 8 12:15:06 2008 Subject: [Libevent-users] how to compile under cygwin In-Reply-To: <20080508152900.GT1379@moria.seul.org> References: <60d886530805080823lcb086cdv382bdce0d93211bd@mail.gmail.com> <20080508152900.GT1379@moria.seul.org> Message-ID: <60d886530805080914s5fb344d7j6c349e1594fa9f8b@mail.gmail.com> Skipped content of type multipart/alternative-------------- next part -------------- A non-text attachment was scrubbed... Name: warcserver[1].exe.stackdump.zip Type: application/zip Size: 752 bytes Desc: not available Url : http://monkeymail.org/archives/libevent-users/attachments/20080508/c7cc160c/warcserver1.exe.stackdump-0001.zip -------------- next part -------------- A non-text attachment was scrubbed... Name: warcserver[1].exe.strace.zip Type: application/zip Size: 9851 bytes Desc: not available Url : http://monkeymail.org/archives/libevent-users/attachments/20080508/c7cc160c/warcserver1.exe.strace-0001.zip From lyesjob at gmail.com Thu May 8 12:17:37 2008 From: lyesjob at gmail.com (Lyes Amazouz) Date: Thu May 8 12:17:42 2008 Subject: Fwd: [Libevent-users] how to compile under cygwin In-Reply-To: <60d886530805080914s5fb344d7j6c349e1594fa9f8b@mail.gmail.com> References: <60d886530805080823lcb086cdv382bdce0d93211bd@mail.gmail.com> <20080508152900.GT1379@moria.seul.org> <60d886530805080914s5fb344d7j6c349e1594fa9f8b@mail.gmail.com> Message-ID: <60d886530805080917w739c5548ucc27599d162d2c3e@mail.gmail.com> ---------- Forwarded message ---------- From: Lyes Amazouz Date: May 8, 2008 6:14 PM Subject: Re: [Libevent-users] how to compile under cygwin To: Nick Mathewson , Lyes Amazouz , libevent-users@monkey.org On 5/8/08, Nick Mathewson wrote: > > I haven't tried cygwin in a while, but it used to work fine. To learn > more about where the bug is here, it might help if you can get a stack > trace (using gdb) to figure out where the segfault is occurring. > Also, if you can send a very small example thing that reproduces the > bug for you, that would help too. > > Finally, make sure you're using Libevent 1.4.3 (or wait for Libevent > 1.4.4, which should come out in the next 48 hours): they should be way > less buggy than many older versions. > > yrs, > -- > Nick > Sorry, this message is to be before the rattachements: Thanks for you quick reponse. I'll wait for 1.4.4. In the mean time, could you please find a complete GDB and STRACE logs (attached). All the best Lyes 1) GDB TRACE: 1.1) Start GDB: $ gdb app/warcserver.exe GNU gdb 6.8.0.20080328-cvs (cygwin-special) Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-cygwin"... (gdb) r -i 10.211.55.4 -p 7777 -x tmp Starting program: /cygdrive/c/warc-tools-read-only/app/warcserver.exe -i 10.211.55.4 -p 7777 -x tmp [New thread 532.0xa7c] [New thread 532.0xf7c] Starting the WARC Server ... 1.2) Send a request : curl http://10.211.55.4:7777/WARC/0.17 1.3) Return to GDB: [New thread 532.0x8c0] 10 [main] warcserver 532 _cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION 989 [main] warcserver 532 open_stackdumpfile: Dumping stack trace to warcserver.exe.stackdump 210501 [main] warcserver 532 _cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION 211948 [main] warcserver 532 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack) Program received signal SIGSEGV, Segmentation fault. 0x61016583 in stack_info::walk () from /usr/bin/cygwin1.dll (gdb) backtrace #0 0x61016583 in stack_info::walk () from /usr/bin/cygwin1.dll #1 0x7c859bb0 in OutputDebugStringA () from /cygdrive/c/WINDOWS/system32/kernel32.dll #2 0x40010006 in ?? () #3 0x00000000 in ?? () (gdb) 1.4) Please find attached the coredump (warcserver.exe.stackdump) 2) STRACE: 2.1) Launch the application with STRACE: $ strace ./app/warcserver.exe -i 10.211.55.4 -p 7777 -x tmp &>warcserver.exe.strace 2398351 [main] warcserver 4044 _cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION 2567102 [main] warcserver 4044 open_stackdumpfile: Dumping stack trace to warcserver.exe.stackdump 2756096 [main] warcserver 4044 _cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION 2758951 [main] warcserver 4044 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack) 2.2) Please find attached the STRACE log (warcserver.exe.strace) -- =========== | Lyes Amazouz | USTHB, Algiers =========== -- =========== | Lyes Amazouz | USTHB, Algiers =========== -------------- next part -------------- An HTML attachment was scrubbed... URL: http://monkeymail.org/archives/libevent-users/attachments/20080508/247a2cc7/attachment.htm From william at 25thandClement.com Thu May 8 12:56:43 2008 From: william at 25thandClement.com (William Ahern) Date: Thu May 8 13:00:40 2008 Subject: [Libevent-users] Patch: useful sendfile for HTTP servers (1.4.3-stable) In-Reply-To: <20080508143321.GQ1379@moria.seul.org> References: <37707ed10805072331t2b4bf45dreea273c33a779fc7@mail.gmail.com> <850f7cbe0805072347x3a2f4862ua465365e997f1157@mail.gmail.com> <20080508143321.GQ1379@moria.seul.org> Message-ID: <20080508165643.GA31998@wilbur.25thandClement.com> On Thu, May 08, 2008 at 10:33:21AM -0400, Nick Mathewson wrote: > On Wed, May 07, 2008 at 11:47:09PM -0700, Niels Provos wrote: > > Hi Manual, > > > > this is a good suggestion. Nick and I are currently working on how > > buffers and http work in libevent 2.0. You might want to check out > > trunk to see some of the progress there. In any case, it seems that > > your sendfile changes would be a good fit there. BTW, sendfile is > > available on a large number of platforms now. > > In fact, this fits pretty well into the newer evbuffer implementation. > Whereas the old implementation used a big chunk of memory for the > entire buffer, the new code uses a linked list of small chunks. (This > removes the need for big memmov operations, and generally makes > writing big files more efficient.) > > All we'd need to do to support sendfile is add another chunk type > whose contents were a file rather than a chunk of ram. We'd probably > want at least two ways to "add a file at this point in the stream": > one taking a filename and one taking an fd. Of course, we'd need to > make sure to fall back on mmap() for systems lacking sendfile(), and > maybe on a series of read() operations on systems lacking mmap(). On Linux, I'd bet that AIO+splice can beat sendfile. The problem with sendfile is that it can still block on file I/O. This is one major reason why sendfile is no good for multimedia servers, _unless_ you're willing to juggle and manage multiple threads (w/ the headache of profiling access patterns and adjusting number of threads). On Linux, though, you could have one thread doing kernel AIO from a file into a pipe using vmsplice, and a second thread running the event loop (or N+M threads, where N is your number of cores--an easier calculation.) This leads into the second issue, which is how best to manage vmsplice buffers, which needs to be page aligned, and have certain ownership restrictions. The upside is that it's the only feasible way in any unix (that I'm aware of) to actually get a page of file data into a buffer without worrying about (a) blocking, (b) dealing with POSIX AIO readiness signalling, or (c) copying the data. _Also_, this allows a potential single code pathway for either encrypted or plaintext I/O; for encrypted you'd just insert a filter, and write the new data to a new page buffer. (Given all the recent political "issues" lately, it's disconcerting that more people are giving thought to moving the net toward ubiquitous encryption; including reducing the overhead so there are few excuses.) One caveat w/ the non-blocking splice setup is how to handle seeking. But that can be dealt with as a matter of course. Anyhow, next month I'll have some code and hopefully some numbers. From dan at sunsaturn.com Thu May 8 18:05:20 2008 From: dan at sunsaturn.com (Dan) Date: Thu May 8 18:05:43 2008 Subject: [Libevent-users] FYI: libevent/libev benchmark updated for libevent-1.4.3 In-Reply-To: <20080508204048.GA13890@schmorp.de> References: <20080507154238.GA9421@schmorp.de> <20080508204048.GA13890@schmorp.de> Message-ID: Its to bad when people write emails like this, clearly no social skills. Yeah I suggested I was a noob just to see if he was an asshole, and guess what! :) Have a couple emails as well of him making personal attacks against my family and such, its really to bad, I feel sorry for him, but I'll leave it at that... Dan. On Thu, 8 May 2008, Marc Lehmann wrote: > On Thu, May 08, 2008 at 12:03:06AM -0500, Dan wrote: >> Think I tried Ev once, to many bugs, hell couldn't even set a timer within >> a timer as I remember, > > In no release ever was there such a bug. libev and EV are used in many > production environments and projects, too and have proven their stability > by now. > > FYI: This dan guy is not an unknown, he regularly trolls, and has proven > many times that he has no clue of programming, how to pass arguments > etc.. This is from his earlier mails: > > From: Dan > Date: Sun, 20 Apr 2008 01:55:04 -0500 (CDT) > #> Like your perl EV module but kinda pointless without letting us have args. > #> > #> need to do $blah->blah($a,$b,\%c,\@d); > #> > #> I notice new version out of libevent....are you going to maintain this? > #> Like to make this my event library.... > > (So his main problem was not having a clue about the programming language > he wanted to use, namely Perl). > > From: Dan > Date: Sun, 20 Apr 2008 23:39:56 -0500 (CDT) > #> Sorry I am abit of a noob to events still. I been doing alot of research > #> on what the fastest, best module would be to use and yours seems like it > #> would be by far the fastest and use the least memory. > [...] > #> What I thought I would do is use your excellent module and use events. > > So back then it was an excellent module for you, that is, until I told you to > read a good book about perl first. > > Apparently, you don't want to improve your programming skills, lieing > about other people's work is enough for you. Try again. > >> This EV stuff just meant to undermine the hardwork of the folks at >> libevent? > > No, you are just an idiot, and a bad liar and top. > > The benchmark document explains exactly how these timings were derived > and how to reproduce them, including the source to the benchmark, exact > version numbers for the libraires used, compiler flags etc., for everybody > to verify. If you don't believe the numbers you can verify them yourself, > as well as the validity of the benchmark numbers and the implementation. > > You are certainly not doing the libevent developers any good by trolling > and spreading lies: I am sure they don't need the support of fanboys like > you. > > -- > The choice of a Deliantra, the free code+content MORPG > -----==- _GNU_ http://www.deliantra.net > ----==-- _ generation > ---==---(_)__ __ ____ __ Marc Lehmann > --==---/ / _ \/ // /\ \/ / pcg@goof.com > -=====/_/_//_/\_,_/ /_/\_\ > From nickm at freehaven.net Thu May 8 18:41:01 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 8 18:41:43 2008 Subject: [Libevent-users] FYI: libevent/libev benchmark updated for libevent-1.4.3 In-Reply-To: References: <20080507154238.GA9421@schmorp.de> <20080508204048.GA13890@schmorp.de> Message-ID: <20080508224101.GC14680@moria.seul.org> On Thu, May 08, 2008 at 05:05:20PM -0500, Dan wrote: > > > Its to bad when people write emails like this, clearly no social skills. Dan, please take this off-list. This kind of flamewar does not help libevent, libev, or anybody. yrs, -- Nick From nickm at freehaven.net Fri May 9 00:13:11 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Fri May 9 00:13:38 2008 Subject: [Libevent-users] Success compile libevent 1.4.3 with VC6 In-Reply-To: <480F3ACC.6010102@mail.ru> References: <480F3ACC.6010102@mail.ru> Message-ID: <20080509041310.GA4518@moria.seul.org> On Wed, Apr 23, 2008 at 05:34:04PM +0400, Eugene 'HMage' Bujak wrote: > Hi, > > I want to submit a more complete patch for VC6. > > This one makes all elements of the code compilable and this code is > being used on a production-level project at work. > > The patch is in attachment. Compiles and works under VC6. > * signal_test works. > * timer_test works. > * event_test fails due to the reason that win32 select() can't work on > anything but network sockets. > > Most importantly, my code that runs perfectly well on unix (linux & > freebsd) now runs on windows with little modification. > > But: > * Didn't try to run any other tests since there are no project files for > them. > * Didn't test how mingw32 copes with these changes either. Okay, I've gone through this patch again, under VC++2005. I think my earlier issues still stand, so here's where we are: > The main changes are: > * INPUT and OUTPUT are defined in platform SDK, so I had to redefine > them as EVRPC_INPUT and EVRPC_OUTPUT. See notes in previous patch. > * uint64_t on MSVC must be defined as unsigned __int64 > * int64_t on MSVC is to be defined as signed __int64 Should be fixed. > * MSVC6 doesn't know about __func__ and the #ifdefs weren't guarding > against them good enough. This is just the changes in the sample dir, right? As near as I can tell, the change in config.h shouldn't be necessary, yes? > * winsock2.h sometimes was included after windows.h, that lead to > compiler errors in libevent. Fixed. > * select.c can be painlessly excluded from compilation in win32, but I > still fixed it's compilation. There's no point in including it; it shouldn't be in the win32 project. > * Winsock library needs to be initialized and freed explicitly on win32. Haven't applied yet. > * http.c was using sockaddr_storage. There isn't one in MSVC. Using > sockaddr is good enough for MSVC. Checking for msc isn't right here: newer sdks do indeed seem to define sockaddr_storage. > * There are tons of compiler warnings regarding "do {} while(0);" Sorry, which part fixes this? > * I took the liberty to add #pragma to the WIN32-section of the event.h > so that there's no need to put ws2_32 library into the linker explicitly. > * There's no NFDBITS in msvc. Shouldn't be needed if we don't use the select.c file. > * vsnprintf() is _vsnprintf() for some weird reason on win32. Actually, this underscores a deeper problem. Windows vsnprintf returns -1 if the result is too big for the buffer, but this is not what libevent expects in a lot of places. We need to solve this one. I'm filing a bug here so we don't forget about it. > * I've had to bump tv->tv_usec to 1000 to prevent eating 100% of the cpu > core in win32 dispatch when using timers with events each 10ms or so. Hm? If the timers are happening every 10 ms, then the usec field should be at least 10000 already. If there's a small example here to help me wrap my head around the problem, that would be great. > * Also I've provided a gettimeofday() wrapper that uses timeGetTime() > instead of much slower _ftime(). Unfortunately, this will probably turn out to give unreliable results, as it wraps every 49 days. Thus, roughly 1 day out of 50, users' timers will all go off way too early or not at all, depending. Still, it's a shame to use a slow time interface. I hear GetSystemTimeAsFileTime() [or whatever it's called] has a high resolution, but I hear it preforms badly on win9x. Perhaps if we're feeling nutty, we could cobble something monotonic together out of time() and timeGetTime(), like: int fake_gettimeofday(struct timeval *tv, struct timezone *tz) { /* Threadsafety? What threadsafety? Also, not tested. */ static DWORD last_timeGetTime_result = 0; static long seconds_offset = 0; DWORD now = timeGetTime(); time_t seconds = now / 1000; if (!seconds_offset || now < last_timeGetTime_result) { /* Called for the first time, or wrapping around. */ seconds_offset = time(NULL) - seconds; } tv->tv_sec = seconds + seconds_offset; tv->tv_usec = (now % 1000) * 1000; last_timeGetTime_result = now; return 0; } In any case, 1.4.4 will call gettimeofday a lot less frequently than 1.4.3; maybe the ftime() call won't hurt as much now? From daniminas at gmail.com Fri May 9 09:16:28 2008 From: daniminas at gmail.com (Daniel Morales) Date: Fri May 9 09:16:54 2008 Subject: [Libevent-users] libevent and autotools In-Reply-To: <20080423043807.GC24086@moria.seul.org> References: <20080423043807.GC24086@moria.seul.org> Message-ID: Skipped content of type multipart/alternative-------------- next part -------------- A non-text attachment was scrubbed... Name: pkgconfig.patch Type: text/x-diff Size: 949 bytes Desc: not available Url : http://monkeymail.org/archives/libevent-users/attachments/20080509/d3656c56/pkgconfig-0001.bin From C.Rzewuski at elka.pw.edu.pl Fri May 9 15:50:51 2008 From: C.Rzewuski at elka.pw.edu.pl (Cezary Rzewuski) Date: Fri May 9 16:00:41 2008 Subject: [Libevent-users] garbage collection in libevent In-Reply-To: <850f7cbe0804271334w6652bbb8pc8770446b5c1e4db@mail.gmail.com> References: <850f7cbe0804271334w6652bbb8pc8770446b5c1e4db@mail.gmail.com> Message-ID: <4824AB1B.2060003@elka.pw.edu.pl> Niels Provos wrote: > You could try to use event_set_mem_functions() to change the functions > that libevent uses for memory allocation internally. > > Which function exactly do you mean? I'd like to change memory allocation function to detect memory leaks, but I cannot find event_set_mem_functions nor by grepping libevent source neither through google. Cezary Rzewuski From C.Rzewuski at elka.pw.edu.pl Mon May 12 06:33:50 2008 From: C.Rzewuski at elka.pw.edu.pl (Cezary Rzewuski) Date: Mon May 12 06:55:18 2008 Subject: [Libevent-users] http input buffer deallocation problem Message-ID: <48281D0E.1090209@elka.pw.edu.pl> Hello, I'm experiencing problem with memory freeing in libevent (1.4.3 stable). I've implemented proxy server using libevent http functions. Everything works OK as long as the workload isn't heavy - then memory allocations grows rapidly. Memory leak detection tool (I use memoryscape from totalview technologies) told me that allocation of memory that isn't deallocated is done in evbuffer_expand function (when realloc is called). The backtrace is: event_dispatch event_loop event_base_loop event_read_body evbuffer_add evbuffer_expand When I use tool like wget to download file, everything works fine. But when it's proxying crawler requests (which meany heavy workload) the heap grows. I suspect there may be two reasons, but I don't know if this how libevent works: 1) there is any priority in events processed in libevent, and buffer deallocation remains in the tail of events queue 2) may be there is any HTTP header that causes libevent to postpone closing connection (which crawler uses but wget not). Any help appreciated. Best regards, Cezary Rzewuski From phil at ultimate.com Mon May 12 17:39:51 2008 From: phil at ultimate.com (Phil Budne) Date: Mon May 12 17:40:53 2008 Subject: [Libevent-users] patch for "realtime signal" events in libevent-1.4.3-stable Message-ID: <200805122139.m4CLdp3s013588@ultimate.com> I needed to do apples-to-apples comparison between rtsignals and epoll for a client, so I fixed rtsig.c from 1.3e (see an earlier post) to compile, then fixed it to work, and ported that to 1.4.3-stable. NOTE WELL! Used only for benchmarking: the rtsig_dealloc routine may not free everything it needs to! Below are are diffs than can be applied by "patch" to libevent-1.4.3-stable.tar.gz; then run: ./autogen.sh ./configure --with-rtsig I also added a command line argument to bench.c to allow me to specify how many trials are performed. Many many thanks to Scott Lamb for posting "chartbench.py" http://monkeymail.org/archives/libevent-users/2007-December/001085.html and to the authors of libevent for giving me a platform I could perform the testing on! --- ./Makefile.in.orig 2008-04-05 17:06:34.000000000 -0400 +++ Makefile.in 2008-05-09 20:51:20.000000000 -0400 @@ -40,7 +40,7 @@ $(srcdir)/config.h.in $(top_srcdir)/configure ChangeLog \ config.guess config.sub devpoll.c epoll.c epoll_sub.c evport.c \ install-sh kqueue.c ltmain.sh missing mkinstalldirs poll.c \ - select.c signal.c + rtsig.c select.c signal.c ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ --- ./event.c.orig 2008-02-25 02:34:37.000000000 -0500 +++ event.c 2008-05-09 20:38:32.000000000 -0400 @@ -78,6 +78,9 @@ #ifdef WIN32 extern const struct eventop win32ops; #endif +#ifdef HAVE_RTSIG +extern const struct eventop rtsigops; +#endif /* In order of preference */ const struct eventop *eventops[] = { @@ -102,6 +105,9 @@ #ifdef WIN32 &win32ops, #endif +#ifdef HAVE_RTSIG + &rtsigops, +#endif NULL }; --- ./config.h.in.orig 2008-05-09 20:40:59.000000000 -0400 +++ config.h.in 2008-05-09 20:53:11.000000000 -0400 @@ -78,6 +78,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_PORT_H +/* Define if your system supports POSIX realtime signals */ +#undef HAVE_RTSIG + /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT @@ -93,6 +96,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H +/* Define to 1 if you have the `sigtimedwait' function. */ +#undef HAVE_SIGTIMEDWAIT + /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H @@ -192,6 +198,9 @@ /* Define if kqueue works correctly with pipes */ #undef HAVE_WORKING_KQUEUE +/* Define if realtime signals work on pipes */ +#undef HAVE_WORKING_RTSIG + /* Name of package */ #undef PACKAGE --- ./event-config.h.orig 2008-04-05 17:06:51.000000000 -0400 +++ event-config.h 2008-05-09 20:53:54.000000000 -0400 @@ -9,13 +9,13 @@ /* config.h.in. Generated from configure.in by autoheader. */ /* Define if clock_gettime is available in libc */ -/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */ +#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1 /* Define is no secure id variant is available */ -#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 +/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */ /* Define to 1 if you have the `clock_gettime' function. */ -/* #undef _EVENT_HAVE_CLOCK_GETTIME */ +#define _EVENT_HAVE_CLOCK_GETTIME 1 /* Define if /dev/poll is available */ /* #undef _EVENT_HAVE_DEVPOLL */ @@ -24,10 +24,10 @@ #define _EVENT_HAVE_DLFCN_H 1 /* Define if your system supports the epoll system calls */ -/* #undef _EVENT_HAVE_EPOLL */ +#define _EVENT_HAVE_EPOLL 1 /* Define to 1 if you have the `epoll_ctl' function. */ -/* #undef _EVENT_HAVE_EPOLL_CTL */ +#define _EVENT_HAVE_EPOLL_CTL 1 /* Define if your system supports event ports */ /* #undef _EVENT_HAVE_EVENT_PORTS */ @@ -54,16 +54,16 @@ #define _EVENT_HAVE_INTTYPES_H 1 /* Define to 1 if you have the `kqueue' function. */ -#define _EVENT_HAVE_KQUEUE 1 +/* #undef _EVENT_HAVE_KQUEUE */ /* Define to 1 if you have the `nsl' library (-lnsl). */ -/* #undef _EVENT_HAVE_LIBNSL */ +#define _EVENT_HAVE_LIBNSL 1 /* Define to 1 if you have the `resolv' library (-lresolv). */ #define _EVENT_HAVE_LIBRESOLV 1 /* Define to 1 if you have the `rt' library (-lrt). */ -/* #undef _EVENT_HAVE_LIBRT */ +#define _EVENT_HAVE_LIBRT 1 /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef _EVENT_HAVE_LIBSOCKET */ @@ -86,6 +86,9 @@ /* Define to 1 if you have the header file. */ /* #undef _EVENT_HAVE_PORT_H */ +/* Define if your system supports POSIX realtime signals */ +#define _EVENT_HAVE_RTSIG 1 + /* Define to 1 if you have the `select' function. */ #define _EVENT_HAVE_SELECT 1 @@ -101,6 +104,9 @@ /* Define to 1 if you have the header file. */ #define _EVENT_HAVE_SIGNAL_H 1 +/* Define to 1 if you have the `sigtimedwait' function. */ +#define _EVENT_HAVE_SIGTIMEDWAIT 1 + /* Define to 1 if you have the header file. */ #define _EVENT_HAVE_STDARG_H 1 @@ -117,7 +123,7 @@ #define _EVENT_HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ -#define _EVENT_HAVE_STRLCPY 1 +/* #undef _EVENT_HAVE_STRLCPY */ /* Define to 1 if you have the `strsep' function. */ #define _EVENT_HAVE_STRSEP 1 @@ -135,10 +141,10 @@ /* #undef _EVENT_HAVE_SYS_DEVPOLL_H */ /* Define to 1 if you have the header file. */ -/* #undef _EVENT_HAVE_SYS_EPOLL_H */ +#define _EVENT_HAVE_SYS_EPOLL_H 1 /* Define to 1 if you have the header file. */ -#define _EVENT_HAVE_SYS_EVENT_H 1 +/* #undef _EVENT_HAVE_SYS_EVENT_H */ /* Define to 1 if you have the header file. */ #define _EVENT_HAVE_SYS_IOCTL_H 1 @@ -198,7 +204,10 @@ #define _EVENT_HAVE_VASPRINTF 1 /* Define if kqueue works correctly with pipes */ -#define _EVENT_HAVE_WORKING_KQUEUE 1 +/* #undef _EVENT_HAVE_WORKING_KQUEUE */ + +/* Define if realtime signals work on pipes */ +#define _EVENT_HAVE_WORKING_RTSIG 1 /* Name of package */ #define _EVENT_PACKAGE "libevent" --- ./configure.in.orig 2008-04-05 17:03:51.000000000 -0400 +++ configure.in 2008-05-09 20:50:44.000000000 -0400 @@ -32,6 +32,11 @@ dnl AC_DISABLE_SHARED AC_SUBST(LIBTOOL_DEPS) +dnl Check for optional stuff +AC_ARG_WITH(rtsig, + [ --with-rtsig compile with support for real time signals (experimental)], + [usertsig=yes], [usertsig=no]) + dnl Checks for libraries. AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(resolv, inet_aton) @@ -164,10 +169,58 @@ fi havepoll=no +havertsig=no AC_CHECK_FUNCS(poll, [havepoll=yes], ) if test "x$havepoll" = "xyes" ; then AC_LIBOBJ(poll) needsignal=yes + + if test "x$usertsig" = "xyes" ; then + AC_CHECK_FUNCS(sigtimedwait, [havertsig=yes], ) + fi +fi +if test "x$havertsig" = "xyes" ; then + AC_MSG_CHECKING(for F_SETSIG in fcntl.h) + AC_EGREP_CPP(yes, +[ +#define _GNU_SOURCE +#include +#ifdef F_SETSIG +yes +#endif +], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no); havertsig=no]) +fi +if test "x$havertsig" = "xyes" ; then + AC_DEFINE(HAVE_RTSIG, 1, [Define if your system supports POSIX realtime signals]) + AC_LIBOBJ(rtsig) + AC_MSG_CHECKING(for working rtsig on pipes) + AC_TRY_RUN( +[ +#define _GNU_SOURCE +#include +#include +#include + +int sigio() +{ + exit(0); +} + +int main() +{ + int fd[2]; + + pipe(fd); + signal(SIGIO, sigio); + fcntl(fd[0], F_SETOWN, getpid()); + fcntl(fd[0], F_SETSIG, SIGIO); + fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_ASYNC); + write(fd[1], "", 1); + return 1; +} +], [ AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_WORKING_RTSIG, 1, [Define if realtime signals work on pipes])], + AC_MSG_RESULT(no)) fi haveepoll=no --- ./rtsig.c.orig 2008-05-12 17:00:50.000000000 -0400 +++ rtsig.c 2008-05-12 17:00:27.000000000 -0400 @@ -0,0 +1,1018 @@ +/* + * rtsig.c from 1.3e with fixes to compile and run on Fedora 8 + * (2.6.24.5-85.fc8) with libevent-1.4.3-stable to perform + * apples-to-apples benchmarking between rtsig and epoll. + * by Phil Budne + * May 2008 + */ +/* + * Copyright (c) 2006 Mathew Mills + * 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. + */ +/* + * Meta-level comments: You know that a kernel interface is wrong if + * supporting it requires three times more code than any of the other + * kernel interfaces supported in libevent. Niels - 2006-02-22 + */ +/** + + "RTSIG" is a shorthand for using O_ASYNC to make descriptors send + signals when readable/writable and to use POSIX real-time signals + witch are queued unlike normal signals. At first blush this may + seem like a alternative to epoll, but a number of problems arise + when attempting to build an eventloop entirely out of rtsig. + Still, we can use rtsig in combination with poll() to + provide an eventloop that allows for many thousands of sockets + without huge overheads implicit with using select() or poll() + alone. epoll and kqueue are far superior to rtsig and should be + used where available, but rtsig has been in standard Linux kernels + for a long time and have a huge installation base. epoll requires + special patches for 2.4 kernels and 2.6 kernels are not yet nearly + so ubiquitous. + + rtsig problems: + - O_ASYNC mechanisms work only on sockets - not pipes or tty's + + - O_ASYNC signals are edge-triggered, POLLIN on packet arriving + or socket close; POLLOUT when a socket transitions from + non-writable to writable. Being edge-triggered means the + event-handler callbacks must transition the level ( reading + completely the socket buffer contents ) or it will be unable to + reliably receive notification again. + + - rtsig implementations must be intimately involved in how a + process dispatches signals. + + - delivering signals per-event can be expensive, CPU-wise, but + sigtimedwait() blocks on signals only and means non-sockets + cannot be serviced. + + Theory of operation: + This libevent module uses rtsig to allow us to manage a set of + poll-event descriptors. We can drop uninteresting fd's from the + pollset if the fd will send a signal when it becomes interesting + again. + + poll() offers us level-triggering and, when we have verified the + level of a socket, we can trust the edge-trigger nature of the + ASYNC signal. + + As an eventloop we must poll for external events but leverage + kernel functionality to sleep between events ( until the loop's + next scheduled timed event ). + + If we are polling on any non-sockets then we simply have no choice + about blocking on the poll() call. If we blocked on the + sigtimedwait() call as rtsig papers recommend we will not wake on + non-socket state transitions. As part of libevent, this module + must support non-socket polling. + + Many applications, however, do not need to poll on non-sockets and + so this module should be able to optimize this case by using + sigtimedwait(). For this reason this module can actually trigger + events in each of three different ways: + - poll() returning ready events from descriptors in the pollset + + - real-time signals dequeued via sigtimedwait() + + - real-time signals that call an installed signal handler which in + turn writes the contents of siginfo to one end of a socketpair + DGRAM socket. The other end of the socket is always in the + pollset so poll will be guaranteed to return even if the signal is + received before entering poll(). + + non-socket descriptors force us to block on the poll() for the + duration of a dispatch. In this case we unblock (w/ sigprocmask) + the managed signals just before polling. Each managed signal is + handled by signal_handler() which send()'s the contents of siginfo + over the socketpair. Otherwise, we call poll() with a timeout of + 0ms so it checks the levels of the fd's in the pollset and returns + immediately. Any fd that is a socket and has no active state is + removed from the pollset for the next pass -- we will rely on + getting a signal for events on these fd's. + + The receiving end of the siginfo socketpair is in the pollset + (permanently) so if we are polling on non-sockets, the delivery of + signals immediately following sigprocmask( SIG_UNBLOCK...) will + result in a readable op->signal_recv_fd which ensures the poll() + will return immediately. If the poll() call is blocking and a + signal arrives ( possibly a real-time signal from a socket not in + the pollset ) its handler will write the data to the socketpair + and interrupt the poll(). + + After every poll call we attempt a non-blocking recv from the + signal_recv_fd and continue to recv and dispatch the events until + recv indicates the socket buffer is empty. + + One might raise concerns about receiving event activations from + both poll() and from the rtsig data in the signal_recv_fd. + Fortunately, libevent is already structured for event coalescing, + so this issue is mitigated ( though we do some work twice for the + same event making us less efficient ). I suspect that the cost of + turning off the O_ASYNC flag on fd's in the pollset is more + expensive than handling some events twice. Looking at the + kernel's source code for setting O_ASYNC, it looks like it takes a + global kernel lock... + + After a poll and recv-loop for the signal_recv_fd, we finally do a + sigtimedwait(). sigtimedwait will only block if we haven't + blocked in poll() and we have not enqueued events from either the + poll or the recv-loop. Because sigtimedwait blocks all signals + that are not in the set of signals to be dequeued, we need to + dequeue almost all signals and make sure we dispatch them + correctly. We dequeue any signal that is not blocked as well as + all libevent-managed signals. If we get a signal that is not + managed by libevent we lookup the sigaction for the specific + signal and call that function ourselves. + + Finally, I should mention that getting a SIGIO signal indicates + that the rtsig buffer has overflowed and we have lost events. + This forces us to add _every_ descriptor to the pollset to recover. + +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Enable F_SETSIG and F_SETOWN */ +#define _GNU_SOURCE + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "event.h" +#include "event-internal.h" +#include "log.h" + +#ifndef __NR_gettid +#define gettid() getpid() +#else +#if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3))) +#ifdef _syscall0 +_syscall0(pid_t,gettid) +#else +pid_t gettid(void) { + return syscall(__NR_gettid); +} +#endif +#endif + +#endif + +#define EVLIST_NONSOCK 0x1000 /* event is for a non-socket file-descriptor */ +#define EVLIST_DONTDEL 0x2000 /* event should always be in the pollset */ +#define MAXBUFFERSIZE (1024 * 1024 * 2) /* max socketbuffer for signal-spair */ +#define INIT_MAX 16 /* init/min # of fd positions in our pollset */ + +static int signal_send_fd[_NSIG]; /* the globalend of the signal socketpair */ +static int trouble[_NSIG]; /* 1 when signal-handler cant send to signal_send_fd */ + +struct rtdata; +TAILQ_HEAD(rtdata_list, rtdata); + +struct rtsigop { + sigset_t sigs; /* signal mask for all _managed_ signals */ + struct pollfd *poll; /* poll structures */ + struct rtdata **ptodat; /* map poll_position to rtdata */ + int cur; /* cur # fd's in a poll set */ + int max; /* max # fd's in a poll set, start at 16 and grow as needed */ + int total; /* count of fd's we are watching now */ + int signo; /* the signo we use for ASYNC fd notifications */ + int nonsock; /* number of non-socket fd's we are watching */ + int highestfd; /* highest fd accomodated by fdtodat */ + struct rtdata_list **fdtodat; /* map fd to rtdata ( and thus to event ) */ + int signal_recv_fd; /* recv side of the signal_send_fd */ + int signal_send_fd; /* recv side of the signal_send_fd */ + struct event sigfdev; /* our own event structure for the signal fd */ +}; + +struct rtdata { + /* rtdata holds rtsig-private state on each event */ + TAILQ_ENTRY (rtdata) next; + struct event *ev; + int poll_position; +}; + +static void *rtsig_init(struct event_base *); +static int rtsig_add(void *, struct event *); +static int rtsig_del(void *, struct event *); +static int rtsig_dispatch(struct event_base *, void *, struct timeval *); +static void rtsig_dealloc (struct event_base *, void *); + +struct eventop rtsigops = { + "rtsig", + rtsig_init, + rtsig_add, + rtsig_del, + rtsig_dispatch, + rtsig_dealloc, + 1 /* need reinit ??? */ +}; + +static void +signal_handler(int sig, siginfo_t *info, void *ctx) +{ + /* + * the signal handler for all libevent-managed signals only + * used if we need to do a blocking poll() call due to + * non-socket fd's in the pollset. + */ + + siginfo_t *i = info; + siginfo_t i_local; + + if (trouble[sig - 1]) { + i_local.si_signo = SIGIO; + i_local.si_errno = 0; + i_local.si_code = 0; + i = &i_local; + trouble[sig - 1] = 0; + } + + if (send(signal_send_fd[sig - 1], i, sizeof(*i), + MSG_DONTWAIT|MSG_NOSIGNAL) == -1) + trouble[sig - 1] = 1; +} + +static void +donothing(int fd, short event, void *arg) +{ + /* + * callback for our signal_recv_fd event structure + * we don't want to act on these events, we just want to wake the poll() + */ +}; + +static void +signotset(sigset_t *set) +{ + int i, l; + l = sizeof(*set) / 4; + for (i = 0; i < l; i++) { + ((unsigned *)set)[i] = ~((unsigned *)set)[i]; + } +} + +/* The next three functions manage our private data about each event struct */ + +static int +grow_fdset(struct rtsigop *op, int newhigh) +{ + /* + * grow the fd -> rtdata array because we have encountered a + * new fd too high to fit in the existing array + */ + + struct rtdata_list **p; + struct rtdata_list *datset; + int i,x; + int newcnt = (newhigh + 1) << 1; + + if (newhigh <= op->highestfd) + return (0); + + p = op->fdtodat; + p = realloc(op->fdtodat, sizeof(struct rtdata_list *) * newcnt); + if (p == NULL) + return (-1); + op->fdtodat = p; + + datset = calloc(newcnt - (op->highestfd + 1), + sizeof(struct rtdata_list)); + if (datset == NULL) + return (-1); + + for (i = op->highestfd + 1, x = 0; i < newcnt; i++, x++) { + op->fdtodat[i] = &(datset[x]); + TAILQ_INIT(op->fdtodat[i]); + } + + op->highestfd = newcnt - 1; + return (0); +} + +static struct rtdata * +ev2dat(struct rtsigop *op, struct event *ev, int create) +{ + /* + * given an event struct, find the dat structure that + * corresponds to it if create is non-zero and the rtdata + * structure does not exist, create it return NULL if not + * found + */ + + int found = 0; + int fd = ev->ev_fd; + struct rtdata *ret = NULL; + + if (op->highestfd < fd && create) + if (grow_fdset(op, fd) == -1) + return (NULL); + + TAILQ_FOREACH(ret, op->fdtodat[fd], next) { + if (ret->ev == ev) { + found = 1; + break; + } + } + + if (!found) { + if (!create) + return (NULL); + + ret = calloc(1, sizeof(struct rtdata)); + if (ret == NULL) + return (NULL); + ret->ev = ev; + ret->poll_position = -1; + TAILQ_INSERT_TAIL(op->fdtodat[fd], ret, next); + } + + return (ret); +} + +static void +dat_del(struct rtsigop *op, struct rtdata *dat) +{ + /* + * delete our private notes about a given event struct + * called from rtsig_del() only + */ + int fd; + if (dat == NULL) + return; + fd = dat->ev->ev_fd; + + TAILQ_REMOVE(op->fdtodat[fd], dat, next); + memset(dat, 0, sizeof(*dat)); + free(dat); +} + + +static void +set_sigaction(int sig) +{ + /* + * set the standard handler for any libevent-managed signal, + * including the rtsig used for O_ASYNC notifications + */ + struct sigaction act; + + act.sa_flags = SA_RESTART | SA_SIGINFO; + sigfillset(&(act.sa_mask)); + act.sa_sigaction = &signal_handler; + sigaction(sig, &act, NULL); +} + +static int +find_rt_signal() +{ + /* find an unused rtsignal */ + struct sigaction act; + int sig = SIGRTMIN; + + while (sig <= SIGRTMAX) { + if (sigaction(sig, NULL, &act) != 0) { + if (errno == EINTR) + continue; + } else { + if (act.sa_flags & SA_SIGINFO) { + if (act.sa_sigaction == NULL) + return (sig); + } else { + if (act.sa_handler == SIG_DFL) + return (sig); + } + } + sig++; + } + return (0); +} + +/* + * the next three functions manage our pollset and the memory management for + * fd -> rtdata -> event -> poll_position maps + */ + +static int +poll_add(struct rtsigop *op, struct event *ev, struct rtdata *dat) +{ + struct pollfd *pfd; + int newmax = op->max << 1; + int pp; + + if (op->poll == NULL) + return (0); + + if (dat == NULL) + dat = ev2dat(op, ev, 0); + + if (dat == NULL) + return (0); + + pp = dat->poll_position; + + if (pp != -1) { + pfd = &op->poll[pp]; + if (ev->ev_events & EV_READ) + pfd->events |= POLLIN; + + if (ev->ev_events & EV_WRITE) + pfd->events |= POLLOUT; + + return (0); + } + + if (op->cur == op->max) { + void *p = realloc(op->poll, sizeof(*op->poll) * newmax); + if (p == NULL) { + errno = ENOMEM; + return (-1); + } + op->poll = p; + + p = realloc(op->ptodat, sizeof(*op->ptodat) * newmax); + if (p == NULL) { + /* shrink the pollset back down */ + op->poll = realloc(op->poll, + sizeof(*op->poll) * op->max); + errno = ENOMEM; + return (-1); + } + op->ptodat = p; + op->max = newmax; + } + + pfd = &op->poll[op->cur]; + pfd->fd = ev->ev_fd; + pfd->revents = 0; + pfd->events = 0; + + if (ev->ev_events & EV_READ) + pfd->events |= POLLIN; + + if (ev->ev_events & EV_WRITE) + pfd->events |= POLLOUT; + + op->ptodat[op->cur] = dat; + dat->poll_position = op->cur; + op->cur++; + + return (0); +} + +static void +poll_free(struct rtsigop *op, int n) +{ + if (op->poll == NULL) + return; + + op->cur--; + + if (n < op->cur) { + memcpy(&op->poll[n], &op->poll[op->cur], sizeof(*op->poll)); + op->ptodat[n] = op->ptodat[op->cur]; + op->ptodat[n]->poll_position = n; + } + + + /* less then half the max in use causes us to shrink */ + if (op->max > INIT_MAX && op->cur < op->max >> 1) { + op->max >>= 1; + op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); + op->ptodat = realloc(op->ptodat, sizeof(*op->ptodat) * op->max); + } +} + +static void +poll_remove(struct rtsigop *op, struct event *ev, struct rtdata *dat) +{ + int pp; + if (dat == NULL) + dat = ev2dat(op, ev, 0); + + if (dat == NULL) return; + + pp = dat->poll_position; + if (pp != -1) { + poll_free(op, pp); + dat->poll_position = -1; + } +} + +static void +activate(struct event *ev, int flags) +{ + /* activate an event, possibly removing one-shot events */ + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, flags, 1); +} + +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + event_warn("fcntl(%d, F_SETFD)", x); \ +} while (0) + +static void * +rtsig_init(struct event_base *base) +{ + struct rtsigop *op; + int sockets[2]; + int optarg; + struct rtdata *dat; + int flags; + + if (getenv("EVENT_NORTSIG")) + goto err; + + op = calloc(1, sizeof(*op)); + if (op == NULL) + goto err; + + op->max = INIT_MAX; + op->poll = malloc(sizeof(*op->poll) * op->max); + if (op->poll == NULL) + goto err_free_op; + + op->signo = find_rt_signal(); + if (op->signo == 0) + goto err_free_poll; + + op->nonsock = 0; + + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sockets) != 0) + goto err_free_poll; + + FD_CLOSEONEXEC(sockets[0]); + FD_CLOSEONEXEC(sockets[1]); + + signal_send_fd[op->signo - 1] = sockets[0]; + trouble[op->signo - 1] = 0; + op->signal_send_fd = sockets[0]; + op->signal_recv_fd = sockets[1]; + flags = fcntl(op->signal_recv_fd, F_GETFL); + fcntl(op->signal_recv_fd, F_SETFL, flags | O_NONBLOCK); + + optarg = MAXBUFFERSIZE; + setsockopt(signal_send_fd[op->signo - 1], + SOL_SOCKET, SO_SNDBUF, + &optarg, sizeof(optarg)); + + optarg = MAXBUFFERSIZE; + setsockopt(op->signal_recv_fd, + SOL_SOCKET, SO_RCVBUF, + &optarg, sizeof(optarg)); + + op->highestfd = -1; + op->fdtodat = NULL; + if (grow_fdset(op, 1) == -1) + goto err_close_pair; + + op->ptodat = malloc(sizeof(*op->ptodat) * op->max); + if (op->ptodat == NULL) + goto err_close_pair; + + sigemptyset(&op->sigs); + sigaddset(&op->sigs, SIGIO); + sigaddset(&op->sigs, op->signo); + sigprocmask(SIG_BLOCK, &op->sigs, NULL); + set_sigaction(SIGIO); + set_sigaction(op->signo); + + event_set(&(op->sigfdev), op->signal_recv_fd, EV_READ|EV_PERSIST, + donothing, NULL); + op->sigfdev.ev_flags |= EVLIST_DONTDEL; + dat = ev2dat(op, &(op->sigfdev), 1); + poll_add(op, &(op->sigfdev), dat); + + return (op); + + err_close_pair: + close(op->signal_recv_fd); + close(signal_send_fd[op->signo - 1]); + + err_free_poll: + free(op->poll); + + err_free_op: + free(op); + err: + return (NULL); +} + +static int +rtsig_add(void *arg, struct event *ev) +{ + struct rtsigop *op = (struct rtsigop *) arg; + int flags, i; + struct stat statbuf; + struct rtdata *dat; + + if (ev->ev_events & EV_SIGNAL) { + int signo = EVENT_SIGNAL(ev); + + sigaddset(&op->sigs, EVENT_SIGNAL(ev)); + if (sigprocmask(SIG_BLOCK, &op->sigs, NULL) == -1) + return (-1); + + set_sigaction(signo); + + signal_send_fd[signo - 1] = op->signal_send_fd; + trouble[signo - 1] = 0; + + return (0); + } + + if (!(ev->ev_events & (EV_READ|EV_WRITE))) + return (0); + + if (-1 == fstat(ev->ev_fd, &statbuf)) + return (-1); + + if (!S_ISSOCK(statbuf.st_mode)) + ev->ev_flags |= EVLIST_NONSOCK; + + flags = fcntl(ev->ev_fd, F_GETFL); + if (flags == -1) + return (-1); + + if (!(flags & O_ASYNC)) { + if (fcntl(ev->ev_fd, F_SETSIG, op->signo) == -1 || + fcntl(ev->ev_fd, F_SETOWN, (int) gettid()) == -1) + return (-1); + + /* + * the overhead of always handling writeable edges + * isn't going to be that bad... + */ + if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC|O_RDWR)) + return (-1); + } + +#ifdef O_ONESIGFD + /* + * F_SETAUXFL and O_ONESIGFD are defined in a non-standard + * linux kernel patch to coalesce events for fds + */ + fcntl(ev->ev_fd, F_SETAUXFL, O_ONESIGFD); +#endif + + dat = ev2dat(op, ev, 1); + if (dat == NULL) + return (-1); + + op->total++; + if (ev->ev_flags & EVLIST_NONSOCK) + op->nonsock++; + + if (poll_add(op, ev, dat) == -1) { + /* must check the level of new fd's */ + i = errno; + fcntl(ev->ev_fd, F_SETFL, flags); + errno = i; + return (-1); + } + + return (0); +} + +static int +rtsig_del(void *arg, struct event *ev) +{ + struct rtdata *dat; + struct rtsigop *op = (struct rtsigop *) arg; + + if (ev->ev_events & EV_SIGNAL) { + sigset_t sigs; + + sigdelset(&op->sigs, EVENT_SIGNAL(ev)); + + sigemptyset(&sigs); + sigaddset(&sigs, EVENT_SIGNAL(ev)); + return (sigprocmask(SIG_UNBLOCK, &sigs, NULL)); + } + + if (!(ev->ev_events & (EV_READ|EV_WRITE))) + return (0); + + dat = ev2dat(op, ev, 0); + poll_remove(op, ev, dat); + dat_del(op, dat); + op->total--; + if (ev->ev_flags & EVLIST_NONSOCK) + op->nonsock--; + + return (0); +} + +/* + * the following do_X functions implement the different stages of a single + * eventloop pass: poll(), recv(sigsock), sigtimedwait() + * + * do_siginfo_dispatch() is a common factor to both do_sigwait() and + * do_signals_from_socket(). + */ + +static inline int +do_poll(struct rtsigop *op, struct timespec *ts, struct timespec **ts_p) +{ + int res = 0; + int i = 0; + + if (op->cur > 1) { + /* non-empty poll set (modulo the signalfd) */ + if (op->nonsock) { + int timeout = -1; + + if (*ts_p != NULL) + timeout = (*ts_p)->tv_nsec / 1000000 + + (*ts_p)->tv_sec * 1000; + + sigprocmask(SIG_UNBLOCK, &(op->sigs), NULL); + + res = poll(op->poll, op->cur, timeout); + + sigprocmask(SIG_BLOCK, &(op->sigs), NULL); + + ts->tv_sec = 0; + ts->tv_nsec = 0; + if (*ts_p) + *ts_p = ts; + } else { + res = poll(op->poll, op->cur, 0); + } + + if (res < 0) { + return (errno == EINTR ? 0 : -1); + } else if (res) { + ts->tv_sec = 0; + ts->tv_nsec = 0; + if (*ts_p) + *ts_p = ts; + } + + i = 0; + while (i < op->cur) { + struct rtdata *dat = op->ptodat[i]; + struct event *ev = dat->ev; + + if (op->poll[i].revents) { + int flags = 0; + + if (op->poll[i].revents & (POLLIN | POLLERR)) + flags |= EV_READ; + + if (op->poll[i].revents & POLLOUT) + flags |= EV_WRITE; + + if (!(ev->ev_events & EV_PERSIST)) { + poll_remove(op, ev, op->ptodat[i]); + event_del(ev); + } else { + i++; + } + + event_active(ev, flags, 1); + } else { + if (ev->ev_flags & (EVLIST_NONSOCK|EVLIST_DONTDEL)) { + i++; + } else { + poll_remove(op, ev, op->ptodat[i]); + } + } + } + } + return (res); +} + +static inline int +do_siginfo_dispatch(struct event_base *base, struct rtsigop *op, + siginfo_t *info) +{ + int signum; + struct rtdata *dat, *next_dat; + struct event *ev, *next_ev; + + if (info == NULL) + return (-1); + + signum = info->si_signo; + if (signum == op->signo) { + int flags, sigok = 0; + flags = 0; + + if (info->si_band & (POLLIN|POLLERR)) + flags |= EV_READ; + if (info->si_band & POLLOUT) + flags |= EV_WRITE; + + if (!flags) + return (0); + + if (info->si_fd > op->highestfd) + return (-1); + + dat = TAILQ_FIRST(op->fdtodat[info->si_fd]); + while (dat != TAILQ_END(op->fdtodat[info->si_fd])) { + next_dat = TAILQ_NEXT(dat, next); + if (flags & dat->ev->ev_events) { + ev = dat->ev; + poll_add(op, ev, dat); + activate(ev, flags & ev->ev_events); + sigok = 1; + } + dat = next_dat; + } + } else if (signum == SIGIO) { + TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { + if (ev->ev_events & (EV_READ|EV_WRITE)) + poll_add(op, ev, NULL); + } + return (1); /* 1 means the caller should poll() again */ + + } else if (sigismember(&op->sigs, signum)) { + /* managed signals are queued */ + ev = TAILQ_FIRST(&base->sig.signalqueue); + while (ev != TAILQ_END(&base->sig.signalqueue)) { + next_ev = TAILQ_NEXT(ev, ev_signal_next); + if (EVENT_SIGNAL(ev) == signum) + activate(ev, EV_SIGNAL); + ev = next_ev; + } + } else { + /* dispatch unmanaged signals immediately */ + struct sigaction sa; + if (sigaction(signum, NULL, &sa) == 0) { + if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction) { + (*sa.sa_sigaction)(signum, info, NULL); + } else if (sa.sa_handler) { + if ((int)sa.sa_handler != 1) + (*sa.sa_handler)(signum); + } else { + if (signum != SIGCHLD) { + /* non-blocked SIG_DFL */ + kill(gettid(), signum); + } + } + } + } + + return (0); +} + +/* + * return 1 if we should poll again + * return 0 if we are all set + * return -1 on error + */ +static inline int +do_sigwait(struct event_base *base, struct rtsigop *op, + struct timespec *ts, struct timespec **ts_p, sigset_t *sigs) +{ + for (;;) { + siginfo_t info; + int signum; + + signum = sigtimedwait(sigs, &info, *ts_p); + + ts->tv_sec = 0; + ts->tv_nsec = 0; + *ts_p = ts; + + if (signum == -1) { + if (errno == EAGAIN || errno == EINTR) + return (0); + return (-1); + } else if (1 == do_siginfo_dispatch(base, op, &info)) { + return (1); + } + } + + /* NOTREACHED */ +} + +static inline int +do_signals_from_socket(struct event_base *base, struct rtsigop *op, + struct timespec *ts, struct timespec **ts_p) +{ + int fd = op->signal_recv_fd; + siginfo_t info; + int res; + + for (;;) { + res = recv(fd, &info, sizeof(info), MSG_NOSIGNAL); + if (res == -1) { + if (errno == EAGAIN) + return (0); + if (errno == EINTR) + continue; + return (-1); + } else { + ts->tv_sec = 0; + ts->tv_nsec = 0; + *ts_p = ts; + if (1 == do_siginfo_dispatch(base, op, &info)) + return (1); + } + } + /* NOTREACHED */ +} + +static int +rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + struct rtsigop *op = (struct rtsigop *) arg; + struct timespec ts, *ts_p = NULL; + int res; + sigset_t sigs; + + if (tv != NULL) { + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; + ts_p = &ts; + } + + poll_for_level: + /* ts and ts_p can be modified in do_XXX() */ + res = do_poll(op, &ts, &ts_p); + + res = do_signals_from_socket(base, op, &ts, &ts_p); + if (res == 1) + goto poll_for_level; + else if (res == -1) + return (-1); + + /* + * the mask = managed_signals | unblocked-signals + * MM - if this is not blocking do we need to cast the net this wide? + */ + sigemptyset(&sigs); + sigprocmask(SIG_BLOCK, &sigs, &sigs); + signotset(&sigs); + sigorset(&sigs, &sigs, &op->sigs); + + res = do_sigwait(base, op, &ts, &ts_p, &sigs); + + if (res == 1) + goto poll_for_level; + else if (res == -1) + return (-1); + + return (0); +} + + +static void +rtsig_dealloc(struct event_base *base, void *arg) +{ + struct rtsigop *op = arg; + + evsignal_dealloc(base); + if (op->poll) + free(op->poll); + if (op->ptodat) + free(op->ptodat); + + memset(op, 0, sizeof(struct rtsigop)); + free(op); +} From list8a.forest at tibit.com Mon May 12 17:56:06 2008 From: list8a.forest at tibit.com (Forest) Date: Mon May 12 17:56:24 2008 Subject: [Libevent-users] how do read timeouts behave with EV_PERSIST? Message-ID: <13873.75.55.199.5.1210629366.squirrel@webmail.sonic.net> I have an event that gets created with EV_READ | EV_PERSIST, and I'm considering different ways to implement read timeouts. Passing a timeout value to event_add() is the obvious approach, but the docs don't make it clear what behavior to expect... "The event in the ev argument must be already initialized by event_set() and may not be used in calls to event_set() until it has timed out or been removed with event_del(). If the event in the ev argument already has a scheduled timeout, the old timeout will be replaced by the new one." If my callback receives EV_TIMEOUT in its second argument, does that mean my read event has been canceled despite my use of EV_PERSIST? If so, does that mean libevent's timeout code has already called event_del() behind the scenes? (In other words, do I still have to call event_del()?) If an EV_PERSIST event callback receives EV_TIMEOUT, can it reinstate its persistent read event just by calling event_add()? Can someone update the docs to clarify how EV_PERSIST and EV_TIMEOUT interact? In case it matters, I'm using libevent 1.3b on linux. Cheers, Forest From phil at ultimate.com Mon May 12 18:27:09 2008 From: phil at ultimate.com (Phil Budne) Date: Mon May 12 18:27:11 2008 Subject: [Libevent-users] libevent search order control Message-ID: <200805122227.m4CMR9AR014268@ultimate.com> Attached is a diff (independent of my rtsig patch) that allows you to specify a search order for libevent methods by putting a comma seperated list of method names in environment variable "EVENT_METHODS", which I find more graceful than dealing with n different EVENT_NOxxxx variables. --- event.c.orig 2008-02-25 02:34:37.000000000 -0500 +++ event.c 2008-05-12 18:07:57.000000000 -0400 @@ -171,6 +171,7 @@ { int i; struct event_base *base; + char *event_methods; if ((base = calloc(1, sizeof(struct event_base))) == NULL) event_err(1, "%s: calloc", __func__); @@ -188,10 +189,39 @@ base->sig.ev_signal_pair[1] = -1; base->evbase = NULL; - for (i = 0; eventops[i] && !base->evbase; i++) { - base->evsel = eventops[i]; + event_methods = getenv("EVENT_METHODS"); + if (event_methods) { + char *mtemp = strdup(event_methods); + char *mp, *np; + + for (mp = mtemp; mp && !base->evbase; mp = np) { + int found = 0; + const struct eventop **opp; + + np = strchr(mp, ','); + if (np) + *np++ = '\0'; + for (opp = eventops; *opp; opp++) { + const struct eventop *op = *opp; + if (op->name && strcmp(mp, op->name) == 0) { + base->evsel = op; + base->evbase = base->evsel->init(base); + found = 1; + break; + } + } +#if 0 /* if EVENT_SHOW_METHOD env var set? */ + if (!found) + event_msgx("libevent %s not found", mp); +#endif - base->evbase = base->evsel->init(base); + } + } + else { + for (i = 0; eventops[i] && !base->evbase; i++) { + base->evsel = eventops[i]; + base->evbase = base->evsel->init(base); + } } if (base->evbase == NULL) From list8a.forest at tibit.com Mon May 12 20:50:39 2008 From: list8a.forest at tibit.com (Forest) Date: Mon May 12 20:51:08 2008 Subject: [Libevent-users] timeouts are not working as documented Message-ID: <17550.208.106.109.136.1210639839.squirrel@webmail.sonic.net> I'm having trouble getting timeouts to work. According to the docs, "libevent can assign timeout events to file descriptors that are triggered whenever a certain amount of time has passed with no activity on a file descriptor." When I create a socket read event and pass a {12, 0} timeout to event_add(), my callback gets called with EV_TIMEOUT 12 seconds after startup, even when there have been read events just a second or two earlier. Contrary to the docs, libevent is triggering the timeout regardless of activity on the socket. I'm calling event_set() with EV_PERSIST, and building against libevent 1.3b on linux. Are timeouts known to be broken with either of these? Furthermore, the docs describe different behavior for timers and timeouts, yet a look at event.h shows no difference between them: #define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) #define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) #define evtimer_add(ev, tv) event_add(ev, tv) #define timeout_add(ev, tv) event_add(ev, tv) Can someone explain that? From provos at citi.umich.edu Mon May 12 22:00:03 2008 From: provos at citi.umich.edu (Niels Provos) Date: Mon May 12 22:00:06 2008 Subject: [Libevent-users] timeouts are not working as documented In-Reply-To: <17550.208.106.109.136.1210639839.squirrel@webmail.sonic.net> References: <17550.208.106.109.136.1210639839.squirrel@webmail.sonic.net> Message-ID: <850f7cbe0805121900l409e1d93h934908f0057c1761@mail.gmail.com> On Mon, May 12, 2008 at 5:50 PM, Forest wrote: > I'm calling event_set() with EV_PERSIST, and building against libevent > 1.3b on linux. Are timeouts known to be broken with either of these? The behavior of timeouts with EV_PERSIST is not well documented and somewhat counter intuitive; see http://sourceforge.net/tracker/index.php?func=detail&aid=1831173&group_id=50884&atid=461325 You might also want to use a more recent version of libevent as 1.3b is over a year old. Niels. From provos at citi.umich.edu Mon May 12 22:42:44 2008 From: provos at citi.umich.edu (Niels Provos) Date: Mon May 12 22:43:04 2008 Subject: [Libevent-users] http input buffer deallocation problem In-Reply-To: <48281D0E.1090209@elka.pw.edu.pl> References: <48281D0E.1090209@elka.pw.edu.pl> Message-ID: <850f7cbe0805121942g469d08aex3fa9ad9ba35ad36f@mail.gmail.com> On Mon, May 12, 2008 at 3:33 AM, Cezary Rzewuski wrote: > I suspect there may be two reasons, but I don't know if this how libevent > works: > 1) there is any priority in events processed in libevent, and buffer > deallocation remains in the tail of events queue > 2) may be there is any HTTP header that causes libevent to postpone closing > connection (which crawler uses but wget not). We would have to see your code to figure out what's going on. For example, HTTP has persistent connections, i.e. connections that stay open after a request has been handled. It would also be good to know which version of libevent you are using. Niels. From lyesjob at gmail.com Tue May 13 06:03:26 2008 From: lyesjob at gmail.com (Lyes Amazouz) Date: Tue May 13 06:03:50 2008 Subject: [Libevent-users] libevent 1.4.4 when? Message-ID: <60d886530805130303w1d0f230fgcc706d970ff5f15c@mail.gmail.com> Hello everybody! I want to know when the version 1.4.4 of the libevent will be released, I asked a question about a cygwin compilation problem last Thursday, and Nick said that this new version may resolve it. He also said that this version will be released after 48 at most, but until today, nothing!?? please, if this release will be later than planned, warn me that i think about a solution to my problem thank you ! -- =========== | Lyes Amazouz | USTHB, Algiers =========== -------------- next part -------------- An HTML attachment was scrubbed... URL: http://monkeymail.org/archives/libevent-users/attachments/20080513/610dce00/attachment.htm From nickm at freehaven.net Tue May 13 09:19:04 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Tue May 13 09:19:42 2008 Subject: [Libevent-users] libevent 1.4.4 when? In-Reply-To: <60d886530805130303w1d0f230fgcc706d970ff5f15c@mail.gmail.com> References: <60d886530805130303w1d0f230fgcc706d970ff5f15c@mail.gmail.com> Message-ID: <20080513131904.GB14680@moria.seul.org> On Tue, May 13, 2008 at 11:03:26AM +0100, Lyes Amazouz wrote: > Hello everybody! > > I want to know when the version 1.4.4 of the libevent will be released, I > asked a question about a cygwin compilation problem last Thursday, and Nick > said that this new version may resolve it. He also said that this version > will be released after 48 at most, but until today, nothing!?? Yes, sorry there. We ran into some Win32 issues that really needed fixing. I don't have any release-blocking issues now. Niels, are we blocking on anything else? Do you have time to put a release out today? > please, if this release will be later than planned, warn me that i think > about a solution to my problem > > thank you ! > > > -- > =========== > | Lyes Amazouz > | USTHB, Algiers > =========== > _______________________________________________ > Libevent-users mailing list > Libevent-users@monkey.org > http://monkeymail.org/mailman/listinfo/libevent-users From lyesloui at gmail.com Tue May 13 09:34:58 2008 From: lyesloui at gmail.com (Lyes Amazouz) Date: Tue May 13 09:35:05 2008 Subject: [Libevent-users] libevent 1.4.4 when? In-Reply-To: <20080513131904.GB14680@moria.seul.org> References: <60d886530805130303w1d0f230fgcc706d970ff5f15c@mail.gmail.com> <20080513131904.GB14680@moria.seul.org> Message-ID: <6d880c430805130634r2833bef0m6d273c05e4dbc9b0@mail.gmail.com> OK, thank you, I am waiting for it. I hope that this version will fix my problem with cygwin definitively 2008/5/13 Nick Mathewson : > On Tue, May 13, 2008 at 11:03:26AM +0100, Lyes Amazouz wrote: > > Hello everybody! > > > > I want to know when the version 1.4.4 of the libevent will be released, I > > asked a question about a cygwin compilation problem last Thursday, and Nick > > said that this new version may resolve it. He also said that this version > > will be released after 48 at most, but until today, nothing!?? > > Yes, sorry there. We ran into some Win32 issues that really needed > fixing. I don't have any release-blocking issues now. Niels, are we > blocking on anything else? Do you have time to put a release out > today? > > > please, if this release will be later than planned, warn me that i think > > about a solution to my problem > > > > thank you ! > > > > > > -- > > =========== > > | Lyes Amazouz > > | USTHB, Algiers > > =========== > > > _______________________________________________ > > Libevent-users mailing list > > Libevent-users@monkey.org > > http://monkeymail.org/mailman/listinfo/libevent-users > > _______________________________________________ > Libevent-users mailing list > Libevent-users@monkey.org > http://monkeymail.org/mailman/listinfo/libevent-users > -- =============================== Lyes Amazouz USTHB, Algiers =============================== From provos at citi.umich.edu Tue May 13 10:44:04 2008 From: provos at citi.umich.edu (Niels Provos) Date: Tue May 13 10:44:15 2008 Subject: [Libevent-users] libevent 1.4.4 when? In-Reply-To: <20080513131904.GB14680@moria.seul.org> References: <60d886530805130303w1d0f230fgcc706d970ff5f15c@mail.gmail.com> <20080513131904.GB14680@moria.seul.org> Message-ID: <850f7cbe0805130744r1963fcd2mbd68c1d88111ec6d@mail.gmail.com> On Tue, May 13, 2008 at 6:19 AM, Nick Mathewson wrote: > Yes, sorry there. We ran into some Win32 issues that really needed > fixing. I don't have any release-blocking issues now. Niels, are we > blocking on anything else? Do you have time to put a release out > today? I should be able to make a release tonight. Niels. From provos at citi.umich.edu Wed May 14 00:30:50 2008 From: provos at citi.umich.edu (Niels Provos) Date: Wed May 14 00:31:03 2008 Subject: [Libevent-users] ANN: Libevent 1.4.4-stable released Message-ID: <850f7cbe0805132130n580f3e26o5b12044af27d74b1@mail.gmail.com> Hi, I am happy to announce the release of libevent 1.4.4-stable. You can download the source here: http://monkey.org/~provos/libevent-1.4.4-stable.tar.gz There have been a few bug fixes since 1.4.3-stable. Here's a brief summary: - Epoll fixes - Correctly handle timeouts larger than 35 minutes for older Linux kernels - Tagging fixes: - Fixes a potential stack corruption on 64-bit architectures - Bufferevent changes: - Fixes a corner cases for read watermarks - Expose the watermark functionality in bufferevent - HTTP changes: - Fix a bug where it was not possible to accept on multiple sockets - Expose the evhttp_accept_socket() functionality which allows the HTTP server to listen on an already created socket - Portability fixes: - Fix functionality and compile problems on Windows and IRIX - Provide a timercmp function that works on all platforms See the changelog for full details: http://levent.svn.sourceforge.net/viewvc/levent/branches/patches-1.4/libevent/ChangeLog?revision=802&view=markup We would like to thank the people who have reported bugs including Matt Domsch, Forest Wilkinson, Jon and several anonymous reporters. To report a bug, make a feature request, or submit code, you can use our sourceforge interface here: https://sourceforge.net/projects/levent Thanks again, Niels. From nickm at freehaven.net Thu May 15 16:09:44 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 15 16:16:24 2008 Subject: [Libevent-users] patch for "realtime signal" events in libevent-1.4.3-stable In-Reply-To: <200805122139.m4CLdp3s013588@ultimate.com> References: <200805122139.m4CLdp3s013588@ultimate.com> Message-ID: <20080515200944.GU14680@moria.seul.org> On Mon, May 12, 2008 at 05:39:51PM -0400, Phil Budne wrote: > I needed to do apples-to-apples comparison between rtsignals and epoll > for a client, so I fixed rtsig.c from 1.3e (see an earlier post) to > compile, then fixed it to work, and ported that to 1.4.3-stable. > > NOTE WELL! Used only for benchmarking: the rtsig_dealloc routine may > not free everything it needs to! Out of curiousity, how did the benchmarks turn out? Any reason to try to get rtsig working again in the mainline distribution? -- Nick From phil at ultimate.com Thu May 15 16:58:53 2008 From: phil at ultimate.com (Phil Budne) Date: Thu May 15 16:58:57 2008 Subject: [Libevent-users] patch for "realtime signal" events in libevent-1.4.3-stable In-Reply-To: <20080515200944.GU14680@moria.seul.org> Message-ID: <200805152058.m4FKwrHo086806@ultimate.com> on Thu, 15 May 2008 Nick Mathewson wrote: > Out of curiousity, how did the benchmarks turn out? Any reason to try > to get rtsig working again in the mainline distribution? > > Nick On Fedora 8 (2.6.24.5-85.fc8), the results were consistantly a little worse than epoll. I didn't check whether the benchmark ever causes signal queue overflow, which is the nightmarish part of using RT signals. You can view plots at: http://www.ultimate.com/phil/temp/libevent/ From C.Rzewuski at elka.pw.edu.pl Fri May 16 12:26:54 2008 From: C.Rzewuski at elka.pw.edu.pl (Cezary Rzewuski) Date: Fri May 16 12:41:56 2008 Subject: [Libevent-users] http input buffer deallocation problem In-Reply-To: <850f7cbe0805121942g469d08aex3fa9ad9ba35ad36f@mail.gmail.com> References: <48281D0E.1090209@elka.pw.edu.pl> <850f7cbe0805121942g469d08aex3fa9ad9ba35ad36f@mail.gmail.com> Message-ID: <482DB5CE.5080808@elka.pw.edu.pl> Niels Provos wrote: > On Mon, May 12, 2008 at 3:33 AM, Cezary Rzewuski > wrote: > >> I suspect there may be two reasons, but I don't know if this how libevent >> works: >> 1) there is any priority in events processed in libevent, and buffer >> deallocation remains in the tail of events queue >> 2) may be there is any HTTP header that causes libevent to postpone closing >> connection (which crawler uses but wget not). >> > > We would have to see your code to figure out what's going on. For > example, HTTP has persistent connections, i.e. connections that stay > open after a request has been handled. It would also be good to know > which version of libevent you are using. > > Niels. > > Actually my code is very similar to spybye. However, I don't need sites to be cached or to wait for antivirus scanning, so it's kind of simplified spybye. libevent functions are used in exactly the same way as in spybye. I use libevent1.4.3-stable. After more extensive debugging I suspect, that, in case of heavy workload, libevent just doesn't complete all the requests that are scheduled. I can see that my proxy receives a request from the crawler, sends the request to a www server, then receives response from the server. Then evhttp_send_reply function is called to return the reply to the crawler. But then, strangely, function evhttp_write is never called with argument of this particular connection. Consequently, evhttp_send_done function, which is responsible for freeing connection and request structures, is also never called. This causes that evhttp_connection and evhttp_request structures are never freed. The situation I've described happens really randomly and only in case of crawling (which means many requests). When I use proxy with browser (and human is the one that interacts:)), everything looks fine. Cezary Rzewuski From nickm at freehaven.net Fri May 16 15:44:48 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Fri May 16 15:45:15 2008 Subject: [Libevent-users] Success compile libevent 1.4.3 with VC6 In-Reply-To: <20080423233732.GB23700@moria.seul.org> References: <480F3ACC.6010102@mail.ru> <20080423233732.GB23700@moria.seul.org> Message-ID: <20080516194447.GF4518@moria.seul.org> On Wed, Apr 23, 2008 at 07:37:32PM -0400, Nick Mathewson wrote: > On Wed, Apr 23, 2008 at 05:34:04PM +0400, Eugene 'HMage' Bujak wrote: [...] > > * Winsock library needs to be initialized and freed explicitly on win32. > > This is true, but it's not libevent's job to do it. Actually, I think I was wrong here. As James Mansion pointed out, it's okay to call WSAStartup more than once. And given that I just spent 30 minutes trying to track down a bug that was really just forgetting to call WSAStartup() from inside a test in a configure script, I've become pretty sure that it is a useful thing to do. yrs, -- Nick From matti.savolainen at dynamoid.com Tue May 20 01:26:23 2008 From: matti.savolainen at dynamoid.com (Matti Savolainen) Date: Tue May 20 01:24:47 2008 Subject: [Libevent-users] EVHTTP memory issue. Message-ID: <483260FF.3070401@dynamoid.com> Hi, I have been using evhttp for some time now for a project involving large POST datas. But now in production use I have noticed it leaking memory so I valgrinder it a bit. I am not sure if it is me using it wrong or if there is a bug somewhere there. Basicly it uses more and more memory as it handles requests. So here is the relevan valgrind outputs: ==14643== 4,096 bytes in 4 blocks are indirectly lost in loss record 7 of 13 ==14643== at 0x4A1B95B: realloc (vg_replace_malloc.c:306) ==14643== by 0x4C56E84: evbuffer_expand (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C56F21: evbuffer_add (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C59B0E: evhttp_make_header (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5A824: evhttp_request_dispatch (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5ABB0: evhttp_connectioncb (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54E5D: event_process_active (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5518F: event_base_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54FF6: event_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54EA6: event_dispatch (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x405753: main (main.cpp:8) ==14643== 6,144 bytes in 18 blocks are indirectly lost in loss record 8 of 13 ==14643== at 0x4A1B858: malloc (vg_replace_malloc.c:149) ==14643== by 0x4A1B8D2: realloc (vg_replace_malloc.c:306) ==14643== by 0x4C56E84: evbuffer_expand (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5713F: evbuffer_read (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5B964: evhttp_read_header (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54E5D: event_process_active (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5518F: event_base_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54FF6: event_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54EA6: event_dispatch (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x405753: main (main.cpp:8) ==14643== 67,108,864 bytes in 2 blocks are still reachable in loss record 13 of 13 ==14643== at 0x4A1B95B: realloc (vg_replace_malloc.c:306) ==14643== by 0x4C56E84: evbuffer_expand (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5713F: evbuffer_read (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5A43D: evhttp_read (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54E5D: event_process_active (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C5518F: event_base_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54FF6: event_loop (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x4C54EA6: event_dispatch (in /usr/local/lib/libevent-1.4.so.2.0.0) ==14643== by 0x405753: main (main.cpp:8) The way I use evhttp is basicly: evhttp_start evhttp_set_gencb In the callback: Copy the data for later use from EVBUFFER_DATA(request->input_buffer) add headers to output_headers: Content-Length: 0, Connection: close, and a Location: evhttp_send_reply with HTTP_MOVEPERM evhttp_send_reply_end -- Matti Savolainen From nadir.belkhelfa at gmail.com Mon May 26 11:10:18 2008 From: nadir.belkhelfa at gmail.com (mohamed nadir belkhelfa) Date: Mon May 26 11:10:37 2008 Subject: [Libevent-users] can me compile libevent under cygwin ? Message-ID: Hello every body. I want to compile libevent under cygwin . and I dont know if is possible or not. can you help me please -------------- next part -------------- An HTML attachment was scrubbed... URL: http://monkeymail.org/archives/libevent-users/attachments/20080526/ad9af75f/attachment.htm From slamb at slamb.org Mon May 26 15:10:15 2008 From: slamb at slamb.org (Scott Lamb) Date: Mon May 26 15:10:39 2008 Subject: [Libevent-users] "make verify" failure in regress.c:test_methods() Message-ID: <483B0B17.6080103@slamb.org> "make verify" does not work for me under Linux (CentOS 5) with trunk HEAD (revision 836). It reaches the epoll section and says this: EPOLL test-eof: OKAY test-weof: OKAY test-time: OKAY regress: Testing supported methods: epoll poll select [err] event_base_new_with_config: no event mechanism available FAILED It looks like regress.c:test_methods() is trying to disable the first method and instantiate a config, which is failing because the test.sh wrapper has set environmental variables which cause evsel->init() to fail on all other methods. As for a fix...maybe the environmental variables should just be used to set up a default config to be used if none is specified, and possibly to be copied on event_config_new(). (If the latter, test_methods() would need to call event_config_is_avoided() before adding a method to its count, and this test would always be skipped on "make verify".) It seems odd for EVENT_NO* and event_config_avoid_method() to work by totally different mechanisms. This must have been broken since the test was added on May 8th. I'm trying to understand how that happened - is "make verify" not what the cool kids use to test libevent? or do the cool kids not use Linux? Best regards, Scott -- Scott Lamb From provos at citi.umich.edu Wed May 28 21:40:33 2008 From: provos at citi.umich.edu (Niels Provos) Date: Wed May 28 21:41:09 2008 Subject: [Libevent-users] "make verify" failure in regress.c:test_methods() In-Reply-To: <483B0B17.6080103@slamb.org> References: <483B0B17.6080103@slamb.org> Message-ID: <850f7cbe0805281840h3b80bf6dj4dc48395a212a955@mail.gmail.com> On Mon, May 26, 2008 at 12:10 PM, Scott Lamb wrote: > It looks like regress.c:test_methods() is trying to disable the first method > and instantiate a config, which is failing because the test.sh wrapper has > set environmental variables which cause evsel->init() to fail on all other > methods. Good find. I fixed trunk. Thank you, Niels. From valery+libevent at grid.net.ru Thu May 29 11:40:16 2008 From: valery+libevent at grid.net.ru (Valery Kholodkov) Date: Thu May 29 11:41:33 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour Message-ID: <.62.218.60.210.1212075616.squirrel@grid.net.ru> Greetings! Since discovering libevent for myself I've been wondering why where is still no support for Edge-Triggered behaviour, which from my point of view could be easily implemented. There were many talks already among Linux kernel developers as well as application developers about how and why to use it. I have also discovered that people already were trying to implement such functionality with greater or lesser degree of success, e.g. here: https://webmail.iro.umontreal.ca/pipermail/gambit-list/2005-August/000367.html So I tried to do it once again and a link to a patch is given below. But the problem with Edge-Triggered behaviour is that few people understand it. There is simply no clear understanding among application developers of how Edge-Triggered works, which produces Fear, Uncertainity and Doubt (FUD). Therefore I think I have to provide some guidelines about this. libevent is currently by default Level-Triggered (LT), this means that an event is generated every time kqueue/epoll/select/whatever is invoked and a descriptor has data available to read or IO space available to write to. With Edge-Triggered (ET) behaviour an event is generated every time the amount of data available to read overcomes threshold of 0 or the amount of IO space available to write to overcomes threshold of 0. This means that no new events will be generated unless the application will read out all available incoming data or fill all available outbound IO space. This means that whenever a descriptor available to read is reported and Edge-Triggered behaviour takes place the application have to read out all the data until EOF or error or EAGAIN will be returned by read/readv. In the similar way whenever a descriptor available to write is reported and Edge-Triggered behaviour takes place the application have to write all the data it has until an error or EAGAIN will be returned by write/writev/sendfile. Such a strategy is also recommended by select_tut(2) man page (see section SELECT LAW point 6) to prevent IO starvation. So there is nothing mystical behind it and similar strategy has been already existing in pre-ET era. This has a significant advantage, that whenever you read and you run out of destination buffer/IO space there is no need to unarm the descriptor by calling event_del, you just have to remember somewhere that the descriptor is still available to read. Then you return to it when the destination buffer/IO space emerges. In the similar way where is not need to rearm the descriptor whenever data emerges to be sent out. You just have to remember in your application that the descriptor was available to write and simply continue to write. With epoll/kqueue this saves you a number of system calls which is the source of additional performance. With kqueue Edge-Triggered behaviour could be simply enforced using EV_CLEAR flag according to this message: http://www.cs.helsinki.fi/linux/linux-kernel/2001-38/0547.html The patch itself is submitted into SF's patch tracking system: http://sourceforge.net/tracker/index.php?func=detail&aid=1968284&group_id=50884&atid=461324 This patch introduces EV_ET flag. Whenever you specify EV_ET in event_set call a specific module will try enforce Edge-Triggered behaviour. Whevever Edge-Triggered behaviour takes place ,the event argument of a callback will additionally contain EV_ET flag, and you should react accordingly. When methods are used, which do not support ET such as select or poll, no EV_ET flag will be ever set. The file test/test_et.c demonstrates the usage of EV_ET flag. I hope that maintainers will agree to integrate the patch in future versions of libevent. Good luck and additional performance to your applications! -- Best regards, Valery Kholodkov From nickm at freehaven.net Thu May 29 12:10:21 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 29 12:11:25 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <.62.218.60.210.1212075616.squirrel@grid.net.ru> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> Message-ID: <20080529161021.GJ30848@moria.seul.org> On Thu, May 29, 2008 at 05:40:16PM +0200, Valery Kholodkov wrote: > Greetings! > > Since discovering libevent for myself I've been wondering > why where is still no support for Edge-Triggered behaviour, which > from my point of view could be easily implemented. Basically, because nobody had written it yet. Thanks for writing it! :) [...] > The patch itself is submitted into SF's patch tracking system: > > http://sourceforge.net/tracker/index.php?func=detail&aid=1968284&group_id=50884&atid=461324 Thanks for reminding me; I've just added a few questions there. > This patch introduces EV_ET flag. Whenever you specify EV_ET in event_set > call a specific module will try enforce Edge-Triggered behaviour. Well, not exactly. The way the patch is written now, when EV_ET is set, *and* you're using the epoll backend or the kqueue backend, you'll get edge-triggered behavior. Otherwise, you get regular behavior. I'm not sure whether this is the right API or not; it might make more sense for event_add to give an error when you try to add an EV_ET event to a backend that doesn't support EV_ET. Alternatively, we could define the semantics of EV_ET so that instead of meaning "make this event edge triggered" it means "make this event edge triggered if possible." (This is one of the comments on the sourceforge patch; I'm hoping we can discuss this more there. Niels: what do you think?) [...] > I hope that maintainers will agree to integrate the patch in future > versions of libevent. I'd definitely like to merge functionality like this into Libevent 2.0. The code looks clear enough, and the functionality certainly seems valuable enough. -- Nick From valery+libevent at grid.net.ru Thu May 29 13:06:31 2008 From: valery+libevent at grid.net.ru (Valery Kholodkov) Date: Thu May 29 13:07:35 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <20080529161021.GJ30848@moria.seul.org> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> Message-ID: <.192.168.1.13.1212080791.squirrel@grid.net.ru> >> This patch introduces EV_ET flag. Whenever you specify EV_ET in >> event_set >> call a specific module will try enforce Edge-Triggered behaviour. > > Well, not exactly. The way the patch is written now, when EV_ET is > set, *and* you're using the epoll backend or the kqueue backend, > you'll get edge-triggered behavior. Otherwise, you get regular > behavior. I'm not sure whether this is the right API or not; it might > make more sense for event_add to give an error when you try to add an > EV_ET event to a backend that doesn't support EV_ET. Alternatively, > we could define the semantics of EV_ET so that instead of meaning > "make this event edge triggered" it means "make this event edge > triggered if possible." > > (This is one of the comments on the sourceforge patch; I'm hoping we > can discuss this more there. Niels: what do you think?) "make this event edge triggered if possible." is exactly what I've meant. There are two different points of view, which are better not to mix. >From application developer's point of view EV_ET means "make this event edge triggered if possible", since he/she/it should not be dependent on the availability of a particular backend (kqueue/select/poll). >From library developer's point of view EV_ET means "make this event edge triggered" whenever kqueue/epoll is used. -- Best regards, Valery Kholodkov From valery+libevent at grid.net.ru Thu May 29 14:02:18 2008 From: valery+libevent at grid.net.ru (Valery Kholodkov) Date: Thu May 29 14:03:24 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <20080529161021.GJ30848@moria.seul.org> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> Message-ID: <.192.168.1.13.1212084138.squirrel@grid.net.ru> For the convenience I'll answer to Nick's questions from SF's patch tracker in this list. > A few initial questions: > - How exactly does the test_et.c file test the edge-triggered behavior? > As near as I can tell, the test ought to pass whether EV_ET works or not. > What am I missing? I hardly find a direct and automatic way to do it... Try following patch for test_et.c --- test_et2.c 2008-05-29 21:53:15.000000000 +0200 +++ test_et.c 2008-05-29 21:50:42.000000000 +0200 @@ -27,28 +27,27 @@ #include int test_okay = 1; -int called = 0; +int edge_triggered = 0; static void read_cb(int fd, short event, void *arg) { - char buf[256]; + char buf; int len; - do{ - len = read(fd, buf, sizeof(buf)); + len = read(fd, &buf, sizeof(buf)); - printf("%s: %s %d%s\n", __func__, event & EV_ET ? "etread" : "read", - len, len ? "" : " - means EOF"); + printf("%s: %s %d%s\n", __func__, event & EV_ET ? "etread" : "read", + len, len ? "" : " - means EOF"); - if (!len) { - if (called > 0) - test_okay = 0; - event_del(arg); - } + if(event & EV_ET) + edge_triggered++; - called++; - }while(len != 0); + if (!len) { + if (edge_triggered > 0) + test_okay = 0; + event_del(arg); + } } #ifndef SHUT_WR You should get following now: $ ./test_et read_cb: etread 1 ^C *HANGING!!!* $ EVENT_NOKQUEUE=1 EVENT_NOEPOLL=1 ./test_et read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 1 read_cb: read 0 - means EOF Means with ET the handler is being invoked only once when amount of data available overcame threshold of 0. I must think a bit how to automate this. Please give me time. > - Is it really a good idea to have backends that do not support EV_ET > silently ignore it? > If writers are really hoping for edge-triggered behavior, won't they > be surprised when they > sometimes get it, and sometimes don't? Yes and no. Principally there could be a situation where application will change it's behaviour depending of the awareness of ET, e.g. set a particular event handler in event_set, providing two different optimized hardcoded handlers for each case. Then it would be better to go back to a solution from Adam Langley where ET capability is explicitly specified for each multiplexing method: https://webmail.iro.umontreal.ca/pipermail/gambit-list/2005-August/000367.html On the other hand it is sometimes very comfortable to simple check presence of EV_ET flag, whenever a difference between ET and non-ET implementation costs only few lines (Perl way). I think that both ways are worth them, so we could adsorb all of them. -- Best regards, Valery Kholodkov From nickm at freehaven.net Thu May 29 15:15:05 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Thu May 29 15:17:33 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <.192.168.1.13.1212084138.squirrel@grid.net.ru> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> <.192.168.1.13.1212084138.squirrel@grid.net.ru> Message-ID: <20080529191505.GK30848@moria.seul.org> On Thu, May 29, 2008 at 08:02:18PM +0200, Valery Kholodkov wrote: > > For the convenience I'll answer to Nick's questions from > SF's patch tracker in this list. > > > A few initial questions: > > - How exactly does the test_et.c file test the edge-triggered behavior? > > As near as I can tell, the test ought to pass whether EV_ET works or not. > > What am I missing? > > I hardly find a direct and automatic way to do it... > > Try following patch for test_et.c [...] > > You should get following now: > > $ ./test_et > read_cb: etread 1 > ^C *HANGING!!!* > $ EVENT_NOKQUEUE=1 EVENT_NOEPOLL=1 ./test_et > read_cb: read 1 > read_cb: read 1 Ah. In the edge-triggered case, the handler only gets called once, but in the level-triggered case, the handler is called so long as read() would still succeed. [...] > I must think a bit how to automate this. Please give me time. Maybe you could use the EVLOOP_NONBLOCK flag to event_loop(), and call it twice, and verify that in the edge-triggered case the event is only activated on the first call, but in the level-triggered case the event is activated on the second call too? yours, -- Nick From valery+libevent at grid.net.ru Thu May 29 15:21:15 2008 From: valery+libevent at grid.net.ru (Valery Kholodkov) Date: Thu May 29 15:22:19 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <20080529191505.GK30848@moria.seul.org> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> <.192.168.1.13.1212084138.squirrel@grid.net.ru> <20080529191505.GK30848@moria.seul.org> Message-ID: <.192.168.1.13.1212088875.squirrel@grid.net.ru> >> I must think a bit how to automate this. Please give me time. > > Maybe you could use the EVLOOP_NONBLOCK flag to event_loop(), and call > it twice, and verify that in the edge-triggered case the event is only > activated on the first call, but in the level-triggered case the event > is activated on the second call too? This looks exactly like a solution to a problem. Thanks, I'll fix. -- Best regards, Valery Kholodkov From valery+libevent at grid.net.ru Fri May 30 04:18:24 2008 From: valery+libevent at grid.net.ru (Valery Kholodkov) Date: Fri May 30 04:20:05 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <.192.168.1.13.1212088875.squirrel@grid.net.ru> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> <.192.168.1.13.1212084138.squirrel@grid.net.ru> <20080529191505.GK30848@moria.seul.org> <.192.168.1.13.1212088875.squirrel@grid.net.ru> Message-ID: <.62.218.60.210.1212135504.squirrel@grid.net.ru> Below is the new version of file test_et.c. The resulting executable should return 1 whenever ET works, 0 otherwise. >>> I must think a bit how to automate this. Please give me time. >> >> Maybe you could use the EVLOOP_NONBLOCK flag to event_loop(), and call >> it twice, and verify that in the edge-triggered case the event is only >> activated on the first call, but in the level-triggered case the event >> is activated on the second call too? > > This looks exactly like a solution to a problem. Thanks, I'll fix. -- Best regards, Valery Kholodkov -------------- next part -------------- A non-text attachment was scrubbed... Name: test_et.c Type: application/octet-stream Size: 1271 bytes Desc: not available Url : http://monkeymail.org/archives/libevent-users/attachments/20080530/f33c4afb/test_et.obj From nickm at freehaven.net Fri May 30 13:06:14 2008 From: nickm at freehaven.net (Nick Mathewson) Date: Fri May 30 13:06:48 2008 Subject: [Libevent-users] Support for Edge-Triggered behaviour In-Reply-To: <.62.218.60.210.1212135504.squirrel@grid.net.ru> References: <.62.218.60.210.1212075616.squirrel@grid.net.ru> <20080529161021.GJ30848@moria.seul.org> <.192.168.1.13.1212084138.squirrel@grid.net.ru> <20080529191505.GK30848@moria.seul.org> <.192.168.1.13.1212088875.squirrel@grid.net.ru> <.62.218.60.210.1212135504.squirrel@grid.net.ru> Message-ID: <20080530170614.GQ30848@moria.seul.org> On Fri, May 30, 2008 at 10:18:24AM +0200, Valery Kholodkov wrote: > > Below is the new version of file test_et.c. The resulting > executable should return 1 whenever ET works, 0 otherwise. Applied to trunk; thanks! -- Nick