From: Niels Provos Date: Mon, 24 May 2004 00:19:52 +0000 (+0000) Subject: fix some of the windows compile issues; make buffer.c faster; support X-Git-Tag: release-1.1b~64 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=025d1bc2206c5b7edb2fb0c2ad58e7322f4b8b4d;p=libevent fix some of the windows compile issues; make buffer.c faster; support signals via pipes. svn:r105 --- diff --git a/WIN32-Code/config.h b/WIN32-Code/config.h index 2f65ac07..71b373ef 100644 --- a/WIN32-Code/config.h +++ b/WIN32-Code/config.h @@ -16,7 +16,7 @@ /* #undef u_int8_t */ /* Define if timeradd is defined in */ -#define HAVE_TIMERADD 1 +/* #undef HAVE_TIMERADD */ #ifndef HAVE_TIMERADD #define timeradd(tvp, uvp, vvp) \ do { \ @@ -92,13 +92,13 @@ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 +/* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 +/* #undef HAVE_UNISTD_H */ /* Define to 1 if you have the `warnx' function. */ #define HAVE_WARNX 1 @@ -129,3 +129,21 @@ /* Version number of package */ #define VERSION "0.6" + +typedef unsigned char u_char; + +/* Winsock compatibility */ +#define SHUT_WR SD_SEND + +struct timeval; +struct timezone; +int gettimeofday(struct timeval *tv, struct timezone *tz); + +#define read win_read +#define write win_write + +int win_read(int, void *, unsigned int); +int win_write(int, void *, unsigned int); +int socketpair(int d, int type, int protocol, int *sv); + +#define __func__ __FILE__ \ No newline at end of file diff --git a/WIN32-Code/misc.c b/WIN32-Code/misc.c index f3458f24..7329242b 100644 --- a/WIN32-Code/misc.c +++ b/WIN32-Code/misc.c @@ -28,3 +28,56 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { tv->tv_usec = ((int) tb.millitm) * 1000; return 0; } + +int +win_read(int fd, void *buf, unsigned int length) +{ + DWORD dwBytesRead; + int res = ReadFile((HANDLE) fd, buf, length, &dwBytesRead, NULL); + if (res == 0) { + DWORD error = GetLastError(); + if (error == ERROR_NO_DATA) + return (0); + return (-1); + } else + return (dwBytesRead); +} + +int +win_write(int fd, void *buf, unsigned int length) +{ + DWORD dwBytesWritten; + int res = WriteFile((HANDLE) fd, buf, length, &dwBytesWritten, NULL); + if (res == 0) { + DWORD error = GetLastError(); + if (error == ERROR_NO_DATA) + return (0); + return (-1); + } else + return (dwBytesWritten); +} + +int +socketpair(int d, int type, int protocol, int *sv) +{ + static int count; + char buf[64]; + HANDLE fd; + DWORD dwMode; + sprintf(buf, "\\\\.\\pipe\\levent-%d", count++); + /* Create a duplex pipe which will behave like a socket pair */ + fd = CreateNamedPipe(buf, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT, + PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL); + if (fd == INVALID_HANDLE_VALUE) + return (-1); + sv[0] = (int)fd; + + fd = CreateFile(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd == INVALID_HANDLE_VALUE) + return (-1); + dwMode = PIPE_NOWAIT; + SetNamedPipeHandleState(fd, &dwMode, NULL, NULL); + sv[1] = (int)fd; + + return (0); +} \ No newline at end of file diff --git a/buffer.c b/buffer.c index 393188b4..bbd9378f 100644 --- a/buffer.c +++ b/buffer.c @@ -62,8 +62,8 @@ evbuffer_new(void) void evbuffer_free(struct evbuffer *buffer) { - if (buffer->buffer != NULL) - free(buffer->buffer); + if (buffer->orig_buffer != NULL) + free(buffer->orig_buffer); free(buffer); } @@ -72,10 +72,42 @@ evbuffer_free(struct evbuffer *buffer) * the other buffer. */ +#define SWAP(x,y) do { \ + (x)->buffer = (y)->buffer; \ + (x)->orig_buffer = (y)->orig_buffer; \ + (x)->misalign = (y)->misalign; \ + (x)->totallen = (y)->totallen; \ + (x)->off = (y)->off; \ +} while (0) + int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) { int res; + + /* Short cut for better performance */ + if (outbuf->off == 0) { + struct evbuffer tmp; + size_t oldoff = inbuf->off; + + /* Swap them directly */ + SWAP(&tmp, outbuf); + SWAP(outbuf, inbuf); + SWAP(inbuf, &tmp); + + /* + * Optimization comes with a price; we need to notify the + * buffer if necessary of the changes. oldoff is the amount + * of data that we tranfered from inbuf to outbuf + */ + if (inbuf->off != oldoff && inbuf->cb != NULL) + (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); + if (oldoff && outbuf->cb != NULL) + (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg); + + return (0); + } + res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); if (res == 0) evbuffer_drain(inbuf, inbuf->off); @@ -88,44 +120,86 @@ evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...) { int res = -1; char *msg; +#ifdef WIN32 + static char buffer[4096]; +#endif va_list ap; va_start(ap, fmt); +#ifndef WIN32 if (vasprintf(&msg, fmt, ap) == -1) goto end; +#else + _vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap); + buffer[sizeof(buffer)-1] = '\0'; + msg = buffer; +#endif res = strlen(msg); if (evbuffer_add(buf, msg, res) == -1) res = -1; +#ifndef WIN32 free(msg); - end: +end: +#endif va_end(ap); return (res); } +/* Reads data from an event buffer and drains the bytes read */ + int -evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen) +evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) { - size_t need = buf->off + datlen; - size_t oldoff = buf->off; + int nread = datlen; + if (nread >= buf->off) + nread = buf->off; - if (buf->totallen < need) { - void *newbuf; - int length = buf->totallen; + memcpy(data, buf->buffer, nread); + evbuffer_drain(buf, nread); + + return (nread); +} + +/* Adds data to an event buffer */ - if (length < 256) - length = 256; - while (length < need) - length <<= 1; +static __inline void +evbuffer_align(struct evbuffer *buf) +{ + memmove(buf->orig_buffer, buf->buffer, buf->off); + buf->buffer = buf->orig_buffer; + buf->misalign = 0; +} - if ((newbuf = realloc(buf->buffer, length)) == NULL) - return (-1); +int +evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + size_t oldoff = buf->off; - buf->buffer = newbuf; - buf->totallen = length; + if (buf->totallen < need) { + if (buf->misalign >= datlen) { + evbuffer_align(buf); + } else { + void *newbuf; + size_t length = buf->totallen; + + if (length < 256) + length = 256; + while (length < need) + length <<= 1; + + if (buf->orig_buffer != buf->buffer) + evbuffer_align(buf); + if ((newbuf = realloc(buf->buffer, length)) == NULL) + return (-1); + + buf->orig_buffer = buf->buffer = newbuf; + buf->totallen = length; + } } memcpy(buf->buffer + buf->off, data, datlen); @@ -144,10 +218,14 @@ evbuffer_drain(struct evbuffer *buf, size_t len) if (len >= buf->off) { buf->off = 0; + buf->buffer = buf->orig_buffer; + buf->misalign = 0; goto done; } - memmove(buf->buffer, buf->buffer + len, buf->off - len); + buf->buffer += len; + buf->misalign += len; + buf->off -= len; done: @@ -162,15 +240,27 @@ evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) { u_char inbuf[4096]; int n; +#ifdef WIN32 + DWORD dwBytesRead; +#endif if (howmuch < 0 || howmuch > sizeof(inbuf)) howmuch = sizeof(inbuf); +#ifndef WIN32 n = read(fd, inbuf, howmuch); if (n == -1) return (-1); if (n == 0) return (0); +#else + n = ReadFile((HANDLE)fd, inbuf, howmuch, &dwBytesRead, NULL); + if (n == 0) + return (-1); + if (dwBytesRead == 0) + return (0); + n = dwBytesRead; +#endif evbuffer_add(buffer, inbuf, n); @@ -181,13 +271,24 @@ int evbuffer_write(struct evbuffer *buffer, int fd) { int n; +#ifdef WIN32 + DWORD dwBytesWritten; +#endif +#ifndef WIN32 n = write(fd, buffer->buffer, buffer->off); if (n == -1) return (-1); if (n == 0) return (0); - +#else + n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); + if (n == 0) + return (-1); + if (dwBytesWritten == 0) + return (0); + n = dwBytesWritten; +#endif evbuffer_drain(buffer, n); return (n); diff --git a/event.c b/event.c index 92eadde7..f5e0c762 100644 --- a/event.c +++ b/event.c @@ -103,8 +103,11 @@ const struct eventop *eventops[] = { NULL }; +/* Global state */ + const struct eventop *evsel; void *evbase; +static int event_count; /* Handle signals - This is a deprecated interface */ int (*event_sigcb)(void); /* Signal callback when gotsig is set */ @@ -133,7 +136,7 @@ compare(struct event *a, struct event *b) return (1); if (a < b) return (-1); - if (a > b) + else if (a > b) return (1); return (0); } @@ -152,6 +155,11 @@ event_init(void) event_gotsig = 0; gettimeofday(&event_tv, NULL); +#if defined(USE_LOG) && defined(USE_DEBUG) + log_to(stderr); + log_debug_cmd(LOG_MISC, 80); +#endif + RB_INIT(&timetree); TAILQ_INIT(&eventqueue); TAILQ_INIT(&activequeue); @@ -169,18 +177,12 @@ event_init(void) if (getenv("EVENT_SHOW_METHOD")) fprintf(stderr, "libevent using: %s\n", evsel->name); - -#if defined(USE_LOG) && defined(USE_DEBUG) - log_to(stderr); - log_debug_cmd(LOG_MISC, 80); -#endif } int event_haveevents(void) { - return (RB_ROOT(&timetree) || TAILQ_FIRST(&eventqueue) || - TAILQ_FIRST(&signalqueue) || TAILQ_FIRST(&activequeue)); + return (event_count > 0); } static void @@ -582,6 +584,9 @@ event_queue_remove(struct event *ev, int queue) errx(1, "%s: %p(fd %d) not on queue %x", __func__, ev, ev->ev_fd, queue); + if (!(ev->ev_flags & EVLIST_INTERNAL)) + event_count--; + ev->ev_flags &= ~queue; switch (queue) { case EVLIST_ACTIVE: @@ -608,6 +613,9 @@ event_queue_insert(struct event *ev, int queue) errx(1, "%s: %p(fd %d) already on queue %x", __func__, ev, ev->ev_fd, queue); + if (!(ev->ev_flags & EVLIST_INTERNAL)) + event_count++; + ev->ev_flags |= queue; switch (queue) { case EVLIST_ACTIVE: diff --git a/event.h b/event.h index eddb0e96..96a725c5 100644 --- a/event.h +++ b/event.h @@ -39,10 +39,11 @@ extern "C" { #define EVLIST_INSERTED 0x02 #define EVLIST_SIGNAL 0x04 #define EVLIST_ACTIVE 0x08 +#define EVLIST_INTERNAL 0x10 #define EVLIST_INIT 0x80 /* EVLIST_X_ Private space: 0x1000-0xf000 */ -#define EVLIST_ALL (0xf000 | 0x8f) +#define EVLIST_ALL (0xf000 | 0x9f) #define EV_TIMEOUT 0x01 #define EV_READ 0x02 @@ -170,7 +171,9 @@ int event_pending(struct event *, short, struct timeval *); struct evbuffer { u_char *buffer; + u_char *orig_buffer; + size_t misalign; size_t totallen; size_t off; @@ -233,7 +236,8 @@ void bufferevent_settimeout(struct bufferevent *bufev, struct evbuffer *evbuffer_new(void); void evbuffer_free(struct evbuffer *); -int evbuffer_add(struct evbuffer *, u_char *, size_t); +int evbuffer_add(struct evbuffer *, void *, size_t); +int evbuffer_remove(struct evbuffer *, void *, size_t); int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); int evbuffer_add_printf(struct evbuffer *, char *fmt, ...); void evbuffer_drain(struct evbuffer *, size_t); diff --git a/sample/event-test.c b/sample/event-test.c index 0eac37e7..965984d4 100644 --- a/sample/event-test.c +++ b/sample/event-test.c @@ -45,7 +45,7 @@ fifo_read(int fd, short event, void *arg) return; } - buf[dwBytesRead + 1] = '\0'; + buf[dwBytesRead] = '\0'; #else len = read(fd, buf, sizeof(buf) - 1); diff --git a/sample/signal-test.c b/sample/signal-test.c index 7a1fefec..98650ca1 100644 --- a/sample/signal-test.c +++ b/sample/signal-test.c @@ -4,6 +4,11 @@ */ #include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #ifndef WIN32 #include diff --git a/sample/time-test.c b/sample/time-test.c index da508ff8..f0f93995 100644 --- a/sample/time-test.c +++ b/sample/time-test.c @@ -4,6 +4,11 @@ */ #include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #ifndef WIN32 #include @@ -11,7 +16,9 @@ #else #include #endif +#ifdef HAVE_SYS_TIME_H #include +#endif #include #include #include diff --git a/signal.c b/signal.c index c748927a..07345002 100644 --- a/signal.c +++ b/signal.c @@ -35,6 +35,7 @@ #include #endif #include +#include #include #include #include @@ -63,10 +64,39 @@ void evsignal_process(void); int evsignal_recalc(sigset_t *); int evsignal_deliver(sigset_t *); +static struct event ev_signal; +static int ev_signal_pair[2]; +static int ev_signal_added; + +/* Callback for when the signal handler write a byte to our signaling socket */ +static void evsignal_cb(int fd, short what, void *arg) +{ + static char signals[100]; + struct event *ev = arg; + int n; + + n = read(fd, signals, sizeof(signals)); + if (n == -1) + err(1, "%s: read"); + event_add(ev, NULL); +} + void evsignal_init(sigset_t *evsigmask) { sigemptyset(evsigmask); + + /* + * Our signal handler is going to write to one end of the socket + * pair to wake up our event loop. The event loop then scans for + * signals that got delivered. + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1) + err(1, "%s: socketpair", __func__); + + event_set(&ev_signal, ev_signal_pair[1], EV_READ, + evsignal_cb, &ev_signal); + ev_signal.ev_flags |= EVLIST_INTERNAL; } int @@ -103,6 +133,9 @@ evsignal_handler(int sig) { evsigcaught[sig]++; evsignal_caught = 1; + + /* Wake up our notification mechanism */ + write(ev_signal_pair[0], "a", 1); } int @@ -110,6 +143,11 @@ evsignal_recalc(sigset_t *evsigmask) { struct sigaction sa; struct event *ev; + + if (!ev_signal_added) { + ev_signal_added = 1; + event_add(&ev_signal, NULL); + } if (TAILQ_FIRST(&signalqueue) == NULL && !needrecalc) return (0); diff --git a/test/regress.c b/test/regress.c index 7361f227..2ac4b113 100644 --- a/test/regress.c +++ b/test/regress.c @@ -25,20 +25,29 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef WIN32 +#include +#include +#endif + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include +#ifdef HAVE_SYS_TIME_H #include +#endif +#ifndef WIN32 #include #include +#include +#endif #include #include #include #include -#include #include #include @@ -232,9 +241,13 @@ setup_test(char *name) int cleanup_test(void) { +#ifndef WIN32 close(pair[0]); close(pair[1]); - +#else + CloseHandle((HANDLE)pair[0]); + CloseHandle((HANDLE)pair[1]); +#endif if (test_ok) fprintf(stdout, "OK\n"); else { @@ -382,6 +395,7 @@ test6(void) cleanup_test(); } +#ifndef WIN32 void test7(void) { @@ -403,6 +417,7 @@ test7(void) cleanup_test(); } +#endif void test8(void) @@ -490,6 +505,16 @@ test9(void) int main (int argc, char **argv) { +#ifdef WIN32 + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 2 ); + + err = WSAStartup( wVersionRequested, &wsaData ); +#endif + setvbuf(stdout, NULL, _IONBF, 0); /* Initalize the event library */ @@ -506,9 +531,9 @@ main (int argc, char **argv) test5(); test6(); - +#ifndef WIN32 test7(); - +#endif test8(); test9();