From des at projects.linpro.no Thu Mar 2 10:29:52 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Thu, 2 Mar 2006 11:29:52 +0100 (CET) Subject: r40 - trunk/varnish-cache/bin/varnishd Message-ID: <20060302102952.6C2DA1ED469@projects.linpro.no> Author: des Date: 2006-03-02 11:29:52 +0100 (Thu, 02 Mar 2006) New Revision: 40 Modified: trunk/varnish-cache/bin/varnishd/ Log: Add varnishd to ignore list. Property changes on: trunk/varnish-cache/bin/varnishd ___________________________________________________________________ Name: svn:ignore - .deps .libs Makefile Makefile.in + .deps .libs Makefile Makefile.in varnishd From des at projects.linpro.no Thu Mar 2 10:31:17 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Thu, 2 Mar 2006 11:31:17 +0100 (CET) Subject: r41 - in trunk/varnish-cache: include include/varnish lib/libvarnishapi Message-ID: <20060302103117.482C61ED541@projects.linpro.no> Author: des Date: 2006-03-02 11:31:17 +0100 (Thu, 02 Mar 2006) New Revision: 41 Added: trunk/varnish-cache/include/varnish/ trunk/varnish-cache/include/varnish/assert.h trunk/varnish-cache/lib/libvarnishapi/varnish_debug.c trunk/varnish-cache/lib/libvarnishapi/varnish_log.c trunk/varnish-cache/lib/libvarnishapi/varnish_util.c Modified: trunk/varnish-cache/include/Makefile.am trunk/varnish-cache/include/varnishapi.h trunk/varnish-cache/lib/libvarnishapi/Makefile.am Log: Untested & undocumented login code. I don't have time to continue working on it right now, but I want it in the tree so phk doesn't start duplicating my effort. Modified: trunk/varnish-cache/include/Makefile.am =================================================================== --- trunk/varnish-cache/include/Makefile.am 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/include/Makefile.am 2006-03-02 10:31:17 UTC (rev 41) @@ -1,4 +1,6 @@ # $Id$ -include_HEADERS = varnishapi.h +include_HEADERS = \ + varnish/assert.h \ + varnishapi.h Added: trunk/varnish-cache/include/varnish/assert.h =================================================================== --- trunk/varnish-cache/include/varnish/assert.h 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/include/varnish/assert.h 2006-03-02 10:31:17 UTC (rev 41) @@ -0,0 +1,20 @@ +/* + * $Id$ + */ + +#ifndef VARNISH_ASSERT_H_INCLUDED +#define VARNISH_ASSERT_H_INCLUDED + +#ifdef NDEBUG +#define V_ASSERT(test) \ + do { /* nothing */ } while (0) +#else +#define V_ASSERT(test) \ + do { \ + if (!(test)) \ + vdb_panic("assertion failed in %s line %d: %s", \ + #test, __FILE__, __LINE__); \ + } while (0) +#endif + +#endif Modified: trunk/varnish-cache/include/varnishapi.h =================================================================== --- trunk/varnish-cache/include/varnishapi.h 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/include/varnishapi.h 2006-03-02 10:31:17 UTC (rev 41) @@ -5,6 +5,23 @@ #ifndef VARNISHAPI_H_INCLUDED #define VARNISHAPI_H_INCLUDED -/* ... */ +#define V_DEAD __attribute__ ((noreturn)) +/* varnish_debug.c */ +void vdb_panic(const char *, ...) V_DEAD; + +/* varnish_log.c */ +typedef struct vlo_buffer vlo_buffer_t; +vlo_buffer_t *vlo_open(const char *, size_t, int); +ssize_t vlo_write(vlo_buffer_t *, const void *, size_t); +vlo_buffer_t *vlo_attach(const char *); +ssize_t vlo_read(vlo_buffer_t *, const void *, size_t); +#if 0 +uuid_t vlo_get_uuid(vlo_buffer_t *); #endif +int vlo_close(vlo_buffer_t *); + +/* varnish_util.c */ +int vut_open_lock(const char *, int, int, int); + +#endif Modified: trunk/varnish-cache/lib/libvarnishapi/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvarnishapi/Makefile.am 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/lib/libvarnishapi/Makefile.am 2006-03-02 10:31:17 UTC (rev 41) @@ -4,4 +4,7 @@ lib_LTLIBRARIES = libvarnishapi.la -libvarnishapi_la_SOURCES = +libvarnishapi_la_SOURCES = \ + varnish_debug.c \ + varnish_log.c \ + varnish_util.c Added: trunk/varnish-cache/lib/libvarnishapi/varnish_debug.c =================================================================== --- trunk/varnish-cache/lib/libvarnishapi/varnish_debug.c 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/lib/libvarnishapi/varnish_debug.c 2006-03-02 10:31:17 UTC (rev 41) @@ -0,0 +1,25 @@ +/* + * $Id$ + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include + +void +varnish_panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, fmt, ap); + va_end(ap); + signal(SIGABRT, SIG_DFL); + raise(SIGABRT); +} Added: trunk/varnish-cache/lib/libvarnishapi/varnish_log.c =================================================================== --- trunk/varnish-cache/lib/libvarnishapi/varnish_log.c 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/lib/libvarnishapi/varnish_log.c 2006-03-02 10:31:17 UTC (rev 41) @@ -0,0 +1,293 @@ +/* + * $Id$ + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define VLO_MAGIC 0x564c4f00 + +typedef struct vlo_control vlo_control_t; + +/* should this be part of the exported API? */ +struct vlo_control { + uint32_t magic; +#if 0 + uuid_t uuid; +#endif + uint32_t size; + uint32_t head; + uint32_t tail; +}; + +struct vlo_buffer { + int mode; + int cfd; + vlo_control_t *ctl; + int bfd; + unsigned char *buf; + uint32_t rpos; +}; + +/* + * Open a log file for writing; create it if necessary. If the control + * file already exists, try to preserve its state, in case someone is + * already listening. + */ +vlo_buffer_t * +vlo_open(const char *name, size_t size, int perm) +{ + char ctlname[PATH_MAX]; + vlo_buffer_t *vb; + int page_size; + int i, serr; + + page_size = getpagesize(); + + V_ASSERT(size > 0); + V_ASSERT(size % page_size == 0); + + if (snprintf(ctlname, sizeof ctlname, "%s.ctl", name) >= sizeof ctlname) { + errno = ENAMETOOLONG; + return (NULL); + } + if ((vb = malloc(sizeof *vb)) == NULL) + goto out; + vb->mode = O_RDWR; + vb->cfd = -1; + vb->ctl = NULL; + vb->bfd = -1; + vb->buf = NULL; + vb->rpos = 0; + + /* open, lock and mmap the control file */ + if ((vb->cfd = vut_open_lock(ctlname, O_RDWR|O_CREAT, + LOCK_EX|LOCK_NB, perm)) == -1 || + ftruncate(vb->cfd, page_size) == -1 || + (vb->ctl = mmap(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_SHARED, vb->cfd, 0)) == NULL || + mlock(vb->ctl, page_size) == -1) + goto out; + + /* open, lock and mmap the buffer file */ + if ((vb->bfd = open(name, O_RDWR|O_CREAT, perm)) == -1 || + flock(vb->bfd, LOCK_EX) == -1 || + ftruncate(vb->bfd, size) == -1 || + (vb->buf = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_SHARED, vb->bfd, 0)) == NULL || + mlock(vb->ctl, size) == -1) + goto out; + + /* initialize control structures */ + if (vb->ctl->magic != VLO_MAGIC || + vb->ctl->size != size || + vb->ctl->head >= size || + vb->ctl->tail >= size) { + vb->ctl->magic = VLO_MAGIC; +#if 0 + vb->ctl->uuid = /* XXX */; +#endif + vb->ctl->size = size; + vb->ctl->head = size - page_size; /* early wraparound */ + vb->ctl->tail = vb->ctl->head; + vb->rpos = vb->ctl->tail; + } + + /* pre-fault buffer */ + for (i = 0; i < size; i += page_size) + vb->buf[i] = '\0'; + + return (vb); + out: + serr = errno; + if (vb != NULL) { + if (vb->buf != NULL) { + munlock(vb->buf, size); + munmap(vb->buf, size); + } + if (vb->bfd != -1) + close(vb->bfd); + if (vb->ctl != NULL) { + munlock(vb->ctl, page_size); + munmap(vb->ctl, page_size); + } + if (vb->cfd != -1) + close(vb->cfd); + free(vb); + } + errno = serr; + return (NULL); +} + +/* + * Write to a log file. + */ +ssize_t +vlo_write(vlo_buffer_t *vb, const void *data, size_t len) +{ + ssize_t result; + size_t copylen; + + V_ASSERT(vb != NULL); + V_ASSERT(vb->mode == O_WRONLY || vb->mode == O_RDWR); + V_ASSERT(vb->cfd != -1 && vb->ctl != NULL); + V_ASSERT(vb->bfd != -1 && vb->buf != NULL); + V_ASSERT(vb->ctl->magic == VLO_MAGIC); + + for (result = 0; len > 0; len -= copylen, result += copylen) { + if (vb->ctl->head + len > vb->ctl->size) + copylen = vb->ctl->size - vb->ctl->head; + else + copylen = len; + if (vb->ctl->tail > vb->ctl->head && + vb->ctl->tail <= vb->ctl->head + copylen) + vb->ctl->tail = + (vb->ctl->head + copylen + 1) % vb->ctl->size; + memcpy(vb->buf + vb->ctl->head, data, copylen); + vb->ctl->head = (vb->ctl->head + copylen) % vb->ctl->size; + } + return (result); +} + +/* + * Attach to an existing log buffer. + */ +vlo_buffer_t * +vlo_attach(const char *name) +{ + char ctlname[PATH_MAX]; + vlo_buffer_t *vb; + int page_size; + int serr; + + page_size = getpagesize(); + + if (snprintf(ctlname, sizeof ctlname, "%s.ctl", name) >= sizeof ctlname) { + errno = ENAMETOOLONG; + return (NULL); + } + if ((vb = malloc(sizeof *vb)) == NULL) + goto out; + vb->mode = O_RDONLY; + vb->cfd = -1; + vb->ctl = NULL; + vb->bfd = -1; + vb->buf = NULL; + vb->rpos = 0; + + /* open, lock and mmap the control file */ + if ((vb->cfd = open(ctlname, O_RDONLY)) == -1 || + (vb->ctl = mmap(NULL, page_size, PROT_READ, + MAP_SHARED, vb->cfd, 0)) == NULL || + mlock(vb->ctl, page_size) == -1) + goto out; + + /* verify control structure */ + if (vb->ctl->magic != VLO_MAGIC || + !(vb->ctl->size > 0 && (vb->ctl->size % page_size) == 0)) { + errno = EINVAL; /* XXX document */ + goto out; + } + + /* open, lock and mmap the buffer file */ + if ((vb->bfd = open(name, O_RDONLY)) == -1 || + (vb->buf = mmap(NULL, vb->ctl->size, PROT_READ, + MAP_SHARED, vb->bfd, 0)) == NULL || + mlock(vb->ctl, vb->ctl->size) == -1) + goto out; + + vb->rpos = vb->ctl->tail; + + return (vb); + out: + serr = errno; + if (vb != NULL) { + if (vb->buf != NULL) { + munlock(vb->buf, vb->ctl->size); + munmap(vb->buf, vb->ctl->size); + } + if (vb->bfd != -1) + close(vb->bfd); + if (vb->ctl != NULL) { + munlock(vb->ctl, page_size); + munmap(vb->ctl, page_size); + } + if (vb->cfd != -1) + close(vb->cfd); + free(vb); + } + errno = serr; + return (NULL); +} + +/* + * Read from a log file. + */ +ssize_t +vlo_read(vlo_buffer_t *vb, const void *data, size_t len) +{ + V_ASSERT(vb != NULL); + V_ASSERT(vb->mode == O_RDONLY || vb->mode == O_RDWR); + V_ASSERT(vb->cfd != -1 && vb->ctl != NULL); + V_ASSERT(vb->bfd != -1 && vb->buf != NULL); + V_ASSERT(vb->ctl->magic == VLO_MAGIC); + + /* not implemented */ + return (-1); +} + +#if 0 +/* + * Return the UUID of the process writing to the log file. + */ +uuid_t +vlo_get_uuid(vlo_buffer *vb) +{ + V_ASSERT(vb != NULL); + V_ASSERT(vb->cfd != -1 && vb->ctl != NULL); + V_ASSERT(vb->bfd != -1 && vb->buf != NULL); + V_ASSERT(vb->ctl->magic == VLO_MAGIC); + + return (vb->ctl->uuid); +} +#endif + +/* + * Close a log file. + */ +int +vlo_close(vlo_buffer_t *vb) +{ + int page_size; + + page_size = getpagesize(); + + V_ASSERT(vb != NULL); + V_ASSERT(vb->cfd != -1 && vb->ctl != NULL); + V_ASSERT(vb->bfd != -1 && vb->buf != NULL); + V_ASSERT(vb->ctl->magic == VLO_MAGIC); + + munlock(vb->buf, vb->ctl->size); + munmap(vb->buf, vb->ctl->size); + close(vb->bfd); + munlock(vb->ctl, page_size); + munmap(vb->ctl, page_size); + close(vb->cfd); + free(vb); + return (0); +} Added: trunk/varnish-cache/lib/libvarnishapi/varnish_util.c =================================================================== --- trunk/varnish-cache/lib/libvarnishapi/varnish_util.c 2006-03-02 10:29:52 UTC (rev 40) +++ trunk/varnish-cache/lib/libvarnishapi/varnish_util.c 2006-03-02 10:31:17 UTC (rev 41) @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include + +/** + * Open and lock a file. + */ +int +vut_open_lock(const char *name, int mode, int lockop, int perm) +{ + struct stat sb, fsb; + int fd, serr; + + for (;;) { + if ((fd = open(name, mode, perm)) == -1) + /* not much we can do about that */ + return (-1); + while (flock(fd, lockop) == -1) { + if (errno != EINTR) { + serr = errno; + close(fd); + errno = serr; + return (-1); + } + } + if (stat(name, &sb) == -1) { + serr = errno; + close(fd); + errno = serr; + + if (errno == ENOENT && (mode & O_CREAT)) + /* file was deleted from under our nose */ + continue; + return (-1); + } + if (fstat(fd, &fsb) == -1) { + /* serious voodoo is going on*/ + serr = errno; + close(fd); + errno = serr; + return (-1); + } + if (sb.st_dev == fsb.st_dev && sb.st_ino == fsb.st_ino) + /* we have the correct file */ + return (fd); + close(fd); + } + /* not reached */ +} From des at projects.linpro.no Thu Mar 2 10:32:59 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Thu, 2 Mar 2006 11:32:59 +0100 (CET) Subject: r42 - trunk/varnish-cache Message-ID: <20060302103259.F27241ED553@projects.linpro.no> Author: des Date: 2006-03-02 11:32:59 +0100 (Thu, 02 Mar 2006) New Revision: 42 Modified: trunk/varnish-cache/ Log: Ignore generated files; generated with the following command: svk propset svn:ignore "$(svk status | awk '/^\?/ { print $2 }')" . Property changes on: trunk/varnish-cache ___________________________________________________________________ Name: svn:ignore + .deps Makefile Makefile.in aclocal.m4 autom4te.cache config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh missing stamp-h1 From phk at projects.linpro.no Mon Mar 13 12:37:05 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 13 Mar 2006 13:37:05 +0100 (CET) Subject: r43 - in trunk/varnish-cache/lib: . libvcl Message-ID: <20060313123705.390161ED539@projects.linpro.no> Author: phk Date: 2006-03-13 13:37:04 +0100 (Mon, 13 Mar 2006) New Revision: 43 Added: trunk/varnish-cache/lib/libvcl/ trunk/varnish-cache/lib/libvcl/Makefile trunk/varnish-cache/lib/libvcl/sample.vcl trunk/varnish-cache/lib/libvcl/vcl_compile.c trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcl_lang.h trunk/varnish-cache/lib/libvcl/vcl_priv.h trunk/varnish-cache/lib/libvcl/vcl_token_defs.h Modified: trunk/varnish-cache/lib/Makefile.am Log: Add first cut of VCL compiler to the tree. The Makefile is a temporary shim until I get the auto* stuff working. The sample.vcl is a small mock-up to test the compiler. Some of the .h files needs to move other places in the fullness of time. But other than that... Modified: trunk/varnish-cache/lib/Makefile.am =================================================================== --- trunk/varnish-cache/lib/Makefile.am 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/Makefile.am 2006-03-13 12:37:04 UTC (rev 43) @@ -2,4 +2,5 @@ SUBDIRS = \ libvarnish \ - libvarnishapi + libvarnishapi \ + libvcl Added: trunk/varnish-cache/lib/libvcl/Makefile =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/Makefile 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,20 @@ +PROG = vpc + +SRCS += vcl_compile.c +SRCS += vcl_fixed_token.c + +NO_MAN = yes + +WARNS ?= 5 + +LDADD += -lsbuf + +.include + + +test: ${PROG} + ./${PROG} ${.CURDIR}/sample.vcl + cc -Wall -c _.c + +flint: + flint flint.lnt -I/usr/include -I. ${SRCS} Added: trunk/varnish-cache/lib/libvcl/sample.vcl =================================================================== --- trunk/varnish-cache/lib/libvcl/sample.vcl 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/sample.vcl 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,109 @@ + +acl rfc1918 { + 10.0.0.0/8; + 172.16.0.0/12; + 192.168.0.0/16; +} + +sub request_policy { + + if (client.ip == 10.1.2.3) { + no_cache; + finish; + } + + if (client.ip ~ rfc1918) { + no_cache; + finish; + } + + if (req.url.host ~ "cnn.no$") { + rewrite "cnn.no$" "vg.no"; + } + + if (req.url.path ~ "cgi-bin") { + no_cache; + } + + if (req.useragent ~ "spider") { + no_new_cache; + } + +# comment + + if (backend.response_time <= 0.8s) { + set req.ttlfactor = 1.5; + } elseif (backend.response_time > 1.5s) { + set req.ttlfactor = 2.0; + } elseif (backend.response_time > 2.5m) { + set req.ttlfactor = 5.0; + } + + /* + * the program contains no references to + * maxage, s-maxage and expires, so the + * default handling (RFC2616) applies + */ +} + +backend vg { + set backend.ip = 10.0.0.100; + set backend.timeout = 4s; + set backend.bandwidth = 2000Mb/s; +} + +backend chat { + set backend.ip = 10.0.0.4; + set backend.timeout = 4s; + set backend.bandwidth = 2000Mb/s; +} + +sub bail { + error 404 "Bailing out"; + finish; +} + +sub fetch_policy { + + if (!req.url.host ~ "/vg.no$/") { + set req.backend = vg; + } else { + /* XXX: specify 404 page url ? */ + error 404; + } + + if (backend.response_time > 2.0s) { + if (req.url.path ~ "/landbrugspriser/") { + call bail; + } + } + fetch; + if (backend.down) { + if (obj.exist) { + set obj.ttl += 10m; + finish; + } + switch_config ohhshit; + } + if (obj.result == 404) { + error 300 "http://www.vg.no"; + } + if (obj.result != 200) { + finish; + } + if (obj.size > 256kb) { + no_cache; + } else if (obj.size > 32kb && obj.ttl < 2m) { + set obj.ttl = 5m; + } + if (backend.response_time > 2.0s) { + set obj.ttl *= 2.0; + } +} + +sub prefetch_policy { + + if (obj.usage < 10 && obj.ttl < 5m) { + fetch; + } +} Added: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,1383 @@ +/* + * $Id$ + */ + +/* + * XXX: + * generate interface structure + * + * XXX: + * Better error messages, throughout. + * >It also accured to me that we could link the errors to the error + * >documentation. + * > + * >Unreferenced function 'request_policy', first mention is + * > Line 8 Pos 4 + * > sub request_policy { + * > ----##############-- + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unreferenced%20function + * > + * > + * > Unknown variable 'obj.bandwidth' + * > At: Line 88 Pos 12 + * > if (obj.bandwidth < 1 kb/h) { + * > ------------#############------------ + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unknown%20variable + * + * XXX: + * Create proper tmp filenames for .h, .c and .o + * + * XXX: + * and all the rest... + */ + +#include +#include +#include +#include +#include +#include +#include +#include "vcl_priv.h" + +#define ERRCHK(tl) do { if ((tl)->err) return; } while (0) + +#define INDENT 2 + +struct token { + unsigned tok; + const char *b; + const char *e; + TAILQ_ENTRY(token) list; + unsigned cnt; +}; + +struct tokenlist { + TAILQ_HEAD(, token) tokens; + const char *b; + const char *e; + struct token *t; + int indent; + unsigned cnt; + FILE *fc, *fh; + TAILQ_HEAD(, ref) refs; + struct sbuf *sb; + int err; +}; + +enum var_type { + BACKEND, + BOOL, + INT, + FLOAT, + SIZE, + RATE, + TIME, + STRING, + IP +}; + +struct var { + const char *name; + enum var_type fmt; + int len; + const char *cname; + +}; + +enum ref_type { + R_FUNC, + R_ACL, + R_BACKEND +}; + +struct ref { + enum ref_type type; + struct token *name; + unsigned defcnt; + unsigned refcnt; + TAILQ_ENTRY(ref) list; +}; + + +static struct var vars[] = { + { "req.ttlfactor", FLOAT, 0, "req->ttlfactor" }, + { "req.url.host", STRING, 0, "req->url.host" }, + { "req.url.path", STRING, 0, "req->url.path" }, + { "req.useragent", STRING, 0, "req->useragent" }, + { "req.backend", BACKEND, 0, "req->backend" }, + { "client.ip", IP, 0, "client->ip" }, + { "backend.response_time", TIME, 0, "backend->responsetime" }, + { "backend.ip", IP, 0, "backend->ip" }, + { "backend.down", BOOL, 0, "backend->down" }, + { "backend.timeout", TIME, 0, "backend->timeout" }, + { "backend.bandwidth", RATE, 0, "backend->bandwidth" }, + { "obj.exist", BOOL, 0, "obj->exists" }, + { "obj.ttl", TIME, 0, "obj->ttl" }, + { "obj.result", INT, 0, "obj->result" }, + { "obj.size", SIZE, 0, "obj->size" }, + { "obj.usage", INT, 0, "obj->usage" }, + { NULL, INT, 0, "NULL" } +}; + +static void Compound(struct tokenlist *tl); +static void Cond_0(struct tokenlist *tl); + +/*--------------------------------------------------------------------*/ + +static void +ErrToken(struct tokenlist *tl, struct token *t) +{ + + if (t->tok == EOI) + sbuf_printf(tl->sb, "end of input"); + else + sbuf_printf(tl->sb, "'%*.*s'", t->e - t->b, t->e - t->b, t->b); +} + +static void +_ErrInternal(struct tokenlist *tl, const char *func, unsigned line) +{ + + sbuf_printf(tl->sb, "VCL compiler internal error at %s():%u\n", + func, line); + tl->err = 1; +} + +#define ErrInternal(tl) _ErrInternal(tl, __func__, __LINE__) + +static void +ErrWhere(struct tokenlist *tl, struct token *t) +{ + unsigned lin, pos, x, y; + const char *p, *l; + + lin = 1; + pos = 0; + for (l = p = tl->b; p < t->b; p++) { + if (*p == '\n') { + lin++; + pos = 0; + l = p + 1; + } else if (*p == '\t') { + pos &= ~7; + pos += 8; + } else + pos++; + } + sbuf_printf(tl->sb, "Line %d Pos %d\n", lin, pos); + x = y = 0; + for (p = l; p < tl->e && *p != '\n'; p++) { + if (*p == '\t') { + y &= ~7; + y += 8; + while (x < y) { + sbuf_bcat(tl->sb, " ", 1); + x++; + } + } else { + x++; + y++; + sbuf_bcat(tl->sb, p, 1); + } + } + sbuf_cat(tl->sb, "\n"); + x = y = 0; + for (p = l; p < tl->e && *p != '\n'; p++) { + if (p >= t->b && p < t->e) { + sbuf_bcat(tl->sb, "#", 1); + x++; + y++; + continue; + } + if (*p == '\t') { + y &= ~7; + y += 8; + } else + y++; + while (x < y) { + sbuf_bcat(tl->sb, "-", 1); + x++; + } + } + sbuf_cat(tl->sb, "\n"); + tl->err = 1; +} + +/*--------------------------------------------------------------------*/ + +static void +NextToken(struct tokenlist *tl) +{ + tl->t = TAILQ_NEXT(tl->t, list); + if (tl->t == NULL) { + sbuf_printf(tl->sb, + "Ran out of input, something is missing or" + " maybe unbalanced (...) or {...}\n"); + tl->err = 1; + return; + } +} + +static void +_Expect(struct tokenlist *tl, unsigned tok, int line) +{ + if (tl->t->tok == tok) + return; + sbuf_printf(tl->sb, "Expected %s got ", tnames[tok]); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, "\n(program line %u), at\n", line); + ErrWhere(tl, tl->t); +} + +#define Expect(a, b) _Expect(a, b, __LINE__) +#define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0) + +#define I(tl) do { \ + fprintf(tl->fc, "/* %-11s */ ", __func__); \ + fprintf(tl->fc, "%*.*s", tl->indent, tl->indent, ""); \ +} while (0) + +#define L(tl, foo) do { \ + tl->indent += INDENT; \ + foo; \ + tl->indent -= INDENT; \ +} while (0) + +#define C(tl, sep) do { \ + I(tl); \ + fprintf(tl->fc, "VCL_count(%u)%s\n", ++tl->cnt, sep); \ + tl->t->cnt = tl->cnt; \ +} while (0) + +/*-------------------------------------------------------------------- + * Compare ID token to string, return true of match + */ + +static int +IdIs(struct token *t, const char *p) +{ + const char *q; + + assert(t->tok == ID); + for (q = t->b; q < t->e && *p != '\0'; p++, q++) + if (*q != *p) + return (0); + if (q != t->e || *p != '\0') + return (0); + return (1); +} + +/*-------------------------------------------------------------------- + * Keep track of definitions and references + */ + +static struct ref * +FindRef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + struct ref *r; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->type != type) + continue; + if (r->name->e - r->name->b != t->e - t->b) + continue; + if (memcmp(t->b, r->name->b, t->e - t->b)) + continue; + return (r); + } + r = calloc(sizeof *r, 1); + assert(r != NULL); + r->name = t; + r->type = type; + TAILQ_INSERT_TAIL(&tl->refs, r, list); + return (r); +} + +static void +AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + + FindRef(tl, t, type)->refcnt++; +} + +static void +AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + + FindRef(tl, t, type)->defcnt++; +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of time, return seconds. + */ + +static double +TimeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (IdIs(tl->t, "ms")) + sc = 1e-3; + else if (IdIs(tl->t, "s")) + sc = 1.0; + else if (IdIs(tl->t, "m")) + sc = 60.0; + else if (IdIs(tl->t, "h")) + sc = 60.0 * 60.0; + else if (IdIs(tl->t, "d")) + sc = 60.0 * 60.0 * 24.0; + else { + sbuf_printf(tl->sb, "Unknown time unit "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n"); + ErrWhere(tl, tl->t); + return (1.0); + } + NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of size, return bytes. + */ + +static double +SizeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (IdIs(tl->t, "b")) + sc = 1.0; + else if (IdIs(tl->t, "kb")) + sc = 1024.0; + else if (IdIs(tl->t, "mb") || IdIs(tl->t, "Mb")) + sc = 1024.0 * 1024.0; + else if (IdIs(tl->t, "gb") || IdIs(tl->t, "Gb")) + sc = 1024.0 * 1024.0 * 1024.0; + else { + sbuf_printf(tl->sb, "Unknown size unit "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n"); + ErrWhere(tl, tl->t); + return (1.0); + } + NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of rate as { space '/' time } + */ + +static double +RateUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + sc = SizeUnit(tl); + Expect(tl, '/'); + NextToken(tl); + sc /= TimeUnit(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM } to unsigned value + */ + +static unsigned +UintVal(struct tokenlist *tl) +{ + unsigned d = 0; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += digittoint(*p); + } + NextToken(tl); + return (d); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value + */ + +static double +DoubleVal(struct tokenlist *tl) +{ + double d = 0.0, e = 0.1; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += digittoint(*p); + } + NextToken(tl); + if (tl->t->tok != '.') + return (d); + NextToken(tl); + if (tl->t->tok != CNUM) + return (d); + for (p = tl->t->b; p < tl->t->e; p++) { + d += digittoint(*p) * e; + e *= 0.1; + } + NextToken(tl); + return (d); +} + +/*--------------------------------------------------------------------*/ + +static unsigned +IpVal(struct tokenlist *tl) +{ + unsigned u, v; + struct token *t; + + t = tl->t; + u = UintVal(tl); + if (u < 256) { + v = u << 24; + Expect(tl, '.'); + NextToken(tl); + t = tl->t; + u = UintVal(tl); + if (u < 256) { + v |= u << 16; + Expect(tl, '.'); + NextToken(tl); + t = tl->t; + u = UintVal(tl); + if (u < 256) { + v |= u << 8; + Expect(tl, '.'); + NextToken(tl); + t = tl->t; + u = UintVal(tl); + if (u < 256) { + v |= u; + return (v); + } + } + } + } + sbuf_printf(tl->sb, "Illegal octet in IP number\n"); + ErrWhere(tl, t); + return (0); +} + +/*--------------------------------------------------------------------*/ + +static struct var * +FindVar(struct tokenlist *tl, struct token *t) +{ + struct var *v; + + for (v = vars; v->name != NULL; v++) { + if (t->e - t->b != v->len) + continue; + if (!memcmp(t->b, v->name, v->len)) + return (v); + } + sbuf_printf(tl->sb, "Unknown variable "); + ErrToken(tl, t); + sbuf_cat(tl->sb, "\nAt: "); + ErrWhere(tl, t); + return (NULL); +} + + +/*--------------------------------------------------------------------*/ + +static void +TimeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = TimeUnit(tl); + fprintf(tl->fc, "(%g * %g)", v, sc); +} + +static void +SizeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = SizeUnit(tl); + fprintf(tl->fc, "(%g * %g)", v, sc); +} + +static void +RateVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = RateUnit(tl); + fprintf(tl->fc, "(%g * %g)", v, sc); +} + +/*--------------------------------------------------------------------*/ + +static void +Cond_Ip(struct var *vp, struct tokenlist *tl) +{ + unsigned u; + + switch (tl->t->tok) { + case '~': + NextToken(tl); + ExpectErr(tl, ID); + I(tl); + AddRef(tl, tl->t, R_ACL); + fprintf(tl->fc, "ip_match(%s, acl_%*.*s)\n", + vp->cname, + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + case T_EQ: + case T_NEQ: + I(tl); + fprintf(tl->fc, "%s %*.*s ", + vp->cname, + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + u = IpVal(tl); + fprintf(tl->fc, "%uU /* %u.%u.%u.%u */\n", u, + (u >> 24) & 0xff, (u >> 16) & 0xff, + (u >> 8) & 0xff, (u) & 0xff); + break; + default: + sbuf_printf(tl->sb, "Illegal condition "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, " on IP number variable\n"); + sbuf_printf(tl->sb, " only '==', '!=' and '~' are legal\n"); + ErrWhere(tl, tl->t); + break; + } +} + +static void +Cond_String(struct var *vp __unused, struct tokenlist *tl) +{ + + switch (tl->t->tok) { + case '~': + I(tl); fprintf(tl->fc, "string_match(%s, ", vp->cname); + NextToken(tl); + ExpectErr(tl, CSTR); + fprintf(tl->fc, "%*.*s)\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + default: + sbuf_printf(tl->sb, "Illegal condition "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, " on string variable\n"); + sbuf_printf(tl->sb, " only '~' is legal\n"); + ErrWhere(tl, tl->t); + break; + } +} + +static void +Cond_Int(struct var *vp, struct tokenlist *tl) +{ + + I(tl); + fprintf(tl->fc, "%s ", vp->cname); + switch (tl->t->tok) { + case T_EQ: + case T_NEQ: + case T_LEQ: + case T_GEQ: + case '>': + case '<': + fprintf(tl->fc, "%*.*s ", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + switch(vp->fmt) { + case TIME: + TimeVal(tl); + break; + case INT: + ExpectErr(tl, CNUM); + fprintf(tl->fc, "%*.*s ", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + case SIZE: + SizeVal(tl); + break; + default: + sbuf_printf(tl->sb, + "No conditions available for variable '%s'\n", + vp->name); + ErrWhere(tl, tl->t); + return; + } + fprintf(tl->fc, "\n"); + break; + default: + sbuf_printf(tl->sb, "Illegal condition "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, " on integer variable\n"); + sbuf_printf(tl->sb, + " only '==', '!=', '<', '>', '<=' and '>=' are legal\n"); + ErrWhere(tl, tl->t); + break; + } +} + +static void +Cond_Bool(struct var *vp, struct tokenlist *tl) +{ + + I(tl); + fprintf(tl->fc, "%s\n", vp->cname); +} + +static void +Cond_2(struct tokenlist *tl) +{ + struct var *vp; + + C(tl, ","); + I(tl); + if (tl->t->tok == '!') { + fprintf(tl->fc, "!"); + NextToken(tl); + } + fprintf(tl->fc, "(\n"); + if (tl->t->tok == '(') { + NextToken(tl); + Cond_0(tl); + ExpectErr(tl, ')'); + NextToken(tl); + } else if (tl->t->tok == VAR) { + vp = FindVar(tl, tl->t); + ERRCHK(tl); + assert(vp != NULL); + NextToken(tl); + switch (vp->fmt) { + case INT: L(tl, Cond_Int(vp, tl)); break; + case SIZE: L(tl, Cond_Int(vp, tl)); break; + case BOOL: L(tl, Cond_Bool(vp, tl)); break; + case IP: L(tl, Cond_Ip(vp, tl)); break; + case STRING: L(tl, Cond_String(vp, tl)); break; + case TIME: L(tl, Cond_Int(vp, tl)); break; + /* XXX backend == */ + default: + sbuf_printf(tl->sb, + "Variable '%s'" + " has no conditions that can be checked\n", + vp->name); + ErrWhere(tl, tl->t); + return; + } + } else { + sbuf_printf(tl->sb, + "Syntax error in condition, expected '(', '!' or" + " variable name, found "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, "\n"); + ErrWhere(tl, tl->t); + return; + } + I(tl); + fprintf(tl->fc, ")\n"); +} + +static void +Cond_1(struct tokenlist *tl) +{ + + I(tl); fprintf(tl->fc, "(\n"); + L(tl, Cond_2(tl)); + while (tl->t->tok == T_CAND) { + NextToken(tl); + I(tl); fprintf(tl->fc, ") && (\n"); + L(tl, Cond_2(tl)); + } + I(tl); fprintf(tl->fc, ")\n"); +} + +static void +Cond_0(struct tokenlist *tl) +{ + + I(tl); fprintf(tl->fc, "(\n"); + L(tl, Cond_1(tl)); + while (tl->t->tok == T_COR) { + NextToken(tl); + I(tl); fprintf(tl->fc, ") || (\n"); + L(tl, Cond_1(tl)); + } + I(tl); fprintf(tl->fc, ")\n"); +} + +static void +Conditional(struct tokenlist *tl) +{ + + ExpectErr(tl, '('); + NextToken(tl); + I(tl); fprintf(tl->fc, "(\n"); + L(tl, Cond_0(tl)); + ERRCHK(tl); + I(tl); fprintf(tl->fc, ")\n"); + ExpectErr(tl, ')'); + NextToken(tl); +} + +/*--------------------------------------------------------------------*/ + +static void +IfStmt(struct tokenlist *tl) +{ + + ExpectErr(tl, T_IF); + I(tl); fprintf(tl->fc, "if \n"); + NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + while (1) { + switch (tl->t->tok) { + case T_ELSE: + NextToken(tl); + if (tl->t->tok != T_IF) { + I(tl); fprintf(tl->fc, "else \n"); + L(tl, Compound(tl)); + ERRCHK(tl); + return; + } + /* FALLTHROUGH */ + case T_ELSEIF: + case T_ELSIF: + I(tl); fprintf(tl->fc, "else if \n"); + NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + break; + default: + return; + } + } +} + +/*--------------------------------------------------------------------*/ + +static void +Action(struct tokenlist *tl) +{ + unsigned a, u; + struct var *vp; + struct token *at; + + at = tl->t; + NextToken(tl); + switch (at->tok) { + case T_NO_NEW_CACHE: + I(tl); + fprintf(tl->fc, "VCL_no_new_cache();\n"); + return; + case T_NO_CACHE: + I(tl); + fprintf(tl->fc, "VCL_no_cache();\n"); + return; + case T_FINISH: + I(tl); + fprintf(tl->fc, "return;\n"); + return; + case T_FETCH: + I(tl); + fprintf(tl->fc, "VCL_fetch();\n"); + return; + case T_ERROR: + a = UintVal(tl); + I(tl); + fprintf(tl->fc, "VCL_error(%u, ", a); + if (tl->t->tok == CSTR) { + fprintf(tl->fc, "%*.*s);\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + } else + fprintf(tl->fc, "(const char *)0);\n"); + return; + case T_SWITCH_CONFIG: + ExpectErr(tl, ID); + I(tl); + fprintf(tl->fc, "VCL_switch_config(\"%*.*s\");\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + return; + case T_CALL: + ExpectErr(tl, ID); + AddRef(tl, tl->t, R_FUNC); + I(tl); + fprintf(tl->fc, "VCL_function_%*.*s(VCL_PASS_ARGS);\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + /* XXX: check if function finished request */ + NextToken(tl); + return; + case T_REWRITE: + ExpectErr(tl, CSTR); + I(tl); + fprintf(tl->fc, "VCL_rewrite(%*.*s", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + ExpectErr(tl, CSTR); + fprintf(tl->fc, ", %*.*s);\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + return; + case T_SET: + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t); + ERRCHK(tl); + assert(vp != NULL); + I(tl); + fprintf(tl->fc, "%s ", vp->cname); + NextToken(tl); + switch (vp->fmt) { + case INT: + case SIZE: + case RATE: + case TIME: + case FLOAT: + fprintf(tl->fc, "%*.*s ", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + a = tl->t->tok; + NextToken(tl); + if (a == T_MUL || a == T_DIV) + fprintf(tl->fc, "%g", DoubleVal(tl)); + else if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else + fprintf(tl->fc, "%g", DoubleVal(tl)); + fprintf(tl->fc, ";\n"); + break; + case IP: + if (tl->t->tok == '=') { + NextToken(tl); + u = IpVal(tl); + fprintf(tl->fc, "= %uU; /* %u.%u.%u.%u */\n", + u, + (u >> 24) & 0xff, + (u >> 16) & 0xff, + (u >> 8) & 0xff, + u & 0xff); + break; + } + sbuf_printf(tl->sb, "Illegal assignment operator "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, + " only '=' is legal for IP numbers\n"); + ErrWhere(tl, tl->t); + return; + case BACKEND: + if (tl->t->tok == '=') { + NextToken(tl); + fprintf(tl->fc, "= &VCL_backend_%*.*s;\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + } + sbuf_printf(tl->sb, "Illegal assignment operator "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, + " only '=' is legal for backend\n"); + ErrWhere(tl, tl->t); + return; + default: + sbuf_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + ErrWhere(tl, tl->t); + return; + } + return; + default: + sbuf_printf(tl->sb, "Expected action, 'if' or '}'\n"); + ErrWhere(tl, at); + return; + } +} + +/*--------------------------------------------------------------------*/ + +static void +Acl(struct tokenlist *tl) +{ + unsigned u, m; + + NextToken(tl); + + ExpectErr(tl, ID); + AddDef(tl, tl->t, R_ACL); + fprintf(tl->fh, "static struct vcl_acl acl_%*.*s[];\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + I(tl); + fprintf(tl->fc, "static struct vcl_acl acl_%*.*s[] = {\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + + tl->indent += INDENT; + + ExpectErr(tl, '{'); + NextToken(tl); + + while (tl->t->tok == CNUM) { + u = IpVal(tl); + if (tl->t->tok == '/') { + NextToken(tl); + ExpectErr(tl, CNUM); + m = UintVal(tl); + } else + m = 32; + ExpectErr(tl, ';'); + NextToken(tl); + I(tl); + fprintf(tl->fc, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n", + u, m, + (u >> 24) & 0xff, (u >> 16) & 0xff, + (u >> 8) & 0xff, (u) & 0xff, m); + } + ExpectErr(tl, '}'); + I(tl); + fprintf(tl->fc, "{ %11uU, %3uU }\n", 0, 0); + + tl->indent -= INDENT; + + I(tl); + fprintf(tl->fc, "};\n\n"); + NextToken(tl); +} + +/*--------------------------------------------------------------------*/ + +static void +Compound(struct tokenlist *tl) +{ + + ExpectErr(tl, '{'); + I(tl); fprintf(tl->fc, "{\n"); + tl->indent += INDENT; + C(tl, ";"); + NextToken(tl); + while (1) { + ERRCHK(tl); + switch (tl->t->tok) { + case '{': + Compound(tl); + break; + case T_IF: + IfStmt(tl); + break; + case '}': + NextToken(tl); + tl->indent -= INDENT; + I(tl); fprintf(tl->fc, "}\n"); + return; + case EOI: + sbuf_printf(tl->sb, + "End of input while in compound statement\n"); + tl->err = 1; + return; + default: + Action(tl); + ERRCHK(tl); + ExpectErr(tl, ';'); + NextToken(tl); + break; + } + } +} + +/*--------------------------------------------------------------------*/ + +static void +Backend(struct tokenlist *tl) +{ + + NextToken(tl); + ExpectErr(tl, ID); + AddDef(tl, tl->t, R_BACKEND); + I(tl); + fprintf(tl->fh, "static struct backend VCL_backend_%*.*s;\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + fprintf(tl->fc, "static struct backend VCL_backend_%*.*s;\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + fprintf(tl->fc, "static void\n"); + I(tl); + fprintf(tl->fc, "VCL_init_backend_%*.*s (struct backend *backend)\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + L(tl, Compound(tl)); + fprintf(tl->fc, "\n"); +} + +/*--------------------------------------------------------------------*/ + +static void +Function(struct tokenlist *tl) +{ + + NextToken(tl); + ExpectErr(tl, ID); + AddDef(tl, tl->t, R_FUNC); + fprintf(tl->fh, "static void VCL_function_%*.*s (VCL_FARGS);\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + I(tl); + fprintf(tl->fc, "static void\n"); + I(tl); + fprintf(tl->fc, "VCL_function_%*.*s (VCL_FARGS)\n", + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + L(tl, Compound(tl)); + fprintf(tl->fc, "\n"); +} + +/*-------------------------------------------------------------------- + * Top level of parser, recognize: + * Function definitions + * Backend definitions + * End of input + */ + +static void +Parse(struct tokenlist *tl) +{ + + while (tl->t->tok != EOI) { + ERRCHK(tl); + switch (tl->t->tok) { + case T_ACL: + Acl(tl); + break; + case T_SUB: + Function(tl); + break; + case T_BACKEND: + Backend(tl); + break; + case EOI: + break; + default: + sbuf_printf(tl->sb, + "Expected 'acl', 'sub' or 'backend', found "); + ErrToken(tl, tl->t); + sbuf_printf(tl->sb, " at\n"); + ErrWhere(tl, tl->t); + return; + } + } +} + +/*-------------------------------------------------------------------- + * Add a token to the token list. + */ + +static void +AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e) +{ + struct token *t; + + t = calloc(sizeof *t, 1); + assert(t != NULL); + t->tok = tok; + t->b = b; + t->e = e; + TAILQ_INSERT_TAIL(&tl->tokens, t, list); + tl->t = t; +} + +/*-------------------------------------------------------------------- + * Lexical analysis and token generation + */ + +static void +Lexer(struct tokenlist *tl, const char *b, const char *e) +{ + const char *p, *q; + unsigned u; + + for (p = b; p < e; ) { + + /* Skip any whitespace */ + if (isspace(*p)) { + p++; + continue; + } + + /* Skip '#.*\n' comments */ + if (*p == '#') { + while (p < e && *p != '\n') + p++; + continue; + } + + /* Skip C-style comments */ + if (*p == '/' && p[1] == '*') { + p += 2; + for (p += 2; p < e; p++) { + if (*p == '*' && p[1] == '/') { + p += 2; + break; + } + } + continue; + } + + /* Match for the fixed tokens (see token.tcl) */ + u = fixed_token(p, &q); + if (u != 0) { + AddToken(tl, u, p, q); + p = q; + continue; + } + + /* Match strings, with \\ and \" escapes */ + if (*p == '"') { + for (q = p + 1; q < e; q++) { + if (*q == '\\' && q[1] == '\\') + q++; + else if (*q == '\\' && q[1] == '"') + q++; + else if (*q == '"') { + q++; + break; + } + } + AddToken(tl, CSTR, p, q); + p = q; + continue; + } + + /* Match Identifiers */ + if (isident1(*p)) { + for (q = p; q < e; q++) + if (!isident(*q)) + break; + if (isvar(*q)) { + for (; q < e; q++) + if (!isvar(*q)) + break; + AddToken(tl, VAR, p, q); + } else { + AddToken(tl, ID, p, q); + } + p = q; + continue; + } + + /* Match numbers { [0-9]+ } */ + if (isdigit(*p)) { + for (q = p; q < e; q++) + if (!isdigit(*q)) + break; + AddToken(tl, CNUM, p, q); + p = q; + continue; + } + AddToken(tl, EOI, p, p + 1); + sbuf_printf(tl->sb, "Syntax error at\n"); + ErrWhere(tl, tl->t); + return; + } + /* Add End Of Input token */ + AddToken(tl, EOI, p, p); +} + +/*--------------------------------------------------------------------*/ + +static void +CheckRefs(struct tokenlist *tl) +{ + struct ref *r; + const char *bug; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->defcnt == 0) + bug = "Undefined "; + else if (r->refcnt == 0) + bug = "Unreferenced "; + else + continue; + switch(r->type) { + case R_FUNC: + sbuf_printf(tl->sb, "%s function ", bug); + break; + case R_ACL: + sbuf_printf(tl->sb, "%s acl ", bug); + break; + case R_BACKEND: + sbuf_printf(tl->sb, "%s backend ", bug); + break; + default: + ErrInternal(tl); + sbuf_printf(tl->sb, "Ref "); + ErrToken(tl, r->name); + sbuf_printf(tl->sb, " has unknown type %d\n", + r->type); + return; + } + ErrToken(tl, r->name); + sbuf_cat(tl->sb, ", first mention is\n"); + ErrWhere(tl, r->name); + return; + } +} + +/*--------------------------------------------------------------------*/ + +static void +LocTable(struct tokenlist *tl) +{ + struct token *t; + unsigned lin, pos; + const char *p; + + fprintf(tl->fh, "static struct vcl_ref VCL_ref[%u];\n", tl->cnt + 1); + fprintf(tl->fc, "static struct vcl_ref VCL_ref[%u] = {\n", tl->cnt + 1); + lin = 1; + pos = 0; + p = tl->b; + TAILQ_FOREACH(t, &tl->tokens, list) { + if (t->cnt == 0) + continue; + for (;p < t->b; p++) { + if (*p == '\n') { + lin++; + pos = 0; + } else if (*p == '\t') { + pos &= ~7; + pos += 8; + } else + pos++; + + } + fprintf(tl->fc, + "%*.*s[%3u] = { %4u, %3u, 0, \"%*.*s\" },\n", + INDENT, INDENT, "", + t->cnt, lin, pos + 1, + t->e - t->b, + t->e - t->b, t->b); + } + fprintf(tl->fc, "};\n"); +} + + +/*--------------------------------------------------------------------*/ + +static void +Compile(struct sbuf *sb, const char *b, const char *e) +{ + struct tokenlist tokens; + + memset(&tokens, 0, sizeof tokens); + TAILQ_INIT(&tokens.tokens); + TAILQ_INIT(&tokens.refs); + tokens.sb = sb; + + tokens.fc = fopen("_.c", "w"); + assert(tokens.fc != NULL); + + tokens.fh = fopen("_.h", "w"); + assert(tokens.fh != NULL); + + fprintf(tokens.fc, "#include \"vcl_lang.h\"\n"); + fprintf(tokens.fc, "#include \"_.h\"\n"); + tokens.b = b; + tokens.e = e; + Lexer(&tokens, b, e); + ERRCHK(&tokens); + tokens.t = TAILQ_FIRST(&tokens.tokens); + Parse(&tokens); + ERRCHK(&tokens); + CheckRefs(&tokens); + ERRCHK(&tokens); + LocTable(&tokens); +} + +/*--------------------------------------------------------------------*/ + +#include + +#define MYSPACE (128 * 1024) + +int +main(int argc, char **argv) +{ + char *p; + size_t z; + FILE *fi; + struct sbuf *sb; + + setbuf(stdout, NULL); + { + struct var *v; + + for (v = vars; v->name != NULL; v++) { + v->len = strlen(v->name); + } + } + if (argc != 2) + err(1, "Usage: %s file", argv[0]); + fi = fopen(argv[1], "r"); + if (fi == NULL) + err(1, "Cannot open %s", argv[1]); + p = malloc(MYSPACE); + assert(p != NULL); + + z = fread(p, 1, MYSPACE - 1, fi); + if (z == 0) + err(1, "Nothing read from %s", argv[1]); + p[z] = '\0'; + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + Compile(sb, p, p + z); + sbuf_finish(sb); + if (sbuf_len(sb)) + printf("<%s>\n", sbuf_data(sb)); + return (0); +} Added: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,365 @@ +/* + * NB: This file is machine generated, DO NOT EDIT! + * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand + */ + +#include "vcl_priv.h" + +unsigned +fixed_token(const char *p, const char **q) +{ + + switch (p[0]) { + case '!': + if (p[0] == '!' && p[1] == '=') { + *q = p + 2; + return (T_NEQ); + } + if (p[0] == '!') { + *q = p + 1; + return ('!'); + } + return (0); + case '%': + if (p[0] == '%') { + *q = p + 1; + return ('%'); + } + return (0); + case '&': + if (p[0] == '&' && p[1] == '&') { + *q = p + 2; + return (T_CAND); + } + if (p[0] == '&') { + *q = p + 1; + return ('&'); + } + return (0); + case '(': + if (p[0] == '(') { + *q = p + 1; + return ('('); + } + return (0); + case ')': + if (p[0] == ')') { + *q = p + 1; + return (')'); + } + return (0); + case '*': + if (p[0] == '*' && p[1] == '=') { + *q = p + 2; + return (T_MUL); + } + if (p[0] == '*') { + *q = p + 1; + return ('*'); + } + return (0); + case '+': + if (p[0] == '+' && p[1] == '=') { + *q = p + 2; + return (T_INCR); + } + if (p[0] == '+' && p[1] == '+') { + *q = p + 2; + return (T_INC); + } + if (p[0] == '+') { + *q = p + 1; + return ('+'); + } + return (0); + case ',': + if (p[0] == ',') { + *q = p + 1; + return (','); + } + return (0); + case '-': + if (p[0] == '-' && p[1] == '-') { + *q = p + 2; + return (T_DEC); + } + if (p[0] == '-') { + *q = p + 1; + return ('-'); + } + return (0); + case '.': + if (p[0] == '.') { + *q = p + 1; + return ('.'); + } + return (0); + case '/': + if (p[0] == '/' && p[1] == '=') { + *q = p + 2; + return (T_DECR); + } + if (p[0] == '/' && p[1] == '=') { + *q = p + 2; + return (T_DIV); + } + if (p[0] == '/') { + *q = p + 1; + return ('/'); + } + return (0); + case ';': + if (p[0] == ';') { + *q = p + 1; + return (';'); + } + return (0); + case '<': + if (p[0] == '<' && p[1] == '=') { + *q = p + 2; + return (T_LEQ); + } + if (p[0] == '<' && p[1] == '<') { + *q = p + 2; + return (T_SHL); + } + if (p[0] == '<') { + *q = p + 1; + return ('<'); + } + return (0); + case '=': + if (p[0] == '=' && p[1] == '=') { + *q = p + 2; + return (T_EQ); + } + if (p[0] == '=') { + *q = p + 1; + return ('='); + } + return (0); + case '>': + if (p[0] == '>' && p[1] == '>') { + *q = p + 2; + return (T_SHR); + } + if (p[0] == '>' && p[1] == '=') { + *q = p + 2; + return (T_GEQ); + } + if (p[0] == '>') { + *q = p + 1; + return ('>'); + } + return (0); + case 'a': + if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l' + && !isvar(p[3])) { + *q = p + 3; + return (T_ACL); + } + return (0); + case 'b': + if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' && + p[3] == 'k' && p[4] == 'e' && p[5] == 'n' && + p[6] == 'd' && !isvar(p[7])) { + *q = p + 7; + return (T_BACKEND); + } + return (0); + case 'c': + if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' && + p[3] == 'l' && !isvar(p[4])) { + *q = p + 4; + return (T_CALL); + } + return (0); + case 'e': + if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' && + p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) { + *q = p + 5; + return (T_ERROR); + } + if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && + p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) { + *q = p + 5; + return (T_ELSIF); + } + if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && + p[3] == 'e' && p[4] == 'i' && p[5] == 'f' + && !isvar(p[6])) { + *q = p + 6; + return (T_ELSEIF); + } + if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && + p[3] == 'e' && !isvar(p[4])) { + *q = p + 4; + return (T_ELSE); + } + return (0); + case 'f': + if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' && + p[3] == 'c' && !isvar(p[4])) { + *q = p + 4; + return (T_FUNC); + } + if (p[0] == 'f' && p[1] == 'i' && p[2] == 'n' && + p[3] == 'i' && p[4] == 's' && p[5] == 'h' + && !isvar(p[6])) { + *q = p + 6; + return (T_FINISH); + } + if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' && + p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) { + *q = p + 5; + return (T_FETCH); + } + return (0); + case 'i': + if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) { + *q = p + 2; + return (T_IF); + } + return (0); + case 'n': + if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && + p[3] == 'n' && p[4] == 'e' && p[5] == 'w' && + p[6] == '_' && p[7] == 'c' && p[8] == 'a' && + p[9] == 'c' && p[10] == 'h' && p[11] == 'e' + && !isvar(p[12])) { + *q = p + 12; + return (T_NO_NEW_CACHE); + } + if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && + p[3] == 'c' && p[4] == 'a' && p[5] == 'c' && + p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) { + *q = p + 8; + return (T_NO_CACHE); + } + return (0); + case 'p': + if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' && + p[3] == 'c' && !isvar(p[4])) { + *q = p + 4; + return (T_PROC); + } + return (0); + case 'r': + if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' && + p[3] == 'r' && p[4] == 'i' && p[5] == 't' && + p[6] == 'e' && !isvar(p[7])) { + *q = p + 7; + return (T_REWRITE); + } + return (0); + case 's': + if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' && + p[3] == 't' && p[4] == 'c' && p[5] == 'h' && + p[6] == '_' && p[7] == 'c' && p[8] == 'o' && + p[9] == 'n' && p[10] == 'f' && p[11] == 'i' && + p[12] == 'g' && !isvar(p[13])) { + *q = p + 13; + return (T_SWITCH_CONFIG); + } + if (p[0] == 's' && p[1] == 'u' && p[2] == 'b' + && !isvar(p[3])) { + *q = p + 3; + return (T_SUB); + } + if (p[0] == 's' && p[1] == 'e' && p[2] == 't' + && !isvar(p[3])) { + *q = p + 3; + return (T_SET); + } + return (0); + case '{': + if (p[0] == '{') { + *q = p + 1; + return ('{'); + } + return (0); + case '|': + if (p[0] == '|' && p[1] == '|') { + *q = p + 2; + return (T_COR); + } + if (p[0] == '|') { + *q = p + 1; + return ('|'); + } + return (0); + case '}': + if (p[0] == '}') { + *q = p + 1; + return ('}'); + } + return (0); + case '~': + if (p[0] == '~') { + *q = p + 1; + return ('~'); + } + return (0); + default: + return (0); + } +} + +const char *tnames[256] = { + ['!'] = "'!'" /* t2 '!' T! */, + ['%'] = "'%'" /* t2 '%' T% */, + ['&'] = "'&'" /* t2 '&' T& */, + ['('] = "'('" /* t2 '(' T( */, + [')'] = "')'" /* t2 ')' T) */, + ['*'] = "'*'" /* t2 '*' T* */, + ['+'] = "'+'" /* t2 '+' T+ */, + [','] = "','" /* t2 ',' T, */, + ['-'] = "'-'" /* t2 '-' T- */, + ['.'] = "'.'" /* t2 '.' T. */, + ['/'] = "'/'" /* t2 '/' T/ */, + ['<'] = "'<'" /* t2 '<' T< */, + ['='] = "'='" /* t2 '=' T= */, + ['>'] = "'>'" /* t2 '>' T> */, + ['{'] = "'{'" /* t2 '\{' T\{ */, + ['}'] = "'}'" /* t2 '\}' T\} */, + ['|'] = "'|'" /* t2 '|' T| */, + ['~'] = "'~'" /* t2 '~' T~ */, + [';'] = "';'" /* t2 {';'} {T;} */, + [CNUM] = "CNUM" /* t CNUM CNUM */, + [CSTR] = "CSTR" /* t CSTR CSTR */, + [EOI] = "EOI" /* t EOI EOI */, + [ID] = "ID" /* t ID ID */, + [T_ACL] = "acl" /* t T_ACL acl */, + [T_BACKEND] = "backend" /* t T_BACKEND backend */, + [T_CALL] = "call" /* t T_CALL call */, + [T_CAND] = "&&" /* t T_CAND && */, + [T_COR] = "||" /* t T_COR || */, + [T_DEC] = "--" /* t T_DEC -- */, + [T_DECR] = "/=" /* t T_DECR /= */, + [T_DIV] = "/=" /* t T_DIV /= */, + [T_ELSE] = "else" /* t T_ELSE else */, + [T_ELSEIF] = "elseif" /* t T_ELSEIF elseif */, + [T_ELSIF] = "elsif" /* t T_ELSIF elsif */, + [T_EQ] = "==" /* t T_EQ == */, + [T_ERROR] = "error" /* t T_ERROR error */, + [T_FETCH] = "fetch" /* t T_FETCH fetch */, + [T_FINISH] = "finish" /* t T_FINISH finish */, + [T_FUNC] = "func" /* t T_FUNC func */, + [T_GEQ] = ">=" /* t T_GEQ >= */, + [T_IF] = "if" /* t T_IF if */, + [T_INC] = "++" /* t T_INC ++ */, + [T_INCR] = "+=" /* t T_INCR += */, + [T_LEQ] = "<=" /* t T_LEQ <= */, + [T_MUL] = "*=" /* t T_MUL *= */, + [T_NEQ] = "!=" /* t T_NEQ != */, + [T_NO_CACHE] = "no_cache" /* t T_NO_CACHE no_cache */, + [T_NO_NEW_CACHE] = "no_new_cache" /* t T_NO_NEW_CACHE no_new_cache */, + [T_PROC] = "proc" /* t T_PROC proc */, + [T_REWRITE] = "rewrite" /* t T_REWRITE rewrite */, + [T_SET] = "set" /* t T_SET set */, + [T_SHL] = "<<" /* t T_SHL << */, + [T_SHR] = ">>" /* t T_SHR >> */, + [T_SUB] = "sub" /* t T_SUB sub */, + [T_SWITCH_CONFIG] = "switch_config" /* t T_SWITCH_CONFIG switch_config */, + [VAR] = "VAR" /* t VAR VAR */, +}; Added: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,171 @@ +#!/usr/local/bin/tclsh8.4 +# +# Generate a C source file to recognize a set of tokens for the +# Varnish + +set keywords { + if else elseif elsif + + func proc sub + + acl + + backend + + error + fetch + call + no_cache + no_new_cache + set + rewrite + finish + switch_config +} + +set magic { + {"++" INC} + {"--" DEC} + {"&&" CAND} + {"||" COR} + {"<=" LEQ} + {"==" EQ} + {"!=" NEQ} + {">=" GEQ} + {">>" SHR} + {"<<" SHL} + {"+=" INCR} + {"/=" DECR} + {"*=" MUL} + {"/=" DIV} +} + +set char {{}()*+-/%><=;!&.|~,} + +set extras {ID VAR CNUM CSTR EOI} + +set fo [open "vcl_fixed_token.c" w] + +puts $fo {/* + * NB: This file is machine generated, DO NOT EDIT! + * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand + */ +} + +set foh [open "vcl_token_defs.h" w] +puts $foh {/* + * NB: This file is machine generated, DO NOT EDIT! + * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand + */ +} + +puts $fo "#include \"vcl_priv.h\"" + +set tn 128 +puts $foh "#define LOW_TOKEN $tn" + +foreach k $keywords { + set t T_[string toupper $k] + lappend tokens [list $t $k] + puts $foh "#define $t $tn" + incr tn + lappend fixed [list $k $t 1] +} +foreach k $magic { + set t T_[string toupper [lindex $k 1]] + lappend tokens [list $t [lindex $k 0]] + puts $foh "#define $t $tn" + incr tn + lappend fixed [list [lindex $k 0] $t 0] +} +foreach k $extras { + set t [string toupper $k] + lappend tokens [list $t $t] + puts $foh "#define [string toupper $k] $tn" + incr tn +} +for {set i 0} {$i < [string length $char]} {incr i} { + set t [string index $char $i] + lappend token2 [list '$t' T$t] + lappend fixed [list "$t" '$t' 0] +} + +set tokens [lsort $tokens] +set token2 [lsort $token2] + +# We want to output in ascii order: create sorted first char list +foreach t $fixed { + set xx([string index [lindex $t 0] 0]) 1 +} +set seq [lsort [array names xx]] + +set ll 0 + +puts $fo { +unsigned +fixed_token(const char *p, const char **q)} +puts $fo "{" +puts $fo "" +puts $fo " switch (p\[0\]) {" + +foreach ch "$seq" { + # Now find all tokens starting with ch + set l "" + foreach t $fixed { + if {[string index [lindex $t 0] 0] == $ch} { + lappend l $t + } + } + # And do then in reverse order to match longest first + set l [lsort -index 0 -decreasing $l] + scan "$ch" "%c" cx + if {$cx != $ll} { + if {$ll} { + puts $fo " return (0);" + } + + puts $fo " case '$ch':" + set ll $cx + } + foreach tt $l { + set k [lindex $tt 0] + puts -nonewline $fo " if (" + for {set i 0} {$i < [string length $k]} {incr i} { + if {$i > 0} { + puts -nonewline $fo " && " + if {![expr $i % 3]} { + puts -nonewline $fo "\n\t\t " + } + } + puts -nonewline $fo "p\[$i\] == '[string index $k $i]'" + } + if {[lindex $tt 2]} { + if {![expr $i % 3]} { + puts -nonewline $fo "\n\t\t " + } + puts -nonewline $fo " && !isvar(p\[$i\])" + } + puts $fo ") {" + puts $fo " *q = p + [string length $k];" + puts $fo " return ([lindex $tt 1]);" + puts $fo " }" + } +} +puts $fo " return (0);" +puts $fo " default:" +puts $fo " return (0);" +puts $fo " }" +puts $fo "}" + +puts $fo "" +puts $fo "const char *tnames\[256\] = {" +foreach i $token2 { + puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 0]\" /* t2 $i */," +} +foreach i $tokens { + puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 1]\" /* t $i */," +} +puts $fo "};" + +close $foh +close $fo Property changes on: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl ___________________________________________________________________ Name: svn:executable + * Added: trunk/varnish-cache/lib/libvcl/vcl_lang.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_lang.h 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_lang.h 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,62 @@ +/* + * Stuff necessary to compile a VCL programs C code + */ + + +struct vcl_ref { + unsigned line; + unsigned pos; + unsigned count; + const char *token; +}; + +struct vcl_acl { + unsigned ip; + unsigned mask; +}; + +struct client { + unsigned ip; +}; + +struct req { + char *req; + char *useragent; + struct { + char *path; + char *host; + } url; + double ttlfactor; + struct backend *backend; +}; + +struct backend { + unsigned ip; + double responsetime; + double timeout; + double bandwidth; + int down; +}; + +struct obj { + int exists; + double ttl; + unsigned result; + unsigned size; + unsigned usage; +}; + +#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend +#define VCL_PASS_ARGS client, obj, req, backend + +void VCL_count(unsigned); +void VCL_no_cache(); +void VCL_no_new_cache(); +int ip_match(unsigned, struct vcl_acl *); +int string_match(const char *, const char *); +int VCL_rewrite(const char *, const char *); +int VCL_error(unsigned, const char *); +int VCL_fetch(void); +int VCL_switch_config(const char *); + + Added: trunk/varnish-cache/lib/libvcl/vcl_priv.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,12 @@ +/* + * Stuff shared between main.c and fixed_token.c + */ + +#include "vcl_token_defs.h" +#include + +#define isident1(c) (isalpha(c)) +#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_') +#define isvar(c) (isident(c) || (c) == '.') +unsigned fixed_token(const char *p, const char **q); +extern const char *tnames[256]; Added: trunk/varnish-cache/lib/libvcl/vcl_token_defs.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-03-02 10:32:59 UTC (rev 42) +++ trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-03-13 12:37:04 UTC (rev 43) @@ -0,0 +1,43 @@ +/* + * NB: This file is machine generated, DO NOT EDIT! + * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand + */ + +#define LOW_TOKEN 128 +#define T_IF 128 +#define T_ELSE 129 +#define T_ELSEIF 130 +#define T_ELSIF 131 +#define T_FUNC 132 +#define T_PROC 133 +#define T_SUB 134 +#define T_ACL 135 +#define T_BACKEND 136 +#define T_ERROR 137 +#define T_FETCH 138 +#define T_CALL 139 +#define T_NO_CACHE 140 +#define T_NO_NEW_CACHE 141 +#define T_SET 142 +#define T_REWRITE 143 +#define T_FINISH 144 +#define T_SWITCH_CONFIG 145 +#define T_INC 146 +#define T_DEC 147 +#define T_CAND 148 +#define T_COR 149 +#define T_LEQ 150 +#define T_EQ 151 +#define T_NEQ 152 +#define T_GEQ 153 +#define T_SHR 154 +#define T_SHL 155 +#define T_INCR 156 +#define T_DECR 157 +#define T_MUL 158 +#define T_DIV 159 +#define ID 160 +#define VAR 161 +#define CNUM 162 +#define CSTR 163 +#define EOI 164 From phk at projects.linpro.no Mon Mar 13 13:30:20 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 13 Mar 2006 14:30:20 +0100 (CET) Subject: r44 - trunk/varnish-cache Message-ID: <20060313133020.BBC261ED545@projects.linpro.no> Author: phk Date: 2006-03-13 14:30:20 +0100 (Mon, 13 Mar 2006) New Revision: 44 Modified: trunk/varnish-cache/autogen.sh Log: Pick up the gnu-autotools binary directory if we spot one. This makes life on FreeBSD somewhat easier. Modified: trunk/varnish-cache/autogen.sh =================================================================== --- trunk/varnish-cache/autogen.sh 2006-03-13 12:37:04 UTC (rev 43) +++ trunk/varnish-cache/autogen.sh 2006-03-13 13:30:20 UTC (rev 44) @@ -3,6 +3,11 @@ # $Id$ # +if [ -d /usr/local/gnu-autotools/bin ] ; then + PATH=${PATH}:/usr/local/gnu-autotools/bin + export PATH +fi + aclocal libtoolize --copy --force autoheader From des at projects.linpro.no Mon Mar 13 14:14:16 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Mon, 13 Mar 2006 15:14:16 +0100 (CET) Subject: r45 - in trunk/varnish-cache: . include lib lib/libsbuf Message-ID: <20060313141416.3C3C21ED563@projects.linpro.no> Author: des Date: 2006-03-13 15:14:16 +0100 (Mon, 13 Mar 2006) New Revision: 45 Added: trunk/varnish-cache/include/sbuf.h trunk/varnish-cache/lib/libsbuf/ trunk/varnish-cache/lib/libsbuf/Makefile.am trunk/varnish-cache/lib/libsbuf/sbuf.c Modified: trunk/varnish-cache/configure.ac trunk/varnish-cache/lib/Makefile.am Log: Add libsbuf, based on the latest sbuf code from FreeBSD-CURRENT. Modified: trunk/varnish-cache/configure.ac =================================================================== --- trunk/varnish-cache/configure.ac 2006-03-13 13:30:20 UTC (rev 44) +++ trunk/varnish-cache/configure.ac 2006-03-13 14:14:16 UTC (rev 45) @@ -65,6 +65,7 @@ Makefile include/Makefile lib/Makefile + lib/libsbuf/Makefile lib/libvarnish/Makefile lib/libvarnishapi/Makefile bin/Makefile Added: trunk/varnish-cache/include/sbuf.h =================================================================== --- trunk/varnish-cache/include/sbuf.h 2006-03-13 13:30:20 UTC (rev 44) +++ trunk/varnish-cache/include/sbuf.h 2006-03-13 14:14:16 UTC (rev 45) @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co?dan Sm?rgrav + * 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 + * in this position and unchanged. + * 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. + * + * $Id$ + * $FreeBSD: src/sys/sys/sbuf.h,v 1.14 2004/07/09 11:35:30 des Exp $ + */ + +#ifndef SBUF_H_INCLUDED +#define SBUF_H_INCLUDED + +/* + * Structure definition + */ +struct sbuf { + char *s_buf; /* storage buffer */ + void *s_unused; /* binary compatibility. */ + int s_size; /* size of storage buffer */ + int s_len; /* current length of string */ +#define SBUF_FIXEDLEN 0x00000000 /* fixed length buffer (default) */ +#define SBUF_AUTOEXTEND 0x00000001 /* automatically extend buffer */ +#define SBUF_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */ +#define SBUF_DYNAMIC 0x00010000 /* s_buf must be freed */ +#define SBUF_FINISHED 0x00020000 /* set by sbuf_finish() */ +#define SBUF_OVERFLOWED 0x00040000 /* sbuf overflowed */ +#define SBUF_DYNSTRUCT 0x00080000 /* sbuf must be freed */ + int s_flags; /* flags */ +}; + +__BEGIN_DECLS +/* + * API functions + */ +struct sbuf *sbuf_new(struct sbuf *, char *, int, int); +void sbuf_clear(struct sbuf *); +int sbuf_setpos(struct sbuf *, int); +int sbuf_bcat(struct sbuf *, const void *, size_t); +int sbuf_bcpy(struct sbuf *, const void *, size_t); +int sbuf_cat(struct sbuf *, const char *); +int sbuf_cpy(struct sbuf *, const char *); +int sbuf_printf(struct sbuf *, const char *, ...) /* __printflike(2, 3) */; +#ifdef va_start +int sbuf_vprintf(struct sbuf *, const char *, va_list) /* __printflike(2, 0) */; +#endif +int sbuf_putc(struct sbuf *, int); +int sbuf_trim(struct sbuf *); +int sbuf_overflowed(struct sbuf *); +void sbuf_finish(struct sbuf *); +char *sbuf_data(struct sbuf *); +int sbuf_len(struct sbuf *); +int sbuf_done(struct sbuf *); +void sbuf_delete(struct sbuf *); +__END_DECLS + +#endif Property changes on: trunk/varnish-cache/include/sbuf.h ___________________________________________________________________ Name: svn:keyword + Id Modified: trunk/varnish-cache/lib/Makefile.am =================================================================== --- trunk/varnish-cache/lib/Makefile.am 2006-03-13 13:30:20 UTC (rev 44) +++ trunk/varnish-cache/lib/Makefile.am 2006-03-13 14:14:16 UTC (rev 45) @@ -1,6 +1,7 @@ # $Id$ SUBDIRS = \ + libsbuf \ libvarnish \ libvarnishapi \ libvcl Property changes on: trunk/varnish-cache/lib/libsbuf ___________________________________________________________________ Name: svn:ignore + .deps .libs Makefile Makefile.in Added: trunk/varnish-cache/lib/libsbuf/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libsbuf/Makefile.am 2006-03-13 13:30:20 UTC (rev 44) +++ trunk/varnish-cache/lib/libsbuf/Makefile.am 2006-03-13 14:14:16 UTC (rev 45) @@ -0,0 +1,8 @@ +# $Id$ + +INCLUDES = -I$(top_srcdir)/include + +lib_LTLIBRARIES = libsbuf.la + +libsbuf_la_SOURCES = \ + sbuf.c Property changes on: trunk/varnish-cache/lib/libsbuf/Makefile.am ___________________________________________________________________ Name: svn:keyword + Id Added: trunk/varnish-cache/lib/libsbuf/sbuf.c =================================================================== --- trunk/varnish-cache/lib/libsbuf/sbuf.c 2006-03-13 13:30:20 UTC (rev 44) +++ trunk/varnish-cache/lib/libsbuf/sbuf.c 2006-03-13 14:14:16 UTC (rev 45) @@ -0,0 +1,468 @@ +/*- + * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co?dan Sm?rgrav + * 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 + * in this position and unchanged. + * 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. + * + * $Id$ + * $FreeBSD: src/sys/kern/subr_sbuf.c,v 1.30 2005/12/23 11:49:53 phk Exp $ + */ + +#include +#include +#include +#include +#include + +#include "sbuf.h" + +#define KASSERT(e, m) +#define SBMALLOC(size) malloc(size) +#define SBFREE(buf) free(buf) +#define min(x,y) (x < y ? x : y) + +/* + * Predicates + */ +#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) +#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) +#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) +#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) +#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) +#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) +#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) + +/* + * Set / clear flags + */ +#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) +#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) + +#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ +#define SBUF_MAXEXTENDSIZE 4096 +#define SBUF_MAXEXTENDINCR 4096 + +/* + * Debugging support + */ +#if !defined(NDEBUG) +static void +_assert_sbuf_integrity(const char *fun, struct sbuf *s) +{ + KASSERT(s != NULL, + ("%s called with a NULL sbuf pointer", fun)); + KASSERT(s->s_buf != NULL, + ("%s called with uninitialized or corrupt sbuf", fun)); + KASSERT(s->s_len < s->s_size, + ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); +} + +static void +_assert_sbuf_state(const char *fun, struct sbuf *s, int state) +{ + KASSERT((s->s_flags & SBUF_FINISHED) == state, + ("%s called with %sfinished or corrupt sbuf", fun, + (state ? "un" : ""))); +} +#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) +#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) +#else +#define assert_sbuf_integrity(s) do { } while (0) +#define assert_sbuf_state(s, i) do { } while (0) +#endif + +static int +sbuf_extendsize(int size) +{ + int newsize; + + newsize = SBUF_MINEXTENDSIZE; + while (newsize < size) { + if (newsize < (int)SBUF_MAXEXTENDSIZE) + newsize *= 2; + else + newsize += SBUF_MAXEXTENDINCR; + } + + return (newsize); +} + + +/* + * Extend an sbuf. + */ +static int +sbuf_extend(struct sbuf *s, int addlen) +{ + char *newbuf; + int newsize; + + if (!SBUF_CANEXTEND(s)) + return (-1); + + newsize = sbuf_extendsize(s->s_size + addlen); + newbuf = (char *)SBMALLOC(newsize); + if (newbuf == NULL) + return (-1); + bcopy(s->s_buf, newbuf, s->s_size); + if (SBUF_ISDYNAMIC(s)) + SBFREE(s->s_buf); + else + SBUF_SETFLAG(s, SBUF_DYNAMIC); + s->s_buf = newbuf; + s->s_size = newsize; + return (0); +} + +/* + * Initialize an sbuf. + * If buf is non-NULL, it points to a static or already-allocated string + * big enough to hold at least length characters. + */ +struct sbuf * +sbuf_new(struct sbuf *s, char *buf, int length, int flags) +{ + KASSERT(length >= 0, + ("attempt to create an sbuf of negative length (%d)", length)); + KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, + ("%s called with invalid flags", __func__)); + + flags &= SBUF_USRFLAGMSK; + if (s == NULL) { + s = (struct sbuf *)SBMALLOC(sizeof *s); + if (s == NULL) + return (NULL); + bzero(s, sizeof *s); + s->s_flags = flags; + SBUF_SETFLAG(s, SBUF_DYNSTRUCT); + } else { + bzero(s, sizeof *s); + s->s_flags = flags; + } + s->s_size = length; + if (buf) { + s->s_buf = buf; + return (s); + } + if (flags & SBUF_AUTOEXTEND) + s->s_size = sbuf_extendsize(s->s_size); + s->s_buf = (char *)SBMALLOC(s->s_size); + if (s->s_buf == NULL) { + if (SBUF_ISDYNSTRUCT(s)) + SBFREE(s); + return (NULL); + } + SBUF_SETFLAG(s, SBUF_DYNAMIC); + return (s); +} + +/* + * Clear an sbuf and reset its position. + */ +void +sbuf_clear(struct sbuf *s) +{ + assert_sbuf_integrity(s); + /* don't care if it's finished or not */ + + SBUF_CLEARFLAG(s, SBUF_FINISHED); + SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); + s->s_len = 0; +} + +/* + * Set the sbuf's end position to an arbitrary value. + * Effectively truncates the sbuf at the new position. + */ +int +sbuf_setpos(struct sbuf *s, int pos) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + KASSERT(pos >= 0, + ("attempt to seek to a negative position (%d)", pos)); + KASSERT(pos < s->s_size, + ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); + + if (pos < 0 || pos > s->s_len) + return (-1); + s->s_len = pos; + return (0); +} + +/* + * Append a byte string to an sbuf. + */ +int +sbuf_bcat(struct sbuf *s, const void *buf, size_t len) +{ + const char *str = buf; + + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + + for (; len; len--) { + if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) + break; + s->s_buf[s->s_len++] = *str++; + } + if (len) { + SBUF_SETFLAG(s, SBUF_OVERFLOWED); + return (-1); + } + return (0); +} + +/* + * Copy a byte string into an sbuf. + */ +int +sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + sbuf_clear(s); + return (sbuf_bcat(s, buf, len)); +} + +/* + * Append a string to an sbuf. + */ +int +sbuf_cat(struct sbuf *s, const char *str) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + + while (*str) { + if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) + break; + s->s_buf[s->s_len++] = *str++; + } + if (*str) { + SBUF_SETFLAG(s, SBUF_OVERFLOWED); + return (-1); + } + return (0); +} + +/* + * Copy a string into an sbuf. + */ +int +sbuf_cpy(struct sbuf *s, const char *str) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + sbuf_clear(s); + return (sbuf_cat(s, str)); +} + +/* + * Format the given argument list and append the resulting string to an sbuf. + */ +int +sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) +{ + va_list ap_copy; + int len; + + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + KASSERT(fmt != NULL, + ("%s called with a NULL format string", __func__)); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + + do { + va_copy(ap_copy, ap); + len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, + fmt, ap_copy); + va_end(ap_copy); + } while (len > SBUF_FREESPACE(s) && + sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); + + /* + * s->s_len is the length of the string, without the terminating nul. + * When updating s->s_len, we must subtract 1 from the length that + * we passed into vsnprintf() because that length includes the + * terminating nul. + * + * vsnprintf() returns the amount that would have been copied, + * given sufficient space, hence the min() calculation below. + */ + s->s_len += min(len, SBUF_FREESPACE(s)); + if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) + SBUF_SETFLAG(s, SBUF_OVERFLOWED); + + KASSERT(s->s_len < s->s_size, + ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + return (0); +} + +/* + * Format the given arguments and append the resulting string to an sbuf. + */ +int +sbuf_printf(struct sbuf *s, const char *fmt, ...) +{ + va_list ap; + int result; + + va_start(ap, fmt); + result = sbuf_vprintf(s, fmt, ap); + va_end(ap); + return(result); +} + +/* + * Append a character to an sbuf. + */ +int +sbuf_putc(struct sbuf *s, int c) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + + if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { + SBUF_SETFLAG(s, SBUF_OVERFLOWED); + return (-1); + } + if (c != '\0') + s->s_buf[s->s_len++] = c; + return (0); +} + +/* + * Trim whitespace characters from end of an sbuf. + */ +int +sbuf_trim(struct sbuf *s) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + + while (s->s_len && isspace(s->s_buf[s->s_len-1])) + --s->s_len; + + return (0); +} + +/* + * Check if an sbuf overflowed + */ +int +sbuf_overflowed(struct sbuf *s) +{ + return SBUF_HASOVERFLOWED(s); +} + +/* + * Finish off an sbuf. + */ +void +sbuf_finish(struct sbuf *s) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + s->s_buf[s->s_len] = '\0'; + SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); + SBUF_SETFLAG(s, SBUF_FINISHED); +} + +/* + * Return a pointer to the sbuf data. + */ +char * +sbuf_data(struct sbuf *s) +{ + assert_sbuf_integrity(s); + assert_sbuf_state(s, SBUF_FINISHED); + + return s->s_buf; +} + +/* + * Return the length of the sbuf data. + */ +int +sbuf_len(struct sbuf *s) +{ + assert_sbuf_integrity(s); + /* don't care if it's finished or not */ + + if (SBUF_HASOVERFLOWED(s)) + return (-1); + return s->s_len; +} + +/* + * Clear an sbuf, free its buffer if necessary. + */ +void +sbuf_delete(struct sbuf *s) +{ + int isdyn; + + assert_sbuf_integrity(s); + /* don't care if it's finished or not */ + + if (SBUF_ISDYNAMIC(s)) + SBFREE(s->s_buf); + isdyn = SBUF_ISDYNSTRUCT(s); + bzero(s, sizeof *s); + if (isdyn) + SBFREE(s); +} + +/* + * Check if an sbuf has been finished. + */ +int +sbuf_done(struct sbuf *s) +{ + + return(SBUF_ISFINISHED(s)); +} Property changes on: trunk/varnish-cache/lib/libsbuf/sbuf.c ___________________________________________________________________ Name: svn:keyword + Id From des at projects.linpro.no Mon Mar 13 14:23:15 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Mon, 13 Mar 2006 15:23:15 +0100 (CET) Subject: r46 - trunk/varnish-cache/include Message-ID: <20060313142315.2136D1ED563@projects.linpro.no> Author: des Date: 2006-03-13 15:23:15 +0100 (Mon, 13 Mar 2006) New Revision: 46 Added: trunk/varnish-cache/include/hash.h trunk/varnish-cache/include/queue.h trunk/varnish-cache/include/tree.h Modified: trunk/varnish-cache/include/Makefile.am Log: Add hash.h, queue.h and tree.h from NetBSD-CURRENT. Modified: trunk/varnish-cache/include/Makefile.am =================================================================== --- trunk/varnish-cache/include/Makefile.am 2006-03-13 14:14:16 UTC (rev 45) +++ trunk/varnish-cache/include/Makefile.am 2006-03-13 14:23:15 UTC (rev 46) @@ -1,6 +1,10 @@ # $Id$ include_HEADERS = \ + hash.h \ + queue.h \ + sbuf.h \ + tree.h \ varnish/assert.h \ varnishapi.h Added: trunk/varnish-cache/include/hash.h =================================================================== --- trunk/varnish-cache/include/hash.h 2006-03-13 14:14:16 UTC (rev 45) +++ trunk/varnish-cache/include/hash.h 2006-03-13 14:23:15 UTC (rev 46) @@ -0,0 +1,111 @@ +/* $Id$ */ +/* $NetBSD: hash.h,v 1.5 2006/02/16 20:17:20 perry Exp $ */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#ifndef _SYS_HASH_H_ +#define _SYS_HASH_H_ + +#include +#ifdef __HAVE_MACHINE_HASH_H +#include +#endif + + +#ifndef __HAVE_HASH32_BUF /* not overridden by MD hash */ + +#define HASH32_BUF_INIT 5381 + +/* + * uint32_t + * hash32_buf(const void *bf, size_t len, uint32_t hash) + * return a 32 bit hash of the binary buffer buf (size len), + * seeded with an initial hash value of hash (usually HASH32_BUF_INIT). + */ +static __inline uint32_t +hash32_buf(const void *bf, size_t len, uint32_t hash) +{ + const uint8_t *s = bf; + + while (len-- != 0) /* "nemesi": k=257, r=r*257 */ + hash = hash * 257 + *s++; + return (hash * 257); +} +#endif /* __HAVE_HASH32_BUF */ + + +#ifndef __HAVE_HASH32_STR /* not overridden by MD hash */ + +#define HASH32_STR_INIT 5381 +/* + * uint32_t + * hash32_str(const void *bf, uint32_t hash) + * return a 32 bit hash of NUL terminated ASCII string buf, + * seeded with an initial hash value of hash (usually HASH32_STR_INIT). + */ +static __inline uint32_t +hash32_str(const void *bf, uint32_t hash) +{ + const uint8_t *s = bf; + uint8_t c; + + while ((c = *s++) != 0) + hash = hash * 33 + c; /* "perl": k=33, r=r+r/32 */ + return (hash + (hash >> 5)); +} + +/* + * uint32_t + * hash32_strn(const void *bf, size_t len, uint32_t hash) + * return a 32 bit hash of NUL terminated ASCII string buf up to + * a maximum of len bytes, + * seeded with an initial hash value of hash (usually HASH32_STR_INIT). + */ +static __inline uint32_t +hash32_strn(const void *bf, size_t len, uint32_t hash) +{ + const uint8_t *s = bf; + uint8_t c; + + while ((c = *s++) != 0 && len-- != 0) + hash = hash * 33 + c; /* "perl": k=33, r=r+r/32 */ + return (hash + (hash >> 5)); +} +#endif /* __HAVE_HASH32_STR */ + + +#endif /* !_SYS_HASH_H_ */ Property changes on: trunk/varnish-cache/include/hash.h ___________________________________________________________________ Name: svn:keyword + Id Added: trunk/varnish-cache/include/queue.h =================================================================== --- trunk/varnish-cache/include/queue.h 2006-03-13 14:14:16 UTC (rev 45) +++ trunk/varnish-cache/include/queue.h 2006-03-13 14:23:15 UTC (rev 46) @@ -0,0 +1,671 @@ +/* $Id$ */ +/* $NetBSD: queue.h,v 1.45 2006/03/07 17:56:00 pooka Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.le_prev != (elm)) \ + panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ + if ((head)->cqh_first != (void *)(head) && \ + (head)->cqh_first->field.cqe_prev != (void *)(head)) \ + panic("CIRCLEQ head forw %p %s:%d", (head), \ + __FILE__, __LINE__); \ + if ((head)->cqh_last != (void *)(head) && \ + (head)->cqh_last->field.cqe_next != (void *)(head)) \ + panic("CIRCLEQ head back %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ + if ((elm)->field.cqe_next == (void *)(head)) { \ + if ((head)->cqh_last != (elm)) \ + panic("CIRCLEQ elm last %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ + panic("CIRCLEQ elm forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } \ + if ((elm)->field.cqe_prev == (void *)(head)) { \ + if ((head)->cqh_first != (elm)) \ + panic("CIRCLEQ elm first %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ + panic("CIRCLEQ elm prev %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ + (elm)->field.cqe_next = (void *)1L; \ + (elm)->field.cqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) +#endif + +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* !_SYS_QUEUE_H_ */ Property changes on: trunk/varnish-cache/include/queue.h ___________________________________________________________________ Name: svn:keyword + Id Added: trunk/varnish-cache/include/tree.h =================================================================== --- trunk/varnish-cache/include/tree.h 2006-03-13 14:14:16 UTC (rev 45) +++ trunk/varnish-cache/include/tree.h 2006-03-13 14:23:15 UTC (rev 46) @@ -0,0 +1,682 @@ +/* $Id$ */ +/* $NetBSD: tree.h,v 1.12 2005/12/28 15:33:47 yamt Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * 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. + * + * 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. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* ARGSUSED */ \ +struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#endif /* _SYS_TREE_H_ */ Property changes on: trunk/varnish-cache/include/tree.h ___________________________________________________________________ Name: svn:keyword + Id From phk at projects.linpro.no Tue Mar 14 09:15:37 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Tue, 14 Mar 2006 10:15:37 +0100 (CET) Subject: r47 - in trunk/varnish-cache: include lib/libvarnish Message-ID: <20060314091537.1594F1ED545@projects.linpro.no> Author: phk Date: 2006-03-14 10:15:36 +0100 (Tue, 14 Mar 2006) New Revision: 47 Added: trunk/varnish-cache/include/libvarnish.h trunk/varnish-cache/lib/libvarnish/argv.c Modified: trunk/varnish-cache/include/Makefile.am trunk/varnish-cache/lib/libvarnish/Makefile.am Log: Add a function to break a command line like string into an argv[]. This will be useful for the various text based protocols etc. Modified: trunk/varnish-cache/include/Makefile.am =================================================================== --- trunk/varnish-cache/include/Makefile.am 2006-03-13 14:23:15 UTC (rev 46) +++ trunk/varnish-cache/include/Makefile.am 2006-03-14 09:15:36 UTC (rev 47) @@ -2,9 +2,9 @@ include_HEADERS = \ hash.h \ + libvarnish.h \ queue.h \ sbuf.h \ tree.h \ varnish/assert.h \ varnishapi.h - Added: trunk/varnish-cache/include/libvarnish.h =================================================================== --- trunk/varnish-cache/include/libvarnish.h 2006-03-13 14:23:15 UTC (rev 46) +++ trunk/varnish-cache/include/libvarnish.h 2006-03-14 09:15:36 UTC (rev 47) @@ -0,0 +1,7 @@ +/* + * $Id$ + */ + +/* from libvarnish/argv.c */ +void FreeArgv(char **argv); +char **ParseArgv(const char *s, int comment); Modified: trunk/varnish-cache/lib/libvarnish/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvarnish/Makefile.am 2006-03-13 14:23:15 UTC (rev 46) +++ trunk/varnish-cache/lib/libvarnish/Makefile.am 2006-03-14 09:15:36 UTC (rev 47) @@ -4,4 +4,5 @@ lib_LTLIBRARIES = libvarnish.la -libvarnish_la_SOURCES = +libvarnish_la_SOURCES = \ + argv.c Added: trunk/varnish-cache/lib/libvarnish/argv.c =================================================================== --- trunk/varnish-cache/lib/libvarnish/argv.c 2006-03-13 14:23:15 UTC (rev 46) +++ trunk/varnish-cache/lib/libvarnish/argv.c 2006-03-14 09:15:36 UTC (rev 47) @@ -0,0 +1,213 @@ +/* + * $Id$ + * + * char **ParseArgv(const char *s, int comment) + * Parse a command like line into an argv[] + * Index zero contains NULL or an error message + * "double quotes" and backslash substitution is handled. + * + * void FreeArgv(char **argv) + * Free the result of ParseArgv() + * + */ + +#include +#include +#include +#include +#include + +#include "libvarnish.h" + +static int +BackSlash(const char *s, int *res) +{ + int i, r; + + assert(*s == '\\'); + r = i = 0; + switch(s[1]) { + case 'n': + i = '\n'; + r = 2; + break; + case 'r': + i = '\r'; + r = 2; + break; + case 't': + i = '\t'; + r = 2; + break; + case '"': + i = '"'; + r = 2; + break; + case '\\': + i = '\\'; + r = 2; + break; + case '0': case '1': case '2': case 3: + case '4': case '5': case '6': case 7: + for (r = 1; r < 4; r++) { + if (!isdigit(s[r])) + break; + if (digittoint(s[r]) > 7) + break; + i <<= 3; + i |= digittoint(s[r]); + } + break; + case 'x': + if (1 == sscanf(s + 1, "x%02x", &i)) + r = 4; + break; + default: + break; + } + if (res != NULL) + *res = i; + return (r); +} + +static char * +BackSlashDecode(const char *s, const char *e) +{ + const char *q; + char *p, *r; + int i, j; + + p = calloc((e - s) + 1, 1); + if (p == NULL) + return (p); + for (r = p, q = s; q < e; ) { + if (*q != '\\') { + *r++ = *q++; + continue; + } + i = BackSlash(q, &j); + q += i; + *r++ = j; + } + *r = '\0'; + return (p); +} + +char ** +ParseArgv(const char *s, int comment) +{ + char **argv; + const char *p; + int nargv, largv; + int i, quote; + + assert(s != NULL); + nargv = 1; + largv = 16; + argv = calloc(sizeof *argv, largv); + if (argv == NULL) + return (NULL); + + for (;;) { + if (*s == '\0') + break; + if (isspace(*s)) { + s++; + continue; + } + if (comment && *s == '#') + break; + if (*s == '"') { + p = ++s; + quote = 1; + } else { + p = s; + quote = 0; + } + while (1) { + if (*s == '\\') { + i = BackSlash(s, NULL); + if (i == 0) { + argv[0] = __DECONST(void *, + "Illegal backslash sequence"); + return (argv); + } + s += i; + continue; + } + if (!quote) { + if (*s == '\0' || isspace(*s)) + break; + s++; + continue; + } + if (*s == '"') + break; + if (*s == '\0') { + argv[0] = __DECONST(void *, + "Missing '\"'"); + return (argv); + } + s++; + } + if (nargv + 1 >= largv) { + argv = realloc(argv, sizeof (*argv) * (largv += largv)); + assert(argv != NULL); + } + argv[nargv++] = BackSlashDecode(p, s); + if (*s != '\0') + s++; + } + argv[nargv++] = NULL; + return (argv); +} + +void +FreeArgv(char **argv) +{ + int i; + + for (i = 1; argv[i] != NULL; i++) + free(argv[i]); + free(argv); +} + +#ifdef TESTPROG + +#include + +static void +PrintArgv(char **argv) +{ + int i; + + printf("---- %p\n", argv); + if (argv[0] != NULL) + printf("err %V\n", argv[0]); + for (i = 1; argv[i] != NULL; i++) + printf("%3d %V\n", i, argv[i]); +} + +static void +Test(const char *str) +{ + char **av; + + printf("Test: <%V>\n", str); + av = ParseArgv(str, 0); + PrintArgv(av); +} + +int +main(int argc __unused, char **argv __unused) +{ + char buf[BUFSIZ]; + + register_printf_render_std("V"); + + while (fgets(buf, sizeof buf, stdin)) + Test(buf); + + return (0); +} +#endif From phk at projects.linpro.no Tue Mar 14 09:31:15 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Tue, 14 Mar 2006 10:31:15 +0100 (CET) Subject: r48 - trunk/varnish-cache/bin/varnishd Message-ID: <20060314093115.ED5B81ED563@projects.linpro.no> Author: phk Date: 2006-03-14 10:31:15 +0100 (Tue, 14 Mar 2006) New Revision: 48 Modified: trunk/varnish-cache/bin/varnishd/varnishd.c Log: Add some trivial bits while I think about the hard ones Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-14 09:15:36 UTC (rev 47) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-14 09:31:15 UTC (rev 48) @@ -10,7 +10,19 @@ static void usage(void) { - fprintf(stderr, "usage: varnishd\n"); + fprintf(stderr, "usage: varnishd [options]\n"); + fprintf(stderr, " %-20s # %s\n", "-d", "debug"); + fprintf(stderr, " %-20s # %s\n", "-p number", "TCP listen port"); +#if 0 + -c clusterid at cluster_controller + -f config_file + -m memory_limit + -s kind[,storage-options] + -l logfile,logsize + -b backend ip... + -u uid + -a CLI_port +#endif exit(1); } @@ -18,9 +30,17 @@ main(int argc, char *argv[]) { int o; + unsigned portnumber = 8080; + unsigned dflag = 1; /* XXX: debug=on for now */ - while ((o = getopt(argc, argv, "")) != -1) + while ((o = getopt(argc, argv, "dp:")) != -1) switch (o) { + case 'd': + dflag++; + break; + case 'p': + portnumber = strtoul(optarg, NULL, 0); + break; default: usage(); } From des at projects.linpro.no Tue Mar 14 11:57:28 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Tue, 14 Mar 2006 12:57:28 +0100 (CET) Subject: r49 - trunk/varnish-cache/lib/libsbuf Message-ID: <20060314115728.764F41ED545@projects.linpro.no> Author: des Date: 2006-03-14 12:57:28 +0100 (Tue, 14 Mar 2006) New Revision: 49 Added: trunk/varnish-cache/lib/libsbuf/sbuf.3 Modified: trunk/varnish-cache/lib/libsbuf/Makefile.am trunk/varnish-cache/lib/libsbuf/sbuf.c Log: Add a man page, and set the correct property (svn:keywords, not svn:keyword) Modified: trunk/varnish-cache/lib/libsbuf/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libsbuf/Makefile.am 2006-03-14 09:31:15 UTC (rev 48) +++ trunk/varnish-cache/lib/libsbuf/Makefile.am 2006-03-14 11:57:28 UTC (rev 49) @@ -6,3 +6,6 @@ libsbuf_la_SOURCES = \ sbuf.c + +man_MANS = \ + sbuf.3 Property changes on: trunk/varnish-cache/lib/libsbuf/Makefile.am ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id Added: trunk/varnish-cache/lib/libsbuf/sbuf.3 =================================================================== --- trunk/varnish-cache/lib/libsbuf/sbuf.3 2006-03-14 09:31:15 UTC (rev 48) +++ trunk/varnish-cache/lib/libsbuf/sbuf.3 2006-03-14 11:57:28 UTC (rev 49) @@ -0,0 +1,338 @@ +.\"- +.\" Copyright (c) 2000 Poul Henning Kamp and Dag-Erling Co?dan Sm?rgrav +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. +.\" +.\" $Id$ +.\" $FreeBSD: src/share/man/man9/sbuf.9,v 1.25 2005/12/23 11:49:52 phk Exp $ +.\" +.Dd March 14, 2006 +.Dt SBUF 3 +.Os +.Sh NAME +.Nm sbuf_new , +.Nm sbuf_clear , +.Nm sbuf_setpos , +.Nm sbuf_bcat , +.Nm sbuf_bcpy , +.Nm sbuf_cat , +.Nm sbuf_cpy , +.Nm sbuf_printf , +.Nm sbuf_vprintf , +.Nm sbuf_putc , +.Nm sbuf_trim , +.Nm sbuf_overflowed , +.Nm sbuf_finish , +.Nm sbuf_data , +.Nm sbuf_len , +.Nm sbuf_done , +.Nm sbuf_delete +.Nd safe string formatting +.Sh LIBRARY +.Lb libsbuf +.Sh SYNOPSIS +.In sbuf.h +.Ft struct sbuf * +.Fn sbuf_new "struct sbuf *s" "char *buf" "int length" "int flags" +.Ft void +.Fn sbuf_clear "struct sbuf *s" +.Ft int +.Fn sbuf_setpos "struct sbuf *s" "int pos" +.Ft int +.Fn sbuf_bcat "struct sbuf *s" "const void *buf" "size_t len" +.Ft int +.Fn sbuf_bcpy "struct sbuf *s" "const void *buf" "size_t len" +.Ft int +.Fn sbuf_cat "struct sbuf *s" "const char *str" +.Ft int +.Fn sbuf_cpy "struct sbuf *s" "const char *str" +.Ft int +.Fn sbuf_printf "struct sbuf *s" "const char *fmt" "..." +.Ft int +.Fn sbuf_vprintf "struct sbuf *s" "const char *fmt" "va_list ap" +.Ft int +.Fn sbuf_putc "struct sbuf *s" "int c" +.Ft int +.Fn sbuf_trim "struct sbuf *s" +.Ft int +.Fn sbuf_overflowed "struct sbuf *s" +.Ft void +.Fn sbuf_finish "struct sbuf *s" +.Ft char * +.Fn sbuf_data "struct sbuf *s" +.Ft int +.Fn sbuf_len "struct sbuf *s" +.Ft int +.Fn sbuf_done "struct sbuf *s" +.Ft void +.Fn sbuf_delete "struct sbuf *s" +.Sh DESCRIPTION +The +.Nm sbuf +family of functions allows one to safely allocate, construct and +release bounded null-terminated strings in kernel space. +Instead of arrays of characters, these functions operate on structures +called +.Fa sbufs , +defined in +.In sys/sbuf.h . +.Pp +The +.Fn sbuf_new +function initializes the +.Fa sbuf +pointed to by its first argument. +If that pointer is +.Dv NULL , +.Fn sbuf_new +allocates a +.Vt struct sbuf +using +.Xr malloc 9 . +The +.Fa buf +argument is a pointer to a buffer in which to store the actual string; +if it is +.Dv NULL , +.Fn sbuf_new +will allocate one using +.Xr malloc 9 . +The +.Fa length +is the initial size of the storage buffer. +The fourth argument, +.Fa flags , +may be comprised of the following flags: +.Bl -tag -width ".Dv SBUF_AUTOEXTEND" +.It Dv SBUF_FIXEDLEN +The storage buffer is fixed at its initial size. +Attempting to extend the sbuf beyond this size results in an overflow condition. +.It Dv SBUF_AUTOEXTEND +This indicates that the storage buffer may be extended as necessary, so long +as resources allow, to hold additional data. +.El +.Pp +Note that if +.Fa buf +is not +.Dv NULL , +it must point to an array of at least +.Fa length +characters. +The result of accessing that array directly while it is in use by the +sbuf is undefined. +.Pp +The +.Fn sbuf_delete +function clears the +.Fa sbuf +and frees any memory allocated for it. +There must be a call to +.Fn sbuf_delete +for every call to +.Fn sbuf_new . +Any attempt to access the sbuf after it has been deleted will fail. +.Pp +The +.Fn sbuf_clear +function invalidates the contents of the +.Fa sbuf +and resets its position to zero. +.Pp +The +.Fn sbuf_setpos +function sets the +.Fa sbuf Ns 's +end position to +.Fa pos , +which is a value between zero and one less than the size of the +storage buffer. +This effectively truncates the sbuf at the new position. +.Pp +The +.Fn sbuf_bcat +function appends the first +.Fa len +bytes from the buffer +.Fa buf +to the +.Fa sbuf . +.Pp +The +.Fn sbuf_bcpy +function replaces the contents of the +.Fa sbuf +with the first +.Fa len +bytes from the buffer +.Fa buf . +.Pp +The +.Fn sbuf_cat +function appends the NUL-terminated string +.Fa str +to the +.Fa sbuf +at the current position. +.Pp +The +.Fn sbuf_cpy +function replaces the contents of the +.Fa sbuf +with those of the NUL-terminated string +.Fa str . +This is equivalent to calling +.Fn sbuf_cat +with a fresh +.Fa sbuf +or one which position has been reset to zero with +.Fn sbuf_clear +or +.Fn sbuf_setpos . +.Pp +The +.Fn sbuf_printf +function formats its arguments according to the format string pointed +to by +.Fa fmt +and appends the resulting string to the +.Fa sbuf +at the current position. +.Pp +The +.Fn sbuf_vprintf +function behaves the same as +.Fn sbuf_printf +except that the arguments are obtained from the variable-length argument list +.Fa ap . +.Pp +The +.Fn sbuf_putc +function appends the character +.Fa c +to the +.Fa sbuf +at the current position. +.Pp +The +.Fn sbuf_trim +function removes trailing whitespace from the +.Fa sbuf . +.Pp +The +.Fn sbuf_overflowed +function returns a non-zero value if the +.Fa sbuf +overflowed. +.Pp +The +.Fn sbuf_finish +function null-terminates the +.Fa sbuf +and marks it as finished, which means that it may no longer be +modified using +.Fn sbuf_setpos , +.Fn sbuf_cat , +.Fn sbuf_cpy , +.Fn sbuf_printf +or +.Fn sbuf_putc . +.Pp +The +.Fn sbuf_data +and +.Fn sbuf_len +functions return the actual string and its length, respectively; +.Fn sbuf_data +only works on a finished +.Fa sbuf . +.Fn sbuf_done +returns non-zero if the sbuf is finished. +.Sh NOTES +If an operation caused an +.Fa sbuf +to overflow, most subsequent operations on it will fail until the +.Fa sbuf +is finished using +.Fn sbuf_finish +or reset using +.Fn sbuf_clear , +or its position is reset to a value between 0 and one less than the +size of its storage buffer using +.Fn sbuf_setpos , +or it is reinitialized to a sufficiently short string using +.Fn sbuf_cpy . +.Sh RETURN VALUES +.Fn sbuf_new +returns +.Dv NULL +if it failed to allocate a storage buffer, and a pointer to the new +.Fa sbuf +otherwise. +.Pp +.Fn sbuf_setpos +returns \-1 if +.Fa pos +was invalid, and zero otherwise. +.Pp +.Fn sbuf_cat , +.Fn sbuf_cpy , +.Fn sbuf_printf , +.Fn sbuf_putc , +and +.Fn sbuf_trim +all return \-1 if the buffer overflowed, and zero otherwise. +.Pp +.Fn sbuf_overflowed +returns a non-zero value if the buffer overflowed, and zero otherwise. +.Pp +.Fn sbuf_data +and +.Fn sbuf_len +return +.Dv NULL +and \-1, respectively, if the buffer overflowed. +.Sh SEE ALSO +.Xr printf 3 , +.Xr strcat 3 , +.Xr strcpy 3 +.Sh HISTORY +The +.Nm sbuf +family of functions first appeared in +.Fx 4.4 . +.Sh AUTHORS +.An -nosplit +The +.Nm sbuf +family of functions was designed by +.An Poul-Henning Kamp Aq phk at FreeBSD.org +and implemented by +.An Dag-Erling Sm\(/orgrav Aq des at FreeBSD.org . +Additional improvements were suggested by +.An Justin T. Gibbs Aq gibbs at FreeBSD.org . +Auto-extend support added by +.An Kelly Yancey Aq kbyanc at FreeBSD.org . +.Pp +This manual page was written by +.An Dag-Erling Sm\(/orgrav Aq des at FreeBSD.org . Property changes on: trunk/varnish-cache/lib/libsbuf/sbuf.3 ___________________________________________________________________ Name: svn:keywords + Id Property changes on: trunk/varnish-cache/lib/libsbuf/sbuf.c ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id From des at projects.linpro.no Tue Mar 14 12:00:35 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Tue, 14 Mar 2006 13:00:35 +0100 (CET) Subject: r50 - trunk/varnish-cache/include Message-ID: <20060314120035.3A1771ED57E@projects.linpro.no> Author: des Date: 2006-03-14 13:00:35 +0100 (Tue, 14 Mar 2006) New Revision: 50 Modified: trunk/varnish-cache/include/hash.h trunk/varnish-cache/include/libvarnish.h trunk/varnish-cache/include/queue.h trunk/varnish-cache/include/sbuf.h trunk/varnish-cache/include/tree.h Log: Set the correct property (svn:keywords, not svn:keyword) Property changes on: trunk/varnish-cache/include/hash.h ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id Property changes on: trunk/varnish-cache/include/libvarnish.h ___________________________________________________________________ Name: svn:keywords + Id Property changes on: trunk/varnish-cache/include/queue.h ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id Property changes on: trunk/varnish-cache/include/sbuf.h ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id Property changes on: trunk/varnish-cache/include/tree.h ___________________________________________________________________ Name: svn:keyword - Id Name: svn:keywords + Id From des at projects.linpro.no Tue Mar 14 12:54:13 2006 From: des at projects.linpro.no (des at projects.linpro.no) Date: Tue, 14 Mar 2006 13:54:13 +0100 (CET) Subject: r51 - in trunk/varnish-cache: . contrib contrib/libevent contrib/libevent/WIN32-Code contrib/libevent/WIN32-Prj contrib/libevent/WIN32-Prj/event_test contrib/libevent/WIN32-Prj/signal_test contrib/libevent/WIN32-Prj/time_test contrib/libevent/compat contrib/libevent/compat/sys contrib/libevent/sample contrib/libevent/test Message-ID: <20060314125413.8409A1ED54A@projects.linpro.no> Author: des Date: 2006-03-14 13:54:13 +0100 (Tue, 14 Mar 2006) New Revision: 51 Added: trunk/varnish-cache/contrib/ trunk/varnish-cache/contrib/libevent/ trunk/varnish-cache/contrib/libevent/Makefile.am trunk/varnish-cache/contrib/libevent/README trunk/varnish-cache/contrib/libevent/WIN32-Code/ trunk/varnish-cache/contrib/libevent/WIN32-Code/config.h trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.c trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.h trunk/varnish-cache/contrib/libevent/WIN32-Code/provos at badschwartau.provos.org.12766 trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c trunk/varnish-cache/contrib/libevent/WIN32-Prj/ trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/ trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/event_test.dsp trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/test.txt trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsw trunk/varnish-cache/contrib/libevent/WIN32-Prj/signal_test/ trunk/varnish-cache/contrib/libevent/WIN32-Prj/signal_test/signal_test.dsp trunk/varnish-cache/contrib/libevent/WIN32-Prj/time_test/ trunk/varnish-cache/contrib/libevent/WIN32-Prj/time_test/time_test.dsp trunk/varnish-cache/contrib/libevent/acconfig.h trunk/varnish-cache/contrib/libevent/buffer.c trunk/varnish-cache/contrib/libevent/compat/ trunk/varnish-cache/contrib/libevent/compat/sys/ trunk/varnish-cache/contrib/libevent/compat/sys/_time.h trunk/varnish-cache/contrib/libevent/compat/sys/queue.h trunk/varnish-cache/contrib/libevent/compat/sys/tree.h trunk/varnish-cache/contrib/libevent/configure.in trunk/varnish-cache/contrib/libevent/devpoll.c trunk/varnish-cache/contrib/libevent/epoll.c trunk/varnish-cache/contrib/libevent/epoll_sub.c trunk/varnish-cache/contrib/libevent/evbuffer.c trunk/varnish-cache/contrib/libevent/event-internal.h trunk/varnish-cache/contrib/libevent/event.3 trunk/varnish-cache/contrib/libevent/event.c trunk/varnish-cache/contrib/libevent/event.h trunk/varnish-cache/contrib/libevent/evsignal.h trunk/varnish-cache/contrib/libevent/kqueue.c trunk/varnish-cache/contrib/libevent/log.c trunk/varnish-cache/contrib/libevent/log.h trunk/varnish-cache/contrib/libevent/poll.c trunk/varnish-cache/contrib/libevent/rtsig.c trunk/varnish-cache/contrib/libevent/sample/ trunk/varnish-cache/contrib/libevent/sample/Makefile.am trunk/varnish-cache/contrib/libevent/sample/Makefile.in trunk/varnish-cache/contrib/libevent/sample/event-test.c trunk/varnish-cache/contrib/libevent/sample/signal-test.c trunk/varnish-cache/contrib/libevent/sample/time-test.c trunk/varnish-cache/contrib/libevent/select.c trunk/varnish-cache/contrib/libevent/signal.c trunk/varnish-cache/contrib/libevent/test/ trunk/varnish-cache/contrib/libevent/test/Makefile.am trunk/varnish-cache/contrib/libevent/test/Makefile.in trunk/varnish-cache/contrib/libevent/test/bench.c trunk/varnish-cache/contrib/libevent/test/regress.c trunk/varnish-cache/contrib/libevent/test/test-eof.c trunk/varnish-cache/contrib/libevent/test/test-init.c trunk/varnish-cache/contrib/libevent/test/test-time.c trunk/varnish-cache/contrib/libevent/test/test-weof.c trunk/varnish-cache/contrib/libevent/test/test.sh Log: Add Niels Provos's libevent 1.1a. Added: trunk/varnish-cache/contrib/libevent/Makefile.am =================================================================== --- trunk/varnish-cache/contrib/libevent/Makefile.am 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/Makefile.am 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,37 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +SUBDIRS = . sample test + +EXTRA_DIST = acconfig.h event.h event-internal.h log.h evsignal.h event.3 \ + kqueue.c epoll_sub.c epoll.c select.c rtsig.c poll.c signal.c \ + devpoll.c \ + sample/Makefile.am sample/Makefile.in sample/event-test.c \ + sample/signal-test.c sample/time-test.c \ + test/Makefile.am test/Makefile.in test/bench.c test/regress.c \ + test/test-eof.c test/test-weof.c test/test-time.c \ + test/test-init.c test/test.sh \ + compat/sys/queue.h compat/sys/tree.h compat/sys/_time.h \ + WIN32-Code WIN32-Code/config.h WIN32-Code/misc.c \ + WIN32-Code/win32.c WIN32-Code/misc.h \ + WIN32-Prj WIN32-Prj/event_test WIN32-Prj/event_test/event_test.dsp \ + WIN32-Prj/event_test/test.txt WIN32-Prj/libevent.dsp \ + WIN32-Prj/libevent.dsw WIN32-Prj/signal_test \ + WIN32-Prj/signal_test/signal_test.dsp WIN32-Prj/time_test \ + WIN32-Prj/time_test/time_test.dsp + +lib_LTLIBRARIES = libevent.la + +libevent_la_SOURCES = event.c buffer.c evbuffer.c log.c +libevent_la_LIBADD = @LTLIBOBJS@ +libevent_la_LDFLAGS = -release @VERSION@ -version-info 1:2:0 + +include_HEADERS = event.h + +INCLUDES = -Icompat + +man_MANS = event.3 + +verify: libevent.la + cd $(srcdir)/test && make verify + +DISTCLEANFILES = *~ Added: trunk/varnish-cache/contrib/libevent/README =================================================================== --- trunk/varnish-cache/contrib/libevent/README 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/README 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,28 @@ +To build libevent, type + +$ ./configure && make + +Install as root via + +# make install + +You can run the regression tests by + +$ make verify + +Before, reporting any problems, please run the regression tests. + +Acknowledgements: +----------------- + +The following people have helped with suggestions, ideas, code or +fixing bugs: + + Nick Mathewson + Andrew Danforth + Shie Erlich + Mike Davis + William Ahern + Alexander von Gernler + +If I have forgotten your name, please contact me. Added: trunk/varnish-cache/contrib/libevent/WIN32-Code/config.h =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Code/config.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Code/config.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,231 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* Define if kqueue works correctly with pipes */ +#undef HAVE_WORKING_KQUEUE + +/* Define to `unsigned long long' if doesn't define. */ +#undef u_int64_t + +/* Define to `unsigned int' if doesn't define. */ +#undef u_int32_t + +/* Define to `unsigned short' if doesn't define. */ +#undef u_int16_t + +/* Define to `unsigned char' if doesn't define. */ +#undef u_int8_t + +/* Define if timeradd is defined in */ +#undef HAVE_TIMERADD +#ifndef HAVE_TIMERADD +#undef timersub +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* !HAVE_TIMERADD */ + +#undef HAVE_TIMERCLEAR +#ifndef HAVE_TIMERCLEAR +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif + +#define HAVE_TIMERCMP +#ifndef HAVE_TIMERCMP +#undef timercmp +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#endif + +#undef HAVE_TIMERISSET +#ifndef HAVE_TIMERISSET +#undef timerisset +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + +/* Define if TAILQ_FOREACH is defined in */ +#define HAVE_TAILQFOREACH +#ifndef HAVE_TAILQFOREACH +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) +#endif /* TAILQ_FOREACH */ + +/* Define if /dev/poll is available */ +#undef HAVE_DEVPOLL + +/* Define if your system supports the epoll system calls */ +#undef HAVE_EPOLL + +/* Define if you have the `epoll_ctl' function. */ +#undef HAVE_EPOLL_CTL + +/* Define if you have the `err' function. */ +#undef HAVE_ERR + +/* Define if you have the `fcntl' function. */ +#undef HAVE_FCNTL + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* Define if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define if you have the header file. */ +#undef HAVE_POLL_H + +/* Define if your system supports POSIX realtime signals */ +#undef HAVE_RTSIG + +/* Define if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define if F_SETFD is defined in */ +#undef HAVE_SETFD + +/* Define if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define if you have the `sigtimedwait' function. */ +#undef HAVE_SIGTIMEDWAIT + +/* Define if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#undef HAVE_SYS_DEVPOLL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_EVENT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_QUEUE_H + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if TAILQ_FOREACH is defined in */ +#undef HAVE_TAILQFOREACH + +/* Define if timeradd is defined in */ +#undef HAVE_TIMERADD + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* 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 */ +#define PACKAGE "libevent" + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#define VERSION "1.0b" + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +#define inline __inline + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define to unsigned int if you dont have it */ +#undef socklen_t + +/* Define to `unsigned short' if does not define. */ +#undef u_int16_t + +/* Define to `unsigned int' if does not define. */ +#undef u_int32_t + +/* Define to `unsigned long long' if does not define. */ +/* #undef u_int64_t */ + +/* Define to `unsigned char' if does not define. */ +/* #undef u_int8_t */ + +/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */ +#define __func__ __FUNCTION__ Added: trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.c =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +/**************************************************************************** + * + * Function: gettimeofday(struct timeval *, struct timezone *) + * + * Purpose: Get current time of day. + * + * Arguments: tv => Place to store the curent time of day. + * tz => Ignored. + * + * Returns: 0 => Success. + * + ****************************************************************************/ + +int gettimeofday(struct timeval *tv, struct timezone *tz) { + struct _timeb tb; + + if(tv == NULL) + return -1; + + _ftime(&tb); + tv->tv_sec = tb.time; + 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 Added: trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.h =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Code/misc.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,6 @@ +#ifndef MISC_H +#define MISC_H + +int gettimeofday(struct timeval *,struct timezone *); + +#endif Added: trunk/varnish-cache/contrib/libevent/WIN32-Code/provos at badschwartau.provos.org.12766 =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Code/provos at badschwartau.provos.org.12766 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Code/provos at badschwartau.provos.org.12766 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1 @@ +link provos at badschwartau.provos.org.12766 \ No newline at end of file Property changes on: trunk/varnish-cache/contrib/libevent/WIN32-Code/provos at badschwartau.provos.org.12766 ___________________________________________________________________ Name: svn:special + * Added: trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,406 @@ +/* + * Copyright 2000-2002 Niels Provos + * Copyright 2003 Michael A. Davis + * 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. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "event.h" +#include "event-internal.h" + +#define XFREE(ptr) do { if (ptr) free(ptr); } while(0) + +extern struct event_list timequeue; +extern struct event_list addqueue; +extern struct event_list signalqueue; + +struct win_fd_set { + u_int fd_count; + SOCKET fd_array[1]; +}; + +int evsigcaught[NSIG]; +volatile sig_atomic_t signal_caught = 0; +/* MSDN says this is required to handle SIGFPE */ +volatile double SIGFPE_REQ = 0.0f; + +int signal_handler(int sig); +void signal_process(void); +int signal_recalc(void); + +struct win32op { + int fd_setsz; + struct win_fd_set *readset_in; + struct win_fd_set *writeset_in; + struct win_fd_set *readset_out; + struct win_fd_set *writeset_out; + struct win_fd_set *exset_out; + int n_events; + int n_events_alloc; + struct event **events; +}; + +void *win32_init (void); +int win32_insert (void *, struct event *); +int win32_del (void *, struct event *); +int win32_recalc (struct event_base *base, void *, int); +int win32_dispatch (struct event_base *base, void *, struct timeval *); + +struct eventop win32ops = { + "win32", + win32_init, + win32_insert, + win32_del, + win32_recalc, + win32_dispatch +}; + +#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET))) + +static int +realloc_fd_sets(struct win32op *op, size_t new_size) +{ + size_t size; + + assert(new_size >= op->readset_in->fd_count && + new_size >= op->writeset_in->fd_count); + assert(new_size >= 1); + + size = FD_SET_ALLOC_SIZE(new_size); + if (!(op->readset_in = realloc(op->readset_in, size))) + return (-1); + if (!(op->writeset_in = realloc(op->writeset_in, size))) + return (-1); + if (!(op->readset_out = realloc(op->readset_out, size))) + return (-1); + if (!(op->exset_out = realloc(op->exset_out, size))) + return (-1); + if (!(op->writeset_out = realloc(op->writeset_out, size))) + return (-1); + op->fd_setsz = new_size; + return (0); +} + +static int +timeval_to_ms(struct timeval *tv) +{ + return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000)); +} + +static int +do_fd_set(struct win32op *op, SOCKET s, int read) +{ + unsigned int i; + struct win_fd_set *set = read ? op->readset_in : op->writeset_in; + for (i=0;ifd_count;++i) { + if (set->fd_array[i]==s) + return (0); + } + if (set->fd_count == op->fd_setsz) { + if (realloc_fd_sets(op, op->fd_setsz*2)) + return (-1); + } + set->fd_array[set->fd_count] = s; + return (set->fd_count++); +} + +static int +do_fd_clear(struct win32op *op, SOCKET s, int read) +{ + unsigned int i; + struct win_fd_set *set = read ? op->readset_in : op->writeset_in; + for (i=0;ifd_count;++i) { + if (set->fd_array[i]==s) { + if (--set->fd_count != i) { + set->fd_array[i] = set->fd_array[set->fd_count]; + } + return (0); + } + } + return (0); +} + +#define NEVENT 64 +void * +win32_init(void) +{ + struct win32op *winop; + size_t size; + if (!(winop = calloc(1, sizeof(struct win32op)))) + return NULL; + winop->fd_setsz = NEVENT; + size = FD_SET_ALLOC_SIZE(NEVENT); + if (!(winop->readset_in = malloc(size))) + goto err; + if (!(winop->writeset_in = malloc(size))) + goto err; + if (!(winop->readset_out = malloc(size))) + goto err; + if (!(winop->writeset_out = malloc(size))) + goto err; + if (!(winop->exset_out = malloc(size))) + goto err; + winop->n_events = 0; + winop->n_events_alloc = NEVENT; + if (!(winop->events = malloc(NEVENT*sizeof(struct event*)))) + goto err; + winop->readset_in->fd_count = winop->writeset_in->fd_count = 0; + winop->readset_out->fd_count = winop->writeset_out->fd_count + = winop->exset_out->fd_count = 0; + + return (winop); + err: + XFREE(winop->readset_in); + XFREE(winop->writeset_in); + XFREE(winop->readset_out); + XFREE(winop->writeset_out); + XFREE(winop->exset_out); + XFREE(winop->events); + XFREE(winop); + return (NULL); +} + +int +win32_recalc(struct event_base *base, void *arg, int max) +{ + return (signal_recalc()); +} + +int +win32_insert(struct win32op *win32op, struct event *ev) +{ + int i; + + if (ev->ev_events & EV_SIGNAL) { + if (ev->ev_events & (EV_READ|EV_WRITE)) + event_errx(1, "%s: EV_SIGNAL incompatible use", + __func__); + if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) + return (-1); + + return (0); + } + if (!(ev->ev_events & (EV_READ|EV_WRITE))) + return (0); + + for (i=0;in_events;++i) { + if(win32op->events[i] == ev) { + event_debug(("%s: Event for %d already inserted.", + __func__, (int)ev->ev_fd)); + return (0); + } + } + event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd)); + if (ev->ev_events & EV_READ) { + if (do_fd_set(win32op, ev->ev_fd, 1)<0) + return (-1); + } + if (ev->ev_events & EV_WRITE) { + if (do_fd_set(win32op, ev->ev_fd, 0)<0) + return (-1); + } + + if (win32op->n_events_alloc == win32op->n_events) { + size_t sz; + win32op->n_events_alloc *= 2; + sz = sizeof(struct event*)*win32op->n_events_alloc; + if (!(win32op->events = realloc(win32op->events, sz))) + return (-1); + } + win32op->events[win32op->n_events++] = ev; + + return (0); +} + +int +win32_del(struct win32op *win32op, struct event *ev) +{ + int i, found; + + if (ev->ev_events & EV_SIGNAL) + return ((int)signal(EVENT_SIGNAL(ev), SIG_IGN)); + + found = -1; + for (i=0;in_events;++i) { + if(win32op->events[i] == ev) { + found = i; + break; + } + } + if (found < 0) { + event_debug(("%s: Unable to remove non-inserted event for %d", + __func__, ev->ev_fd)); + return (-1); + } + event_debug(("%s: Removing event for %d", __func__, ev->ev_fd)); + if (ev->ev_events & EV_READ) + do_fd_clear(win32op, ev->ev_fd, 1); + if (ev->ev_events & EV_WRITE) + do_fd_clear(win32op, ev->ev_fd, 0); + + if (i != --win32op->n_events) { + win32op->events[i] = win32op->events[win32op->n_events]; + } + + return 0; +} + +static void +fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in) +{ + out->fd_count = in->fd_count; + memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET))); +} + +/* + static void dump_fd_set(struct win_fd_set *s) + { + unsigned int i; + printf("[ "); + for(i=0;ifd_count;++i) + printf("%d ",(int)s->fd_array[i]); + printf("]\n"); + } +*/ + +int +win32_dispatch(struct event_base *base, struct win32op *win32op, + struct timeval *tv) +{ + int res = 0; + int i; + int fd_count; + + fd_set_copy(win32op->readset_out, win32op->readset_in); + fd_set_copy(win32op->exset_out, win32op->readset_in); + fd_set_copy(win32op->writeset_out, win32op->writeset_in); + + fd_count = + (win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ? + win32op->readset_out->fd_count : win32op->writeset_out->fd_count; + + if (!fd_count) { + /* Windows doesn't like you to call select() with no sockets */ + Sleep(timeval_to_ms(tv)); + signal_process(); + return (0); + } + + res = select(fd_count, + (struct fd_set*)win32op->readset_out, + (struct fd_set*)win32op->writeset_out, + (struct fd_set*)win32op->exset_out, tv); + + event_debug(("%s: select returned %d", __func__, res)); + + if(res <= 0) { + signal_process(); + return res; + } + + for (i=0;in_events;++i) { + struct event *ev; + int got = 0; + ev = win32op->events[i]; + if ((ev->ev_events & EV_READ)) { + if (FD_ISSET(ev->ev_fd, win32op->readset_out) || + FD_ISSET(ev->ev_fd, win32op->exset_out)) { + got |= EV_READ; + } + } + if ((ev->ev_events & EV_WRITE)) { + if (FD_ISSET(ev->ev_fd, win32op->writeset_out)) { + got |= EV_WRITE; + } + } + if (!got) + continue; + if (!(ev->ev_events & EV_PERSIST)) { + event_del(ev); + } + event_active(ev,got,1); + } + + if (signal_recalc() == -1) + return (-1); + + return (0); +} + + +static int +signal_handler(int sig) +{ + evsigcaught[sig]++; + signal_caught = 1; + + return 0; +} + +int +signal_recalc(void) +{ + struct event *ev; + + /* Reinstall our signal handler. */ + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) + return (-1); + } + return (0); +} + +void +signal_process(void) +{ + struct event *ev; + short ncalls; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + ncalls = evsigcaught[EVENT_SIGNAL(ev)]; + if (ncalls) { + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, EV_SIGNAL, ncalls); + } + } + + memset(evsigcaught, 0, sizeof(evsigcaught)); + signal_caught = 0; +} Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/event_test.dsp =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/event_test.dsp 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/event_test.dsp 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="event_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=event_test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "event_test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "event_test.mak" CFG="event_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "event_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "event_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "event_test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\\" /I "..\..\WIN32-Code" /I "..\..\compat" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "event_test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\WIN32-Code" /I "..\..\compat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "event_test - Win32 Release" +# Name "event_test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\sample\event-test.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/test.txt =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/test.txt 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/event_test/test.txt 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,180 @@ + + Platform SDK: File Storage +ReadFile +The ReadFile function reads data from a file, starting at the position indicated by the file pointer. After the read operation has been completed, the file pointer is adjusted by the number of bytes actually read, unless the file handle is created with the overlapped attribute. If the file handle is created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the read operation. + +This function is designed for both synchronous and asynchronous operation. The ReadFileEx function is designed solely for asynchronous operation. It lets an application perform other processing during a file read operation. + +BOOL ReadFile( + HANDLE hFile, // handle to file + LPVOID lpBuffer, // data buffer + DWORD nNumberOfBytesToRead, // number of bytes to read + LPDWORD lpNumberOfBytesRead, // number of bytes read + LPOVERLAPPED lpOverlapped // overlapped buffer +); +Parameters +hFile +[in] Handle to the file to be read. The file handle must have been created with GENERIC_READ access to the file. +Windows NT/2000/XP: For asynchronous read operations, hFile can be any handle opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept function. + +Windows 95/98/Me: For asynchronous read operations, hFile can be a communications resource opened with the FILE_FLAG_OVERLAPPED flag by CreateFile, or a socket handle returned by socket or accept. You cannot perform asynchronous read operations on mailslots, named pipes, or disk files. + +lpBuffer +[out] Pointer to the buffer that receives the data read from the file. +nNumberOfBytesToRead +[in] Specifies the number of bytes to be read from the file. +lpNumberOfBytesRead +[out] Pointer to the variable that receives the number of bytes read. ReadFile sets this value to zero before doing any work or error checking. If this parameter is zero when ReadFile returns TRUE on a named pipe, the other end of the message-mode pipe called the WriteFile function with nNumberOfBytesToWrite set to zero. +Windows NT/2000/XP: If lpOverlapped is NULL, lpNumberOfBytesRead cannot be NULL. If lpOverlapped is not NULL, lpNumberOfBytesRead can be NULL. If this is an overlapped read operation, you can get the number of bytes read by calling GetOverlappedResult. If hFile is associated with an I/O completion port, you can get the number of bytes read by calling GetQueuedCompletionStatus. + +If I/O completion ports are used and you are using a callback routine to free the memory allocated to the OVERLAPPED structure pointed to by the lpOverlapped parameter, specify NULL as the value of this parameter to avoid a memory corruption problem during the deallocation. This memory corruption problem will cause an invalid number of bytes to be returned in this parameter. + +Windows 95/98/Me: This parameter cannot be NULL. + +lpOverlapped +[in] Pointer to an OVERLAPPED structure. This structure is required if hFile was created with FILE_FLAG_OVERLAPPED. +If hFile was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure. If hFile was created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the read operation is complete. + +If hFile was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the read operation starts at the offset specified in the OVERLAPPED structure and ReadFile may return before the read operation has been completed. In this case, ReadFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING. This allows the calling process to continue while the read operation finishes. The event specified in the OVERLAPPED structure is set to the signaled state upon completion of the read operation. + +If hFile was not opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the read operation starts at the current file position and ReadFile does not return until the operation has been completed. + +Windows NT/2000/XP: If hFile is not opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the read operation starts at the offset specified in the OVERLAPPED structure. ReadFile does not return until the read operation has been completed. + +Windows 95/98/Me: For operations on files, disks, pipes, or mailslots, this parameter must be NULL; a pointer to an OVERLAPPED structure causes the call to fail. However, Windows 95/98/Me supports overlapped I/O on serial and parallel ports. + +Return Values +The ReadFile function returns when one of the following is true: a write operation completes on the write end of the pipe, the number of bytes requested has been read, or an error occurs. + +If the function succeeds, the return value is nonzero. + +If the return value is nonzero and the number of bytes read is zero, the file pointer was beyond the current end of the file at the time of the read operation. However, if the file was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the return value is FALSE and GetLastError returns ERROR_HANDLE_EOF when the file pointer goes beyond the current end of file. + +If the function fails, the return value is zero. To get extended error information, call GetLastError. + +Remarks +If part of the file is locked by another process and the read operation overlaps the locked portion, this function fails. + +An application must meet certain requirements when working with files opened with FILE_FLAG_NO_BUFFERING: + +File access must begin at byte offsets within the file that are integer multiples of the volume's sector size. To determine a volume's sector size, call the GetDiskFreeSpace function. +File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes. +Buffer addresses for read and write operations must be sector aligned (aligned on addresses in memory that are integer multiples of the volume's sector size). One way to sector align buffers is to use the VirtualAlloc function to allocate the buffers. This function allocates memory that is aligned on addresses that are integer multiples of the system's page size. Because both page and volume sector sizes are powers of 2, memory aligned by multiples of the system's page size is also aligned by multiples of the volume's sector size. +Accessing the input buffer while a read operation is using the buffer may lead to corruption of the data read into that buffer. Applications must not read from, write to, reallocate, or free the input buffer that a read operation is using until the read operation completes. + +Characters can be read from the console input buffer by using ReadFile with a handle to console input. The console mode determines the exact behavior of the ReadFile function. + +If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message may be read by a subsequent call to the ReadFile or PeekNamedPipe function. + +When reading from a communications device, the behavior of ReadFile is governed by the current communication time-outs as set and retrieved using the SetCommTimeouts and GetCommTimeouts functions. Unpredictable results can occur if you fail to set the time-out values. For more information about communication time-outs, see COMMTIMEOUTS. + +If ReadFile attempts to read from a mailslot whose buffer is too small, the function returns FALSE and GetLastError returns ERROR_INSUFFICIENT_BUFFER. + +If the anonymous write pipe handle has been closed and ReadFile attempts to read using the corresponding anonymous read pipe handle, the function returns FALSE and GetLastError returns ERROR_BROKEN_PIPE. + +The ReadFile function may fail and return ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding asynchronous I/O requests. + +The ReadFile code to check for the end-of-file condition (eof) differs for synchronous and asynchronous read operations. + +When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero. The following sample code tests for end-of-file for a synchronous read operation: + +// Attempt a synchronous read operation. +bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL) ; +// Check for end of file. +if (bResult && nBytesRead == 0, ) +{ + // we're at the end of the file +} +An asynchronous read operation can encounter the end of a file during the initiating call to ReadFile, or during subsequent asynchronous operation. + +If EOF is detected at ReadFile time for an asynchronous read operation, ReadFile returns FALSE and GetLastError returns ERROR_HANDLE_EOF. + +If EOF is detected during subsequent asynchronous operation, the call to GetOverlappedResult to obtain the results of that operation returns FALSE and GetLastError returns ERROR_HANDLE_EOF. + +To cancel all pending asynchronous I/O operations, use the CancelIo function. This function only cancels operations issued by the calling thread for the specified file handle. I/O operations that are canceled complete with the error ERROR_OPERATION_ABORTED. + +If you are attempting to read from a floppy drive that does not have a floppy disk, the system displays a message box prompting the user to retry the operation. To prevent the system from displaying this message box, call the SetErrorMode function with SEM_NOOPENFILEERRORBOX. + +The following sample code illustrates testing for end-of-file for an asynchronous read operation: + +// set up overlapped structure fields +gOverLapped.Offset = 0; +gOverLapped.OffsetHigh = 0; +gOverLapped.hEvent = hEvent; + +// attempt an asynchronous read operation +bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, + &gOverlapped) ; + +// if there was a problem, or the async. operation's still pending ... +if (!bResult) +{ + // deal with the error code + switch (dwError = GetLastError()) + { + case ERROR_HANDLE_EOF: + { + // we have reached the end of the file + // during the call to ReadFile + + // code to handle that + } + + case ERROR_IO_PENDING: + { + // asynchronous i/o is still in progress + + // do something else for a while + GoDoSomethingElse() ; + + // check on the results of the asynchronous read + bResult = GetOverlappedResult(hFile, &gOverlapped, + &nBytesRead, FALSE) ; + + // if there was a problem ... + if (!bResult) + { + // deal with the error code + switch (dwError = GetLastError()) + { + case ERROR_HANDLE_EOF: + { + // we have reached the end of + // the file during asynchronous + // operation + } + + // deal with other error cases + } + } + } // end case + + // deal with other error cases + + } // end switch +} // end if +Example Code +For an example, see Reading, Writing, and Locking Files. + +Requirements + Windows NT/2000/XP: Included in Windows NT 3.1 and later. + Windows 95/98/Me: Included in Windows 95 and later. + Header: Declared in Winbase.h; include Windows.h. + Library: Use Kernel32.lib. + +See Also +File I/O Overview, File I/O Functions, CancelIo, CreateFile, GetCommTimeouts, GetOverlappedResult, GetQueuedCompletionStatus, OVERLAPPED, PeekNamedPipe, ReadFileEx, SetCommTimeouts, SetErrorMode, WriteFile + +Platform SDK Release: November 2001 What did you think of this topic? +Let us know. Order a Platform SDK CD Online +(U.S/Canada) (International) + + + +Requirements + Windows NT/2000/XP: Included in Windows NT 3.1 and later. + Windows 95/98/Me: Included in Windows 95 and later. + Header: Declared in Winbase.h; include Windows.h. + Library: Use Kernel32.lib. +See Also +File I/O Overview, File I/O Functions, CancelIo, CreateFile, GetCommTimeouts, GetOverlappedResult, GetQueuedCompletionStatus, OVERLAPPED, PeekNamedPipe, ReadFileEx, SetCommTimeouts, SetErrorMode, WriteFile Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,128 @@ +# Microsoft Developer Studio Project File - Name="libevent" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libevent - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libevent.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libevent.mak" CFG="libevent - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libevent - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libevent - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libevent - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\\" /I "..\WIN32-Code" /I "..\compat" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libevent - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\WIN32-Code" /I "..\compat" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libevent - Win32 Release" +# Name "libevent - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\err.c +# End Source File +# Begin Source File + +SOURCE=..\event.c +# End Source File +# Begin Source File + +SOURCE="..\WIN32-Code\misc.c" +# End Source File +# Begin Source File + +SOURCE="..\WIN32-Code\win32.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\acconfig.h +# End Source File +# Begin Source File + +SOURCE="..\WIN32-Code\config.h" +# End Source File +# Begin Source File + +SOURCE=..\compat\err.h +# End Source File +# Begin Source File + +SOURCE=..\event.h +# End Source File +# Begin Source File + +SOURCE="..\WIN32-Code\misc.h" +# End Source File +# End Group +# End Target +# End Project Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsw =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsw 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsw 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,74 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "event_test"=".\event_test\event_test.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libevent + End Project Dependency +}}} + +############################################################################### + +Project: "libevent"=".\libevent.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "signal_test"=".\signal_test\signal_test.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libevent + End Project Dependency +}}} + +############################################################################### + +Project: "time_test"=".\time_test\time_test.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libevent + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/signal_test/signal_test.dsp =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/signal_test/signal_test.dsp 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/signal_test/signal_test.dsp 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="signal_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=signal_test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "signal_test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "signal_test.mak" CFG="signal_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "signal_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "signal_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "signal_test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "signal_test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\WIN32-Code" /I "..\..\compat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "signal_test - Win32 Release" +# Name "signal_test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\sample\signal-test.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project Added: trunk/varnish-cache/contrib/libevent/WIN32-Prj/time_test/time_test.dsp =================================================================== --- trunk/varnish-cache/contrib/libevent/WIN32-Prj/time_test/time_test.dsp 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/time_test/time_test.dsp 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="time_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=time_test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "time_test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "time_test.mak" CFG="time_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "time_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "time_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "time_test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "time_test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\WIN32-Code" /I "..\..\compat" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "time_test - Win32 Release" +# Name "time_test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\sample\time-test.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project Added: trunk/varnish-cache/contrib/libevent/acconfig.h =================================================================== --- trunk/varnish-cache/contrib/libevent/acconfig.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/acconfig.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,79 @@ +/* Define if kqueue works correctly with pipes */ +#undef HAVE_WORKING_KQUEUE + +/* Define to `unsigned long long' if doesn't define. */ +#undef u_int64_t + +/* Define to `unsigned int' if doesn't define. */ +#undef u_int32_t + +/* Define to `unsigned short' if doesn't define. */ +#undef u_int16_t + +/* Define to `unsigned char' if doesn't define. */ +#undef u_int8_t + +/* Define if timeradd is defined in */ +#undef HAVE_TIMERADD +#ifndef HAVE_TIMERADD +#undef timersub +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* !HAVE_TIMERADD */ + +#undef HAVE_TIMERCLEAR +#ifndef HAVE_TIMERCLEAR +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif + +#undef HAVE_TIMERCMP +#ifndef HAVE_TIMERCMP +#undef timercmp +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#endif + +#undef HAVE_TIMERISSET +#ifndef HAVE_TIMERISSET +#undef timerisset +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + +/* Define if TAILQ_FOREACH is defined in */ +#undef HAVE_TAILQFOREACH +#ifndef HAVE_TAILQFOREACH +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) +#endif /* TAILQ_FOREACH */ + +/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */ +#undef __func__ Added: trunk/varnish-cache/contrib/libevent/buffer.c =================================================================== --- trunk/varnish-cache/contrib/libevent/buffer.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/buffer.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2002, 2003 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_VASPRINTF +/* If we have vasprintf, we need to define this before we include stdio.h. */ +#define _GNU_SOURCE +#endif + +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "event.h" + +struct evbuffer * +evbuffer_new(void) +{ + struct evbuffer *buffer; + + buffer = calloc(1, sizeof(struct evbuffer)); + + return (buffer); +} + +void +evbuffer_free(struct evbuffer *buffer) +{ + if (buffer->orig_buffer != NULL) + free(buffer->orig_buffer); + free(buffer); +} + +/* + * This is a destructive add. The data from one buffer moves into + * 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); + + return (res); +} + +int +evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...) +{ + int res = -1; + char *msg; +#ifndef HAVE_VASPRINTF + static char buffer[4096]; +#endif + va_list ap; + + va_start(ap, fmt); + +#ifdef HAVE_VASPRINTF + if (vasprintf(&msg, fmt, ap) == -1) + goto end; +#else +# ifdef WIN32 + _vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap); + buffer[sizeof(buffer)-1] = '\0'; +# else /* ! WIN32 */ + vsnprintf(buffer, sizeof(buffer), fmt, ap); +# endif + msg = buffer; +#endif + + res = strlen(msg); + if (evbuffer_add(buf, msg, res) == -1) + res = -1; +#ifdef HAVE_VASPRINTF + free(msg); + +end: +#endif + va_end(ap); + + return (res); +} + +/* Reads data from an event buffer and drains the bytes read */ + +int +evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) +{ + size_t nread = datlen; + if (nread >= buf->off) + nread = buf->off; + + memcpy(data, buf->buffer, nread); + evbuffer_drain(buf, nread); + + return (nread); +} + +/* + * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. + * The returned buffer needs to be freed by the called. + */ + +char * +evbuffer_readline(struct evbuffer *buffer) +{ + char *data = EVBUFFER_DATA(buffer); + size_t len = EVBUFFER_LENGTH(buffer); + char *line; + int i; + + for (i = 0; i < len; i++) { + if (data[i] == '\r' || data[i] == '\n') + break; + } + + if (i == len) + return (NULL); + + if ((line = malloc(i + 1)) == NULL) { + fprintf(stderr, "%s: out of memory\n", __func__); + evbuffer_drain(buffer, i); + return (NULL); + } + + memcpy(line, data, i); + line[i] = '\0'; + + /* + * Some protocols terminate a line with '\r\n', so check for + * that, too. + */ + if ( i < len - 1 ) { + char fch = data[i], sch = data[i+1]; + + /* Drain one more character if needed */ + if ( (sch == '\r' || sch == '\n') && sch != fch ) + i += 1; + } + + evbuffer_drain(buffer, i + 1); + + return (line); +} + +/* Adds data to an event buffer */ + +static inline void +evbuffer_align(struct evbuffer *buf) +{ + memmove(buf->orig_buffer, buf->buffer, buf->off); + buf->buffer = buf->orig_buffer; + buf->misalign = 0; +} + +/* Expands the available space in the event buffer to at least datlen */ + +int +evbuffer_expand(struct evbuffer *buf, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + + /* If we can fit all the data, then we don't have to do anything */ + if (buf->totallen >= need) + return (0); + + /* + * If the misalignment fulfills our data needs, we just force an + * alignment to happen. Afterwards, we have enough space. + */ + 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; + } + + return (0); +} + +int +evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + size_t oldoff = buf->off; + + if (buf->totallen < need) { + if (evbuffer_expand(buf, datlen) == -1) + return (-1); + } + + memcpy(buf->buffer + buf->off, data, datlen); + buf->off += datlen; + + if (datlen && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + + return (0); +} + +void +evbuffer_drain(struct evbuffer *buf, size_t len) +{ + size_t oldoff = buf->off; + + if (len >= buf->off) { + buf->off = 0; + buf->buffer = buf->orig_buffer; + buf->misalign = 0; + goto done; + } + + buf->buffer += len; + buf->misalign += len; + + buf->off -= len; + + done: + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + +} + +/* + * Reads data from a file descriptor into a buffer. + */ + +#define EVBUFFER_MAX_READ 4096 + +int +evbuffer_read(struct evbuffer *buf, int fd, int howmuch) +{ + u_char *p; + size_t oldoff = buf->off; + int n = EVBUFFER_MAX_READ; +#ifdef WIN32 + DWORD dwBytesRead; +#endif + +#ifdef FIONREAD + if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) + n = EVBUFFER_MAX_READ; +#endif + if (howmuch < 0 || howmuch > n) + howmuch = n; + + /* If we don't have FIONREAD, we might waste some space here */ + if (evbuffer_expand(buf, howmuch) == -1) + return (-1); + + /* We can append new data at this point */ + p = buf->buffer + buf->off; + +#ifndef WIN32 + n = read(fd, p, howmuch); + if (n == -1) + return (-1); + if (n == 0) + return (0); +#else + n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); + if (n == 0) + return (-1); + if (dwBytesRead == 0) + return (0); + n = dwBytesRead; +#endif + + buf->off += n; + + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + + return (n); +} + +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); +} + +u_char * +evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len) +{ + size_t remain = buffer->off; + u_char *search = buffer->buffer; + u_char *p; + + while ((p = memchr(search, *what, remain)) != NULL && remain >= len) { + if (memcmp(p, what, len) == 0) + return (p); + + search = p + 1; + remain = buffer->off - (size_t)(search - buffer->buffer); + } + + return (NULL); +} + +void evbuffer_setcb(struct evbuffer *buffer, + void (*cb)(struct evbuffer *, size_t, size_t, void *), + void *cbarg) +{ + buffer->cb = cb; + buffer->cbarg = cbarg; +} Added: trunk/varnish-cache/contrib/libevent/compat/sys/_time.h =================================================================== --- trunk/varnish-cache/contrib/libevent/compat/sys/_time.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/compat/sys/_time.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,163 @@ +/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */ +/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)time.h 8.2 (Berkeley) 7/10/94 + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; + +/* + * Structure defined by POSIX.1b to be like a timeval. + */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; + +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ + +/* Operations on timevals. */ +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +/* Operations on timespecs. */ +#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0 +#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec) +#define timespeccmp(tsp, usp, cmp) \ + (((tsp)->tv_sec == (usp)->tv_sec) ? \ + ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ + ((tsp)->tv_sec cmp (usp)->tv_sec)) +#define timespecadd(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ + if ((vsp)->tv_nsec >= 1000000000L) { \ + (vsp)->tv_sec++; \ + (vsp)->tv_nsec -= 1000000000L; \ + } \ + } while (0) +#define timespecsub(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ + } while (0) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +/* + * Getkerninfo clock information structure + */ +struct clockinfo { + int hz; /* clock frequency */ + int tick; /* micro-seconds per hz tick */ + int tickadj; /* clock skew rate for adjtime() */ + int stathz; /* statistics clock frequency */ + int profhz; /* profiling clock frequency */ +}; + +#define CLOCK_REALTIME 0 +#define CLOCK_VIRTUAL 1 +#define CLOCK_PROF 2 + +#define TIMER_RELTIME 0x0 /* relative timer */ +#define TIMER_ABSTIME 0x1 /* absolute timer */ + +/* --- stuff got cut here - niels --- */ + +#endif /* !_SYS_TIME_H_ */ Added: trunk/varnish-cache/contrib/libevent/compat/sys/queue.h =================================================================== --- trunk/varnish-cache/contrib/libevent/compat/sys/queue.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/compat/sys/queue.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,488 @@ +/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#ifndef WIN32 +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} +#endif + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ Added: trunk/varnish-cache/contrib/libevent/compat/sys/tree.h =================================================================== --- trunk/varnish-cache/contrib/libevent/compat/sys/tree.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/compat/sys/tree.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,677 @@ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * 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. + * + * 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. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-back tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#endif /* _SYS_TREE_H_ */ Added: trunk/varnish-cache/contrib/libevent/configure.in =================================================================== --- trunk/varnish-cache/contrib/libevent/configure.in 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/configure.in 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,341 @@ +dnl configure.in for libevent +dnl Dug Song +AC_INIT(event.c) + +AM_INIT_AUTOMAKE(libevent,1.1a) +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE + +dnl Initialize prefix. +if test "$prefix" = "NONE"; then + prefix="/usr/local" +fi + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S + +AC_PROG_GCC_TRADITIONAL +if test "$GCC" = yes ; then + CFLAGS="$CFLAGS -Wall" +fi + +AC_PROG_LIBTOOL + +dnl Uncomment "AC_DISABLE_SHARED" to make shared librraries not get +dnl built by default. You can also turn shared libs on and off from +dnl the command line with --enable-shared and --disable-shared. +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) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/ioctl.h sys/devpoll.h) +if test "x$ac_cv_header_sys_queue_h" = "xyes"; then + AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) + AC_EGREP_CPP(yes, +[ +#include +#ifdef TAILQ_FOREACH + yes +#endif +], [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TAILQFOREACH, 1, + [Define if TAILQ_FOREACH is defined in ])], + AC_MSG_RESULT(no) + ) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timeradd in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include +#ifdef timeradd + yes +#endif +], [ AC_DEFINE(HAVE_TIMERADD, 1, + [Define if timeradd is defined in ]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timercmp in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include +#ifdef timercmp + yes +#endif +], [ AC_DEFINE(HAVE_TIMERCMP, 1, + [Define if timercmp is defined in ]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timerclear in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include +#ifdef timerclear + yes +#endif +], [ AC_DEFINE(HAVE_TIMERCLEAR, 1, + [Define if timerclear is defined in ]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timerisset in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include +#ifdef timerisset + yes +#endif +], [ AC_DEFINE(HAVE_TIMERISSET, 1, + [Define if timerisset is defined in ]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME + +dnl Checks for library functions. +AC_CHECK_FUNCS(gettimeofday vasprintf fcntl) + +AC_MSG_CHECKING(for F_SETFD in fcntl.h) +AC_EGREP_CPP(yes, +[ +#define _GNU_SOURCE +#include +#ifdef F_SETFD +yes +#endif +], [ AC_DEFINE(HAVE_SETFD, 1, + [Define if F_SETFD is defined in ]) + AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no)) + +needsignal=no +haveselect=no +AC_CHECK_FUNCS(select, [haveselect=yes], ) +if test "x$haveselect" = "xyes" ; then + AC_LIBOBJ(select) + needsignal=yes +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 +AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], ) +if test "x$haveepoll" = "xyes" ; then + AC_DEFINE(HAVE_EPOLL, 1, + [Define if your system supports the epoll system calls]) + AC_LIBOBJ(epoll) + needsignal=yes +fi + +havedevpoll=no +if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then + AC_DEFINE(HAVE_DEVPOLL, 1, + [Define if /dev/poll is available]) + AC_LIBOBJ(devpoll) +fi + +havekqueue=no +if test "x$ac_cv_header_sys_event_h" = "xyes"; then + AC_CHECK_FUNCS(kqueue, [havekqueue=yes], ) + if test "x$havekqueue" = "xyes" ; then + AC_MSG_CHECKING(for working kqueue) + AC_TRY_RUN( +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int kq; + int n; + int fd[[2]]; + struct kevent ev; + struct timespec ts; + char buf[[8000]]; + + if (pipe(fd) == -1) + exit(1); + if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1) + exit(1); + + while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf)) + ; + + if ((kq = kqueue()) == -1) + exit(1); + + ev.ident = fd[[1]]; + ev.filter = EVFILT_WRITE; + ev.flags = EV_ADD | EV_ENABLE; + n = kevent(kq, &ev, 1, NULL, 0, NULL); + if (n == -1) + exit(1); + + read(fd[[0]], buf, sizeof(buf)); + + ts.tv_sec = 0; + ts.tv_nsec = 0; + n = kevent(kq, NULL, 0, &ev, 1, &ts); + if (n == -1 || n == 0) + exit(1); + + exit(0); +}, [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_WORKING_KQUEUE, 1, + [Define if kqueue works correctly with pipes]) + AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) + fi +fi + +haveepollsyscall=no +if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then + if test "x$haveepoll" = "xno" ; then + AC_MSG_CHECKING(for epoll system call) + AC_TRY_RUN( +#include +#include +#include +#include +#include +#include + +int +epoll_create(int size) +{ + return (syscall(__NR_epoll_create, size)); +} + +int +main(int argc, char **argv) +{ + int epfd; + + epfd = epoll_create(256); + exit (epfd == -1 ? 1 : 0); +}, [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_EPOLL, 1, + [Define if your system supports the epoll system calls]) + needsignal=yes + AC_LIBOBJ(epoll_sub) + AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) + fi +fi + +if test "x$needsignal" = "xyes" ; then + AC_LIBOBJ(signal) +fi + +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_TYPE(u_int64_t, unsigned long long) +AC_CHECK_TYPE(u_int32_t, unsigned int) +AC_CHECK_TYPE(u_int16_t, unsigned short) +AC_CHECK_TYPE(u_int8_t, unsigned char) + +AC_MSG_CHECKING([for socklen_t]) +AC_TRY_COMPILE([ + #include + #include ], + [socklen_t x;], + AC_MSG_RESULT([yes]), + [AC_MSG_RESULT([no]) + AC_DEFINE(socklen_t, unsigned int, + [Define to unsigned int if you dont have it])] +) + +AC_MSG_CHECKING([whether our compiler supports __func__]) +AC_TRY_COMPILE([], + [void foo() { const char *cp = __func__; }], + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([whether our compiler supports __FUNCTION__]) + AC_TRY_COMPILE([], + [void foo() { const char *cp = __FUNCTION__; }], + AC_MSG_RESULT([yes]) + AC_DEFINE(__func__, __FUNCTION__, + [Define to appropriate substitue if compiler doesnt have __func__]), + AC_MSG_RESULT([no]) + AC_DEFINE(__func__, __FILE__, + [Define to appropriate substitue if compiler doesnt have __func__]))) + +AC_OUTPUT(Makefile test/Makefile sample/Makefile) Added: trunk/varnish-cache/contrib/libevent/devpoll.c =================================================================== --- trunk/varnish-cache/contrib/libevent/devpoll.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/devpoll.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,403 @@ +/* + * Copyright 2000-2004 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "event.h" +#include "evsignal.h" +#include "log.h" + +extern volatile sig_atomic_t evsignal_caught; + +/* due to limitations in the devpoll interface, we need to keep track of + * all file descriptors outself. + */ +struct evdevpoll { + struct event *evread; + struct event *evwrite; +}; + +struct devpollop { + struct evdevpoll *fds; + int nfds; + struct pollfd *events; + int nevents; + int dpfd; + sigset_t evsigmask; + struct pollfd *changes; + int nchanges; +}; + +void *devpoll_init (void); +int devpoll_add (void *, struct event *); +int devpoll_del (void *, struct event *); +int devpoll_recalc (struct event_base *, void *, int); +int devpoll_dispatch (struct event_base *, void *, struct timeval *); + +struct eventop devpollops = { + "devpoll", + devpoll_init, + devpoll_add, + devpoll_del, + devpoll_recalc, + devpoll_dispatch +}; + +#define NEVENT 32000 + +static int +devpoll_commit(struct devpollop *devpollop) +{ + /* + * Due to a bug in Solaris, we have to use pwrite with an offset of 0. + * Write is limited to 2GB of data, until it will fail. + */ + if (pwrite(devpollop->dpfd, devpollop->changes, + sizeof(struct pollfd) * devpollop->nchanges, 0) == -1) + return(-1); + + devpollop->nchanges = 0; + return(0); +} + +static int +devpoll_queue(struct devpollop *devpollop, int fd, int events) { + struct pollfd *pfd; + + if (devpollop->nchanges >= devpollop->nevents) { + /* + * Change buffer is full, must commit it to /dev/poll before + * adding more + */ + if (devpoll_commit(devpollop) != 0) + return(-1); + } + + pfd = &devpollop->changes[devpollop->nchanges++]; + pfd->fd = fd; + pfd->events = events; + pfd->revents = 0; + + return(0); +} + +void * +devpoll_init(void) +{ + int dpfd, nfiles = NEVENT; + struct rlimit rl; + struct devpollop *devpollop; + + /* Disable devpoll when this environment variable is set */ + if (getenv("EVENT_NODEVPOLL")) + return (NULL); + + if (!(devpollop = calloc(1, sizeof(struct devpollop)))) + return (NULL); + + if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && + rl.rlim_cur != RLIM_INFINITY) + nfiles = rl.rlim_cur; + + /* Initialize the kernel queue */ + if ((dpfd = open("/dev/poll", O_RDWR)) == -1) { + event_warn("open: /dev/poll"); + free(devpollop); + return (NULL); + } + + devpollop->dpfd = dpfd; + + /* Initialize fields */ + devpollop->events = calloc(nfiles, sizeof(struct pollfd)); + if (devpollop->events == NULL) { + free(devpollop); + close(dpfd); + return (NULL); + } + devpollop->nevents = nfiles; + + devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll)); + if (devpollop->fds == NULL) { + free(devpollop->events); + free(devpollop); + close(dpfd); + return (NULL); + } + devpollop->nfds = nfiles; + + devpollop->changes = calloc(nfiles, sizeof(struct pollfd)); + if (devpollop->changes == NULL) { + free(devpollop->fds); + free(devpollop->events); + free(devpollop); + close(dpfd); + return (NULL); + } + + evsignal_init(&devpollop->evsigmask); + + return (devpollop); +} + +int +devpoll_recalc(struct event_base *base, void *arg, int max) +{ + struct devpollop *devpollop = arg; + + if (max > devpollop->nfds) { + struct evdevpoll *fds; + int nfds; + + nfds = devpollop->nfds; + while (nfds < max) + nfds <<= 1; + + fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll)); + if (fds == NULL) { + event_warn("realloc"); + return (-1); + } + devpollop->fds = fds; + memset(fds + devpollop->nfds, 0, + (nfds - devpollop->nfds) * sizeof(struct evdevpoll)); + devpollop->nfds = nfds; + } + + return (evsignal_recalc(&devpollop->evsigmask)); +} + +int +devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + struct devpollop *devpollop = arg; + struct pollfd *events = devpollop->events; + struct dvpoll dvp; + struct evdevpoll *evdp; + int i, res, timeout; + + if (evsignal_deliver(&devpollop->evsigmask) == -1) + return (-1); + + if (devpollop->nchanges) + devpoll_commit(devpollop); + + timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + + dvp.dp_fds = devpollop->events; + dvp.dp_nfds = devpollop->nevents; + dvp.dp_timeout = timeout; + + res = ioctl(devpollop->dpfd, DP_POLL, &dvp); + + if (evsignal_recalc(&devpollop->evsigmask) == -1) + return (-1); + + if (res == -1) { + if (errno != EINTR) { + event_warn("ioctl: DP_POLL"); + return (-1); + } + + evsignal_process(); + return (0); + } else if (evsignal_caught) + evsignal_process(); + + event_debug(("%s: devpoll_wait reports %d", __func__, res)); + + for (i = 0; i < res; i++) { + int which = 0; + int what = events[i].revents; + struct event *evread = NULL, *evwrite = NULL; + + assert(events[i].fd < devpollop->nfds); + evdp = &devpollop->fds[events[i].fd]; + + if (what & POLLHUP) + what |= POLLIN | POLLOUT; + else if (what & POLLERR) + what |= POLLIN | POLLOUT; + + if (what & POLLIN) { + evread = evdp->evread; + which |= EV_READ; + } + + if (what & POLLOUT) { + evwrite = evdp->evwrite; + which |= EV_WRITE; + } + + if (!which) + continue; + + if (evread != NULL && !(evread->ev_events & EV_PERSIST)) + event_del(evread); + if (evwrite != NULL && evwrite != evread && + !(evwrite->ev_events & EV_PERSIST)) + event_del(evwrite); + + if (evread != NULL) + event_active(evread, EV_READ, 1); + if (evwrite != NULL) + event_active(evwrite, EV_WRITE, 1); + } + + return (0); +} + + +int +devpoll_add(void *arg, struct event *ev) +{ + struct devpollop *devpollop = arg; + struct evdevpoll *evdp; + int fd, events; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&devpollop->evsigmask, ev)); + + fd = ev->ev_fd; + if (fd >= devpollop->nfds) { + /* Extend the file descriptor array as necessary */ + if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1) + return (-1); + } + evdp = &devpollop->fds[fd]; + + /* + * It's not necessary to OR the existing read/write events that we + * are currently interested in with the new event we are adding. + * The /dev/poll driver ORs any new events with the existing events + * that it has cached for the fd. + */ + + events = 0; + if (ev->ev_events & EV_READ) { + if (evdp->evread && evdp->evread != ev) { + /* There is already a different read event registered */ + return(-1); + } + events |= POLLIN; + } + + if (ev->ev_events & EV_WRITE) { + if (evdp->evwrite && evdp->evwrite != ev) { + /* There is already a different write event registered */ + return(-1); + } + events |= POLLOUT; + } + + if (devpoll_queue(devpollop, fd, events) != 0) + return(-1); + + /* Update events responsible */ + if (ev->ev_events & EV_READ) + evdp->evread = ev; + if (ev->ev_events & EV_WRITE) + evdp->evwrite = ev; + + return (0); +} + +int +devpoll_del(void *arg, struct event *ev) +{ + struct devpollop *devpollop = arg; + struct evdevpoll *evdp; + int fd, events; + int needwritedelete = 1, needreaddelete = 1; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(&devpollop->evsigmask, ev)); + + fd = ev->ev_fd; + if (fd >= devpollop->nfds) + return (0); + evdp = &devpollop->fds[fd]; + + events = 0; + if (ev->ev_events & EV_READ) + events |= POLLIN; + if (ev->ev_events & EV_WRITE) + events |= POLLOUT; + + /* + * The only way to remove an fd from the /dev/poll monitored set is + * to use POLLREMOVE by itself. This removes ALL events for the fd + * provided so if we care about two events and are only removing one + * we must re-add the other event after POLLREMOVE. + */ + + if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0) + return(-1); + + if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) { + /* + * We're not deleting all events, so we must resubmit the + * event that we are still interested in if one exists. + */ + + if ((events & POLLIN) && evdp->evwrite != NULL) { + /* Deleting read, still care about write */ + devpoll_queue(devpollop, fd, POLLOUT); + needwritedelete = 0; + } else if ((events & POLLOUT) && evdp->evread != NULL) { + /* Deleting write, still care about read */ + devpoll_queue(devpollop, fd, POLLIN); + needreaddelete = 0; + } + } + + if (needreaddelete) + evdp->evread = NULL; + if (needwritedelete) + evdp->evwrite = NULL; + + return (0); +} Added: trunk/varnish-cache/contrib/libevent/epoll.c =================================================================== --- trunk/varnish-cache/contrib/libevent/epoll.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/epoll.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,345 @@ +/* + * Copyright 2000-2003 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "event.h" +#include "evsignal.h" +#include "log.h" + +extern volatile sig_atomic_t evsignal_caught; + +/* due to limitations in the epoll interface, we need to keep track of + * all file descriptors outself. + */ +struct evepoll { + struct event *evread; + struct event *evwrite; +}; + +struct epollop { + struct evepoll *fds; + int nfds; + struct epoll_event *events; + int nevents; + int epfd; + sigset_t evsigmask; +}; + +void *epoll_init (void); +int epoll_add (void *, struct event *); +int epoll_del (void *, struct event *); +int epoll_recalc (struct event_base *, void *, int); +int epoll_dispatch (struct event_base *, void *, struct timeval *); + +struct eventop epollops = { + "epoll", + epoll_init, + epoll_add, + epoll_del, + epoll_recalc, + epoll_dispatch +}; + +#ifdef HAVE_SETFD +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + event_warn("fcntl(%d, F_SETFD)", x); \ +} while (0) +#else +#define FD_CLOSEONEXEC(x) +#endif + +#define NEVENT 32000 + +void * +epoll_init(void) +{ + int epfd, nfiles = NEVENT; + struct rlimit rl; + struct epollop *epollop; + + /* Disable epollueue when this environment variable is set */ + if (getenv("EVENT_NOEPOLL")) + return (NULL); + + if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && + rl.rlim_cur != RLIM_INFINITY) + nfiles = rl.rlim_cur; + + /* Initalize the kernel queue */ + + if ((epfd = epoll_create(nfiles)) == -1) { + event_warn("epoll_create"); + return (NULL); + } + + FD_CLOSEONEXEC(epfd); + + if (!(epollop = calloc(1, sizeof(struct epollop)))) + return (NULL); + + epollop->epfd = epfd; + + /* Initalize fields */ + epollop->events = malloc(nfiles * sizeof(struct epoll_event)); + if (epollop->events == NULL) { + free(epollop); + return (NULL); + } + epollop->nevents = nfiles; + + epollop->fds = calloc(nfiles, sizeof(struct evepoll)); + if (epollop->fds == NULL) { + free(epollop->events); + free(epollop); + return (NULL); + } + epollop->nfds = nfiles; + + evsignal_init(&epollop->evsigmask); + + return (epollop); +} + +int +epoll_recalc(struct event_base *base, void *arg, int max) +{ + struct epollop *epollop = arg; + + if (max > epollop->nfds) { + struct evepoll *fds; + int nfds; + + nfds = epollop->nfds; + while (nfds < max) + nfds <<= 1; + + fds = realloc(epollop->fds, nfds * sizeof(struct evepoll)); + if (fds == NULL) { + event_warn("realloc"); + return (-1); + } + epollop->fds = fds; + memset(fds + epollop->nfds, 0, + (nfds - epollop->nfds) * sizeof(struct evepoll)); + epollop->nfds = nfds; + } + + return (evsignal_recalc(&epollop->evsigmask)); +} + +int +epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + struct epollop *epollop = arg; + struct epoll_event *events = epollop->events; + struct evepoll *evep; + int i, res, timeout; + + if (evsignal_deliver(&epollop->evsigmask) == -1) + return (-1); + + timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); + + if (evsignal_recalc(&epollop->evsigmask) == -1) + return (-1); + + if (res == -1) { + if (errno != EINTR) { + event_warn("epoll_wait"); + return (-1); + } + + evsignal_process(); + return (0); + } else if (evsignal_caught) + evsignal_process(); + + event_debug(("%s: epoll_wait reports %d", __func__, res)); + + for (i = 0; i < res; i++) { + int which = 0; + int what = events[i].events; + struct event *evread = NULL, *evwrite = NULL; + + evep = (struct evepoll *)events[i].data.ptr; + + if (what & EPOLLHUP) + what |= EPOLLIN | EPOLLOUT; + else if (what & EPOLLERR) + what |= EPOLLIN | EPOLLOUT; + + if (what & EPOLLIN) { + evread = evep->evread; + which |= EV_READ; + } + + if (what & EPOLLOUT) { + evwrite = evep->evwrite; + which |= EV_WRITE; + } + + if (!which) + continue; + + if (evread != NULL && !(evread->ev_events & EV_PERSIST)) + event_del(evread); + if (evwrite != NULL && evwrite != evread && + !(evwrite->ev_events & EV_PERSIST)) + event_del(evwrite); + + if (evread != NULL) + event_active(evread, EV_READ, 1); + if (evwrite != NULL) + event_active(evwrite, EV_WRITE, 1); + } + + return (0); +} + + +int +epoll_add(void *arg, struct event *ev) +{ + struct epollop *epollop = arg; + struct epoll_event epev = {0, {0}}; + struct evepoll *evep; + int fd, op, events; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&epollop->evsigmask, ev)); + + fd = ev->ev_fd; + if (fd >= epollop->nfds) { + /* Extent the file descriptor array as necessary */ + if (epoll_recalc(ev->ev_base, epollop, fd) == -1) + return (-1); + } + evep = &epollop->fds[fd]; + op = EPOLL_CTL_ADD; + events = 0; + if (evep->evread != NULL) { + events |= EPOLLIN; + op = EPOLL_CTL_MOD; + } + if (evep->evwrite != NULL) { + events |= EPOLLOUT; + op = EPOLL_CTL_MOD; + } + + if (ev->ev_events & EV_READ) + events |= EPOLLIN; + if (ev->ev_events & EV_WRITE) + events |= EPOLLOUT; + + epev.data.ptr = evep; + epev.events = events; + if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1) + return (-1); + + /* Update events responsible */ + if (ev->ev_events & EV_READ) + evep->evread = ev; + if (ev->ev_events & EV_WRITE) + evep->evwrite = ev; + + return (0); +} + +int +epoll_del(void *arg, struct event *ev) +{ + struct epollop *epollop = arg; + struct epoll_event epev = {0, {0}}; + struct evepoll *evep; + int fd, events, op; + int needwritedelete = 1, needreaddelete = 1; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(&epollop->evsigmask, ev)); + + fd = ev->ev_fd; + if (fd >= epollop->nfds) + return (0); + evep = &epollop->fds[fd]; + + op = EPOLL_CTL_DEL; + events = 0; + + if (ev->ev_events & EV_READ) + events |= EPOLLIN; + if (ev->ev_events & EV_WRITE) + events |= EPOLLOUT; + + if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) { + if ((events & EPOLLIN) && evep->evwrite != NULL) { + needwritedelete = 0; + events = EPOLLOUT; + op = EPOLL_CTL_MOD; + } else if ((events & EPOLLOUT) && evep->evread != NULL) { + needreaddelete = 0; + events = EPOLLIN; + op = EPOLL_CTL_MOD; + } + } + + epev.events = events; + epev.data.ptr = evep; + + if (needreaddelete) + evep->evread = NULL; + if (needwritedelete) + evep->evwrite = NULL; + + if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1) + return (-1); + + return (0); +} Added: trunk/varnish-cache/contrib/libevent/epoll_sub.c =================================================================== --- trunk/varnish-cache/contrib/libevent/epoll_sub.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/epoll_sub.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,52 @@ +/* + * Copyright 2003 Niels Provos + * 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. + */ +#include + +#include +#include +#include +#include +#include + +int +epoll_create(int size) +{ + return (syscall(__NR_epoll_create, size)); +} + +int +epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + + return (syscall(__NR_epoll_ctl, epfd, op, fd, event)); +} + +int +epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); +} Added: trunk/varnish-cache/contrib/libevent/evbuffer.c =================================================================== --- trunk/varnish-cache/contrib/libevent/evbuffer.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/evbuffer.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2002-2004 Niels Provos + * 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. + */ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#endif + +#include "event.h" + +/* prototypes */ + +void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t); +void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); + +static int +bufferevent_add(struct event *ev, int timeout) +{ + struct timeval tv, *ptv = NULL; + + if (timeout) { + timerclear(&tv); + tv.tv_sec = timeout; + ptv = &tv; + } + + return (event_add(ev, ptv)); +} + +/* + * This callback is executed when the size of the input buffer changes. + * We use it to apply back pressure on the reading side. + */ + +void +bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now, + void *arg) { + struct bufferevent *bufev = arg; + /* + * If we are below the watermak then reschedule reading if it's + * still enabled. + */ + if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) { + evbuffer_setcb(buf, NULL, NULL); + + if (bufev->enabled & EV_READ) + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + } +} + +static void +bufferevent_readcb(int fd, short event, void *arg) +{ + struct bufferevent *bufev = arg; + int res = 0; + short what = EVBUFFER_READ; + size_t len; + + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; + goto error; + } + + res = evbuffer_read(bufev->input, fd, -1); + if (res == -1) { + if (errno == EAGAIN || errno == EINTR) + goto reschedule; + /* error case */ + what |= EVBUFFER_ERROR; + } else if (res == 0) { + /* eof case */ + what |= EVBUFFER_EOF; + } + + if (res <= 0) + goto error; + + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + + /* See if this callbacks meets the water marks */ + len = EVBUFFER_LENGTH(bufev->input); + if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) + return; + if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) { + struct evbuffer *buf = bufev->input; + event_del(&bufev->ev_read); + + /* Now schedule a callback for us */ + evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); + return; + } + + /* Invoke the user callback - must always be called last */ + (*bufev->readcb)(bufev, bufev->cbarg); + return; + + reschedule: + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + return; + + error: + (*bufev->errorcb)(bufev, what, bufev->cbarg); +} + +static void +bufferevent_writecb(int fd, short event, void *arg) +{ + struct bufferevent *bufev = arg; + int res = 0; + short what = EVBUFFER_WRITE; + + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; + goto error; + } + + if (EVBUFFER_LENGTH(bufev->output)) { + res = evbuffer_write(bufev->output, fd); + if (res == -1) { + if (errno == EAGAIN || + errno == EINTR || + errno == EINPROGRESS) + goto reschedule; + /* error case */ + what |= EVBUFFER_ERROR; + } else if (res == 0) { + /* eof case */ + what |= EVBUFFER_EOF; + } + if (res <= 0) + goto error; + } + + if (EVBUFFER_LENGTH(bufev->output) != 0) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + + /* + * Invoke the user callback if our buffer is drained or below the + * low watermark. + */ + if (EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) + (*bufev->writecb)(bufev, bufev->cbarg); + + return; + + reschedule: + if (EVBUFFER_LENGTH(bufev->output) != 0) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + return; + + error: + (*bufev->errorcb)(bufev, what, bufev->cbarg); +} + +/* + * Create a new buffered event object. + * + * The read callback is invoked whenever we read new data. + * The write callback is invoked whenever the output buffer is drained. + * The error callback is invoked on a write/read error or on EOF. + */ + +struct bufferevent * +bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, + everrorcb errorcb, void *cbarg) +{ + struct bufferevent *bufev; + + if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL) + return (NULL); + + if ((bufev->input = evbuffer_new()) == NULL) { + free(bufev); + return (NULL); + } + + if ((bufev->output = evbuffer_new()) == NULL) { + evbuffer_free(bufev->input); + free(bufev); + return (NULL); + } + + event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev); + event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev); + + bufev->readcb = readcb; + bufev->writecb = writecb; + bufev->errorcb = errorcb; + + bufev->cbarg = cbarg; + + bufev->enabled = EV_READ | EV_WRITE; + + return (bufev); +} + +int +bufferevent_priority_set(struct bufferevent *bufev, int priority) +{ + if (event_priority_set(&bufev->ev_read, priority) == -1) + return (-1); + if (event_priority_set(&bufev->ev_write, priority) == -1) + return (-1); + + return (0); +} + +/* Closing the file descriptor is the responsibility of the caller */ + +void +bufferevent_free(struct bufferevent *bufev) +{ + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); + + evbuffer_free(bufev->input); + evbuffer_free(bufev->output); + + free(bufev); +} + +/* + * Returns 0 on success; + * -1 on failure. + */ + +int +bufferevent_write(struct bufferevent *bufev, void *data, size_t size) +{ + int res; + + res = evbuffer_add(bufev->output, data, size); + + if (res == -1) + return (res); + + /* If everything is okay, we need to schedule a write */ + if (size > 0 && (bufev->enabled & EV_WRITE)) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + + return (res); +} + +int +bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf) +{ + int res; + + res = bufferevent_write(bufev, buf->buffer, buf->off); + if (res != -1) + evbuffer_drain(buf, buf->off); + + return (res); +} + +size_t +bufferevent_read(struct bufferevent *bufev, void *data, size_t size) +{ + struct evbuffer *buf = bufev->input; + + if (buf->off < size) + size = buf->off; + + /* Copy the available data to the user buffer */ + memcpy(data, buf->buffer, size); + + if (size) + evbuffer_drain(buf, size); + + return (size); +} + +int +bufferevent_enable(struct bufferevent *bufev, short event) +{ + if (event & EV_READ) { + if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1) + return (-1); + } + if (event & EV_WRITE) { + if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1) + return (-1); + } + + bufev->enabled |= event; + return (0); +} + +int +bufferevent_disable(struct bufferevent *bufev, short event) +{ + if (event & EV_READ) { + if (event_del(&bufev->ev_read) == -1) + return (-1); + } + if (event & EV_WRITE) { + if (event_del(&bufev->ev_write) == -1) + return (-1); + } + + bufev->enabled &= ~event; + return (0); +} + +/* + * Sets the read and write timeout for a buffered event. + */ + +void +bufferevent_settimeout(struct bufferevent *bufev, + int timeout_read, int timeout_write) { + bufev->timeout_read = timeout_read; + bufev->timeout_write = timeout_write; +} + +/* + * Sets the water marks + */ + +void +bufferevent_setwatermark(struct bufferevent *bufev, short events, + size_t lowmark, size_t highmark) +{ + if (events & EV_READ) { + bufev->wm_read.low = lowmark; + bufev->wm_read.high = highmark; + } + + if (events & EV_WRITE) { + bufev->wm_write.low = lowmark; + bufev->wm_write.high = highmark; + } + + /* If the watermarks changed then see if we should call read again */ + bufferevent_read_pressure_cb(bufev->input, + 0, EVBUFFER_LENGTH(bufev->input), bufev); +} Added: trunk/varnish-cache/contrib/libevent/event-internal.h =================================================================== --- trunk/varnish-cache/contrib/libevent/event-internal.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/event-internal.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2004 Niels Provos + * 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. + */ +#ifndef _EVENT_INTERNAL_H_ +#define _EVENT_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct event_base { + const struct eventop *evsel; + void *evbase; + int event_count; /* counts number of total events */ + int event_count_active; /* counts number of active events */ + + int event_gotterm; /* Set to terminate loop */ + + /* active event management */ + struct event_list **activequeues; + int nactivequeues; + + struct event_list eventqueue; + struct timeval event_tv; + + RB_HEAD(event_tree, event) timetree; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _EVENT_INTERNAL_H_ */ Added: trunk/varnish-cache/contrib/libevent/event.3 =================================================================== --- trunk/varnish-cache/contrib/libevent/event.3 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/event.3 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,517 @@ +.\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $ +.\" +.\" Copyright (c) 2000 Artur Grabowski +.\" 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 ``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. +.\" +.Dd August 8, 2000 +.Dt EVENT 3 +.Os +.Sh NAME +.Nm event_init , +.Nm event_dispatch , +.Nm event_loop , +.Nm event_loopexit , +.Nm event_base_loop , +.Nm event_base_loopexit , +.Nm event_set , +.Nm event_add , +.Nm event_del , +.Nm event_once , +.Nm event_pending , +.Nm event_initialized , +.Nm event_priority_init , +.Nm event_priority_set , +.Nm evtimer_set , +.Nm evtimer_add , +.Nm evtimer_del +.Nm evtimer_pending , +.Nm evtimer_initialized , +.Nm signal_set , +.Nm signal_add , +.Nm signal_del +.Nm signal_pending , +.Nm signal_initialized , +.Nm bufferevent_new , +.Nm bufferevent_free , +.Nm bufferevent_write , +.Nm bufferevent_write_buffer , +.Nm bufferevent_read , +.Nm bufferevent_enable , +.Nm bufferevent_disable , +.Nm bufferevent_settimeout , +.Nm evbuffer_new , +.Nm evbuffer_free , +.Nm evbuffer_add , +.Nm evbuffer_add_buffer , +.Nm evbuffer_add_printf , +.Nm evbuffer_drain , +.Nm evbuffer_write , +.Nm evbuffer_read , +.Nm evbuffer_find , +.Nm evbuffer_readline +.Nd execute a function when a specific event occurs +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft "struct event_base *" +.Fn "event_init" +.Ft int +.Fn "event_dispatch" +.Ft int +.Fn "event_loop" "int flags" +.Ft int +.Fn "event_loopexit" "struct timeval *tv" +.Ft int +.Fn "event_base_loop" "struct event_base *" "int flags" +.Ft int +.Fn "event_base_loopexit" "struct event_base *" "struct timeval *tv" +.Ft void +.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" +.Ft int +.Fn "event_add" "struct event *ev" "struct timeval *tv" +.Ft int +.Fn "event_del" "struct event *ev" +.Ft int +.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv" +.Ft int +.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv" +.Ft int +.Fn "event_initialized" "struct event *ev" +.Ft int +.Fn "event_priority_init" "int npriorities" +.Ft int +.Fn "event_priority_set" "struct event *ev" "int priority" +.Ft void +.Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg" +.Ft void +.Fn "evtimer_add" "struct event *ev" "struct timeval *" +.Ft void +.Fn "evtimer_del" "struct event *ev" +.Ft int +.Fn "evtimer_pending" "struct event *ev" "struct timeval *tv" +.Ft int +.Fn "evtimer_initialized" "struct event *ev" +.Ft void +.Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg" +.Ft void +.Fn "signal_add" "struct event *ev" "struct timeval *" +.Ft void +.Fn "signal_del" "struct event *ev" +.Ft int +.Fn "signal_pending" "struct event *ev" "struct timeval *tv" +.Ft int +.Fn "signal_initialized" "struct event *ev" +.Ft "struct bufferevent *" +.Fn "bufferevent_new" "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg" +.Ft void +.Fn "bufferevent_free" "struct bufferevent *bufev" +.Ft int +.Fn "bufferevent_write" "struct bufferevent *bufev" "void *data" "size_t size" +.Ft int +.Fn "bufferevent_write_buffer" "struct bufferevent *bufev" "struct evbuffer *buf" +.Ft size_t +.Fn "bufferevent_read" "struct bufferevent *bufev" "void *data" "size_t size" +.Ft int +.Fn "bufferevent_enable" "struct bufferevent *bufev" "short event" +.Ft int +.Fn "bufferevent_disable" "struct bufferevent *bufev" "short event" +.Ft void +.Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write" +.Ft "struct evbuffer *" +.Fn "evbuffer_new" "void" +.Ft void +.Fn "evbuffer_free" "struct evbuffer *buf" +.Ft int +.Fn "evbuffer_add" "struct evbuffer *buf" "u_char *data" "size_t size" +.Ft int +.Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src" +.Ft int +.Fn "evbuffer_add_printf" "struct evbuffer *buf" "char *fmt" "..." +.Ft void +.Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size" +.Ft int +.Fn "evbuffer_write" "struct evbuffer *buf" "int fd" +.Ft int +.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size" +.Ft "u_char *" +.Fn "evbuffer_find" "struct evbuffer *buf" "u_char *data" "size_t size" +.Ft "char *" +.Fn "evbuffer_readline" "struct evbuffer *buf" +.Ft int +.Fa (*event_sigcb)(void) ; +.Ft int +.Fa event_gotsig ; +.Sh DESCRIPTION +The +.Nm event +API provides a mechanism to execute a function when a specific event +on a file descriptor occurs or after a given time has passed. +.Pp +The +.Nm event +API needs to be initialized with +.Fn event_init +before it can be used. +.Pp +In order to process events, an application needs to call +.Fn event_dispatch . +This function only returns on error, and should replace the event core +of the application program. +.Pp +In order to avoid races in signal handlers, the +.Nm event +API provides two variables: +.Va event_sigcb +and +.Va event_gotsig . +A signal handler +sets +.Va event_gotsig +to indicate that a signal has been received. +The application sets +.Va event_sigcb +to a callback function. After the signal handler sets +.Va event_gotsig , +.Nm event_dispatch +will execute the callback function to process received signals. The +callback returns 1 when no events are registered any more. It can +return -1 to indicate an error to the +.Nm event +library, causing +.Fn event_dispatch +to terminate with +.Va errno +set to +.Er EINTR. +.Pp +The +.Nm event_loop +function provides an interface for single pass execution of pending +events. The flags +.Va EVLOOP_ONCE +and +.Va EVLOOP_NONBLOCK +are recognized. +The +.Nm event_loopexit +function allows the loop to be terminated after some amount of time +has passed. +The parameter indicates the time after which the loop should terminate. +.Pp +It is the responsibility of the caller to provide these functions with +pre-allocated event structures. +.Pp +The function +.Fn event_set +prepares the event structure +.Fa ev +to be used in future calls to +.Fn event_add +and +.Fn event_del . +The event will be prepared to call the function specified by the +.Fa fn +argument with an +.Fa int +argument indicating the file descriptor, a +.Fa short +argument indicating the type of event, and a +.Fa void * +argument given in the +.Fa arg +argument. +The +.Fa fd +indicates the file descriptor that should be monitored for events. +The events can be either +.Va EV_READ , +.Va EV_WRITE , +or both. +Indicating that an application can read or write from the file descriptor +respectively without blocking. +.Pp +The function +.Fa fn +will be called with the file descriptor that triggered the event and +the type of event which will be either +.Va EV_TIMEOUT , +.Va EV_SIGNAL , +.Va EV_READ , +or +.Va EV_WRITE . +The additional flag +.Va EV_PERSIST +makes an +.Fn event_add +persistent until +.Fn event_del +has been called. +.Pp +Once initialized, the +.Fa ev +structure can be used repeatedly with +.Fn event_add +and +.Fn event_del +and does not need to be reinitialized unless the function called and/or +the argument to it are to be changed. +However, when an +.Fa ev +structure has been added to libevent using +.Fn event_add +the structure must persist until the event occurs (assuming +.Fa EV_PERSIST +is not set) or is removed +using +.Fn event_del . +You may not reuse the same +.Fa ev +structure for multiple monitored descriptors; each descriptor +needs its own +.Fa ev . +.Pp +The function +.Fn event_add +schedules the execution of the +.Fa ev +event when the event specified in +.Fn event_set +occurs or in at least the time specified in the +.Fa tv . +If +.Fa tv +is NULL, no timeout occurs and the function will only be called +if a matching event occurs on the file descriptor. +The event in the +.Fa ev +argument must be already initialized by +.Fn event_set +and may not be used in calls to +.Fn event_set +until it has timed out or been removed with +.Fn event_del . +If the event in the +.Fa ev +argument already has a scheduled timeout, the old timeout will be +replaced by the new one. +.Pp +The function +.Fn event_del +will cancel the event in the argument +.Fa ev . +If the event has already executed or has never been added +the call will have no effect. +.Pp +The function +.Fn event_once +is similar to +.Fn event_set . +However, it schedules a callback to be called exactly once and does not +require the caller to prepare an +.Fa event +structure. +This function supports +.Fa EV_TIMEOUT , +.Fa EV_READ +and +.Fa EV_WRITE . +.Pp +The +.Fn event_pending +function can be used to check if the event specified by +.Fa event +is pending to run. +If +.Va EV_TIMEOUT +was specified and +.Fa tv +is not +.Va NULL , +the expiration time of the event will be returned in +.Fa tv . +.Pp +The +.Fn event_initialized +macro can be used to check if an event has been initialized. +.Pp +The functions +.Fn evtimer_set , +.Fn evtimer_add , +.Fn evtimer_del , +.Fn evtimer_initialized , +and +.Fn evtimer_pending +are abbreviations for common situations where only a timeout is required. +The file descriptor passed will be -1, and the event type will be +.Va EV_TIMEOUT . +.Pp +.Pp +The functions +.Fn signal_set , +.Fn signal_add , +.Fn signal_del , +.Fn signal_initialized , +and +.Fn signal_pending +are abbreviations. +The event type will be a persistent +.Va EV_SIGNAL . +That means +.Fn signal_set +adds +.Va EV_PERSIST . +.Pp +It is possible to disable support for +.Va epoll , kqueue , devpoll, poll +or +.Va select +by setting the environment variable +.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL, EVENT_NOPOLL +or +.Va EVENT_NOSELECT . +By setting the environment variable +.Va EVENT_SHOW_METHOD , +.Nm libevent +displays the kernel notification method that it uses. +.Pp +.Sh EVENT PRIORITIES +By default +.Nm libevent +schedules all active events with the same priority. +However, sometime it is desirable to process some events with a higher +priority than others. +For that reason, +.Nm libevent +supports strict priority queues. +Active events with a lower priority are always processed before events +with a higher priority. +.Pp +The number of different priorities can be set initially with the +.Fn event_priority_init +function. +This function should be called before the first call to +.Fn event_dispatch . +The +.Fn event_priority_set +function can be used to assign a priority to an event. +By default, +.Nm libevent +assigns the middle priority to all events unless their priority +is explicitly set. +.Pp +.Sh THREAD SAFE EVENTS +.Nm Libevent +has experimental support for thread-safe events. +When initializing the library via +.Fn event_init , +an event base is returned. +This event base can be used in conjunction with calls to +.Fn event_base_set +.Fn event_base_dispatch , +.Fn event_base_loop , +and +.Fn event_base_loopexit . +.Fn event_base_set +should be called after preparing an event with +.Fn event_set , +as +.Fn event_set +assigns the provided event to the most recently created event base. +.Pp +.Sh BUFFERED EVENTS +.Nm libevent +provides an abstraction on top of the regular event callbacks. +This abstraction is called a +.Va "buffered event" . +A buffered event provides input and output buffer that get filled +and drained automatically. +The user of a buffered event no longer deals directly with the IO, +but instead is reading from input and writing to output buffers. +.Pp +A new bufferevent is created by +.Fn bufferevent_new . +The parameter +.Fa "fd" +specifies the file descriptor from which data is read and written to. +This file descriptor is not allowed to be a +.Xr pipe 2 . +The next three parameters are callbacks. +The read and write callback have the following form +.Ft void +.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" +The argument is specified by the fourth parameter +.Fa "cbarg" . +.Pp +By default the buffered event is read enabled and will try to read +from the file descriptor. +The write callback is executed whenever the output buffer is drained +below the write low watermark which is +.Va 0 +by default. +.Pp +The +.Fn bufferevent_write +function can be used to write data to the file descriptor. +The data is appended to the output buffer and written to the descriptor +automatically as it becomes available for writing. +The +.Fn bufferevent_read +function is used to read data from the input buffer. +Both functions return the amount of data written or read. +.Pp +.Sh RETURN VALUES +Upon successful completion +.Fn event_add +and +.Fn event_del +return 0. +Otherwise, -1 is returned and the global variable errno is +set to indicate the error. +.Sh SEE ALSO +.Xr timeout 9 , +.Xr select 2 , +.Xr kqueue 2 +.Sh HISTORY +The +.Nm event +API manpage is based on the +.Xr timeout 9 +manpage by Artur Grabowski. +The port of +.Nm libevent +to Windows is due to Michael A. Davis. +Support for real-time signals is due to Taral. +.Sh AUTHORS +The +.Nm event +library was written by Niels Provos. +.Pp +.Sh BUGS +This documentation is neither complete nor authoritative. +If you are in doubt about the usage of this API then +check the source code to find out how it works, write +up the missing piece of documentation and send it to +me for inclusion in this man page. Added: trunk/varnish-cache/contrib/libevent/event.c =================================================================== --- trunk/varnish-cache/contrib/libevent/event.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/event.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,809 @@ +/* + * Copyright (c) 2000-2004 Niels Provos + * 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. + */ +#include "config.h" + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include "misc.h" +#endif +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include + +#include "event.h" +#include "event-internal.h" +#include "log.h" + +#ifdef HAVE_SELECT +extern const struct eventop selectops; +#endif +#ifdef HAVE_POLL +extern const struct eventop pollops; +#endif +#ifdef HAVE_RTSIG +extern const struct eventop rtsigops; +#endif +#ifdef HAVE_EPOLL +extern const struct eventop epollops; +#endif +#ifdef HAVE_WORKING_KQUEUE +extern const struct eventop kqops; +#endif +#ifdef HAVE_DEVPOLL +extern const struct eventop devpollops; +#endif +#ifdef WIN32 +extern const struct eventop win32ops; +#endif + +/* In order of preference */ +const struct eventop *eventops[] = { +#ifdef HAVE_WORKING_KQUEUE + &kqops, +#endif +#ifdef HAVE_EPOLL + &epollops, +#endif +#ifdef HAVE_DEVPOLL + &devpollops, +#endif +#ifdef HAVE_RTSIG + &rtsigops, +#endif +#ifdef HAVE_POLL + &pollops, +#endif +#ifdef HAVE_SELECT + &selectops, +#endif +#ifdef WIN32 + &win32ops, +#endif + NULL +}; + +/* Global state */ +struct event_list signalqueue; + +struct event_base *current_base = NULL; + +/* Handle signals - This is a deprecated interface */ +int (*event_sigcb)(void); /* Signal callback when gotsig is set */ +volatile int event_gotsig; /* Set in signal handler */ + +/* Prototypes */ +static void event_queue_insert(struct event_base *, struct event *, int); +static void event_queue_remove(struct event_base *, struct event *, int); +static int event_haveevents(struct event_base *); + +static void event_process_active(struct event_base *); + +static int timeout_next(struct event_base *, struct timeval *); +static void timeout_process(struct event_base *); +static void timeout_correct(struct event_base *, struct timeval *); + +static int +compare(struct event *a, struct event *b) +{ + if (timercmp(&a->ev_timeout, &b->ev_timeout, <)) + return (-1); + else if (timercmp(&a->ev_timeout, &b->ev_timeout, >)) + return (1); + if (a < b) + return (-1); + else if (a > b) + return (1); + return (0); +} + +RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare); + +RB_GENERATE(event_tree, event, ev_timeout_node, compare); + + +void * +event_init(void) +{ + int i; + + if ((current_base = calloc(1, sizeof(struct event_base))) == NULL) + event_err(1, "%s: calloc"); + + event_sigcb = NULL; + event_gotsig = 0; + gettimeofday(¤t_base->event_tv, NULL); + + RB_INIT(¤t_base->timetree); + TAILQ_INIT(¤t_base->eventqueue); + TAILQ_INIT(&signalqueue); + + current_base->evbase = NULL; + for (i = 0; eventops[i] && !current_base->evbase; i++) { + current_base->evsel = eventops[i]; + + current_base->evbase = current_base->evsel->init(); + } + + if (current_base->evbase == NULL) + event_errx(1, "%s: no event mechanism available", __func__); + + if (getenv("EVENT_SHOW_METHOD")) + event_msgx("libevent using: %s\n", + current_base->evsel->name); + + /* allocate a single active event queue */ + event_base_priority_init(current_base, 1); + + return (current_base); +} + +int +event_priority_init(int npriorities) +{ + return event_base_priority_init(current_base, npriorities); +} + +int +event_base_priority_init(struct event_base *base, int npriorities) +{ + int i; + + if (base->event_count_active) + return (-1); + + if (base->nactivequeues && npriorities != base->nactivequeues) { + for (i = 0; i < base->nactivequeues; ++i) { + free(base->activequeues[i]); + } + free(base->activequeues); + } + + /* Allocate our priority queues */ + base->nactivequeues = npriorities; + base->activequeues = (struct event_list **)calloc(base->nactivequeues, + npriorities * sizeof(struct event_list *)); + if (base->activequeues == NULL) + event_err(1, "%s: calloc", __func__); + + for (i = 0; i < base->nactivequeues; ++i) { + base->activequeues[i] = malloc(sizeof(struct event_list)); + if (base->activequeues[i] == NULL) + event_err(1, "%s: malloc", __func__); + TAILQ_INIT(base->activequeues[i]); + } + + return (0); +} + +int +event_haveevents(struct event_base *base) +{ + return (base->event_count > 0); +} + +/* + * Active events are stored in priority queues. Lower priorities are always + * process before higher priorities. Low priority events can starve high + * priority ones. + */ + +static void +event_process_active(struct event_base *base) +{ + struct event *ev; + struct event_list *activeq = NULL; + int i; + short ncalls; + + if (!base->event_count_active) + return; + + for (i = 0; i < base->nactivequeues; ++i) { + if (TAILQ_FIRST(base->activequeues[i]) != NULL) { + activeq = base->activequeues[i]; + break; + } + } + + for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { + event_queue_remove(base, ev, EVLIST_ACTIVE); + + /* Allows deletes to work */ + ncalls = ev->ev_ncalls; + ev->ev_pncalls = &ncalls; + while (ncalls) { + ncalls--; + ev->ev_ncalls = ncalls; + (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); + } + } +} + +/* + * Wait continously for events. We exit only if no events are left. + */ + +int +event_dispatch(void) +{ + return (event_loop(0)); +} + +int +event_base_dispatch(struct event_base *event_base) +{ + return (event_base_loop(event_base, 0)); +} + +static void +event_loopexit_cb(int fd, short what, void *arg) +{ + struct event_base *base = arg; + base->event_gotterm = 1; +} + +/* not thread safe */ + +int +event_loopexit(struct timeval *tv) +{ + return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, + current_base, tv)); +} + +int +event_base_loopexit(struct event_base *event_base, struct timeval *tv) +{ + return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, + event_base, tv)); +} + +/* not thread safe */ + +int +event_loop(int flags) +{ + return event_base_loop(current_base, flags); +} + +int +event_base_loop(struct event_base *base, int flags) +{ + const struct eventop *evsel = base->evsel; + void *evbase = base->evbase; + struct timeval tv; + int res, done; + + /* Calculate the initial events that we are waiting for */ + if (evsel->recalc(base, evbase, 0) == -1) + return (-1); + + done = 0; + while (!done) { + /* Terminate the loop if we have been asked to */ + if (base->event_gotterm) { + base->event_gotterm = 0; + break; + } + + /* You cannot use this interface for multi-threaded apps */ + while (event_gotsig) { + event_gotsig = 0; + if (event_sigcb) { + res = (*event_sigcb)(); + if (res == -1) { + errno = EINTR; + return (-1); + } + } + } + + /* Check if time is running backwards */ + gettimeofday(&tv, NULL); + if (timercmp(&tv, &base->event_tv, <)) { + struct timeval off; + event_debug(("%s: time is running backwards, corrected", + __func__)); + timersub(&base->event_tv, &tv, &off); + timeout_correct(base, &off); + } + base->event_tv = tv; + + if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) + timeout_next(base, &tv); + else + timerclear(&tv); + + /* If we have no events, we just exit */ + if (!event_haveevents(base)) { + event_debug(("%s: no events registered.", __func__)); + return (1); + } + + res = evsel->dispatch(base, evbase, &tv); + + if (res == -1) + return (-1); + + timeout_process(base); + + if (base->event_count_active) { + event_process_active(base); + if (!base->event_count_active && (flags & EVLOOP_ONCE)) + done = 1; + } else if (flags & EVLOOP_NONBLOCK) + done = 1; + + if (evsel->recalc(base, evbase, 0) == -1) + return (-1); + } + + event_debug(("%s: asked to terminate loop.", __func__)); + return (0); +} + +/* Sets up an event for processing once */ + +struct event_once { + struct event ev; + + void (*cb)(int, short, void *); + void *arg; +}; + +/* One-time callback, it deletes itself */ + +static void +event_once_cb(int fd, short events, void *arg) +{ + struct event_once *eonce = arg; + + (*eonce->cb)(fd, events, eonce->arg); + free(eonce); +} + +/* Schedules an event once */ + +int +event_once(int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) +{ + struct event_once *eonce; + struct timeval etv; + + /* We cannot support signals that just fire once */ + if (events & EV_SIGNAL) + return (-1); + + if ((eonce = calloc(1, sizeof(struct event_once))) == NULL) + return (-1); + + eonce->cb = callback; + eonce->arg = arg; + + if (events == EV_TIMEOUT) { + if (tv == NULL) { + timerclear(&etv); + tv = &etv; + } + + evtimer_set(&eonce->ev, event_once_cb, eonce); + } else if (events & (EV_READ|EV_WRITE)) { + events &= EV_READ|EV_WRITE; + + event_set(&eonce->ev, fd, events, event_once_cb, eonce); + } else { + /* Bad event combination */ + free(eonce); + return (-1); + } + + event_add(&eonce->ev, tv); + + return (0); +} + +void +event_set(struct event *ev, int fd, short events, + void (*callback)(int, short, void *), void *arg) +{ + /* Take the current base - caller needs to set the real base later */ + ev->ev_base = current_base; + + ev->ev_callback = callback; + ev->ev_arg = arg; + ev->ev_fd = fd; + ev->ev_events = events; + ev->ev_flags = EVLIST_INIT; + ev->ev_ncalls = 0; + ev->ev_pncalls = NULL; + + /* by default, we put new events into the middle priority */ + ev->ev_pri = current_base->nactivequeues/2; +} + +int +event_base_set(struct event_base *base, struct event *ev) +{ + /* Only innocent events may be assigned to a different base */ + if (ev->ev_flags != EVLIST_INIT) + return (-1); + + ev->ev_base = base; + ev->ev_pri = base->nactivequeues/2; + + return (0); +} + +/* + * Set's the priority of an event - if an event is already scheduled + * changing the priority is going to fail. + */ + +int +event_priority_set(struct event *ev, int pri) +{ + if (ev->ev_flags & EVLIST_ACTIVE) + return (-1); + if (pri < 0 || pri >= ev->ev_base->nactivequeues) + return (-1); + + ev->ev_pri = pri; + + return (0); +} + +/* + * Checks if a specific event is pending or scheduled. + */ + +int +event_pending(struct event *ev, short event, struct timeval *tv) +{ + int flags = 0; + + if (ev->ev_flags & EVLIST_INSERTED) + flags |= (ev->ev_events & (EV_READ|EV_WRITE)); + if (ev->ev_flags & EVLIST_ACTIVE) + flags |= ev->ev_res; + if (ev->ev_flags & EVLIST_TIMEOUT) + flags |= EV_TIMEOUT; + if (ev->ev_flags & EVLIST_SIGNAL) + flags |= EV_SIGNAL; + + event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL); + + /* See if there is a timeout that we should report */ + if (tv != NULL && (flags & event & EV_TIMEOUT)) + *tv = ev->ev_timeout; + + return (flags & event); +} + +int +event_add(struct event *ev, struct timeval *tv) +{ + struct event_base *base = ev->ev_base; + const struct eventop *evsel = base->evsel; + void *evbase = base->evbase; + + event_debug(( + "event_add: event: %p, %s%s%scall %p", + ev, + ev->ev_events & EV_READ ? "EV_READ " : " ", + ev->ev_events & EV_WRITE ? "EV_WRITE " : " ", + tv ? "EV_TIMEOUT " : " ", + ev->ev_callback)); + + assert(!(ev->ev_flags & ~EVLIST_ALL)); + + if (tv != NULL) { + struct timeval now; + + if (ev->ev_flags & EVLIST_TIMEOUT) + event_queue_remove(base, ev, EVLIST_TIMEOUT); + + /* Check if it is active due to a timeout. Rescheduling + * this timeout before the callback can be executed + * removes it from the active list. */ + if ((ev->ev_flags & EVLIST_ACTIVE) && + (ev->ev_res & EV_TIMEOUT)) { + /* See if we are just active executing this + * event in a loop + */ + if (ev->ev_ncalls && ev->ev_pncalls) { + /* Abort loop */ + *ev->ev_pncalls = 0; + } + + event_queue_remove(base, ev, EVLIST_ACTIVE); + } + + gettimeofday(&now, NULL); + timeradd(&now, tv, &ev->ev_timeout); + + event_debug(( + "event_add: timeout in %d seconds, call %p", + tv->tv_sec, ev->ev_callback)); + + event_queue_insert(base, ev, EVLIST_TIMEOUT); + } + + if ((ev->ev_events & (EV_READ|EV_WRITE)) && + !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { + event_queue_insert(base, ev, EVLIST_INSERTED); + + return (evsel->add(evbase, ev)); + } else if ((ev->ev_events & EV_SIGNAL) && + !(ev->ev_flags & EVLIST_SIGNAL)) { + event_queue_insert(base, ev, EVLIST_SIGNAL); + + return (evsel->add(evbase, ev)); + } + + return (0); +} + +int +event_del(struct event *ev) +{ + struct event_base *base; + const struct eventop *evsel; + void *evbase; + + event_debug(("event_del: %p, callback %p", + ev, ev->ev_callback)); + + /* An event without a base has not been added */ + if (ev->ev_base == NULL) + return (-1); + + base = ev->ev_base; + evsel = base->evsel; + evbase = base->evbase; + + assert(!(ev->ev_flags & ~EVLIST_ALL)); + + /* See if we are just active executing this event in a loop */ + if (ev->ev_ncalls && ev->ev_pncalls) { + /* Abort loop */ + *ev->ev_pncalls = 0; + } + + if (ev->ev_flags & EVLIST_TIMEOUT) + event_queue_remove(base, ev, EVLIST_TIMEOUT); + + if (ev->ev_flags & EVLIST_ACTIVE) + event_queue_remove(base, ev, EVLIST_ACTIVE); + + if (ev->ev_flags & EVLIST_INSERTED) { + event_queue_remove(base, ev, EVLIST_INSERTED); + return (evsel->del(evbase, ev)); + } else if (ev->ev_flags & EVLIST_SIGNAL) { + event_queue_remove(base, ev, EVLIST_SIGNAL); + return (evsel->del(evbase, ev)); + } + + return (0); +} + +void +event_active(struct event *ev, int res, short ncalls) +{ + /* We get different kinds of events, add them together */ + if (ev->ev_flags & EVLIST_ACTIVE) { + ev->ev_res |= res; + return; + } + + ev->ev_res = res; + ev->ev_ncalls = ncalls; + ev->ev_pncalls = NULL; + event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE); +} + +int +timeout_next(struct event_base *base, struct timeval *tv) +{ + struct timeval dflt = TIMEOUT_DEFAULT; + + struct timeval now; + struct event *ev; + + if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) { + *tv = dflt; + return (0); + } + + if (gettimeofday(&now, NULL) == -1) + return (-1); + + if (timercmp(&ev->ev_timeout, &now, <=)) { + timerclear(tv); + return (0); + } + + timersub(&ev->ev_timeout, &now, tv); + + assert(tv->tv_sec >= 0); + assert(tv->tv_usec >= 0); + + event_debug(("timeout_next: in %d seconds", tv->tv_sec)); + return (0); +} + +static void +timeout_correct(struct event_base *base, struct timeval *off) +{ + struct event *ev; + + /* + * We can modify the key element of the node without destroying + * the key, beause we apply it to all in the right order. + */ + RB_FOREACH(ev, event_tree, &base->timetree) + timersub(&ev->ev_timeout, off, &ev->ev_timeout); +} + +void +timeout_process(struct event_base *base) +{ + struct timeval now; + struct event *ev, *next; + + gettimeofday(&now, NULL); + + for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) { + if (timercmp(&ev->ev_timeout, &now, >)) + break; + next = RB_NEXT(event_tree, &base->timetree, ev); + + event_queue_remove(base, ev, EVLIST_TIMEOUT); + + /* delete this event from the I/O queues */ + event_del(ev); + + event_debug(("timeout_process: call %p", + ev->ev_callback)); + event_active(ev, EV_TIMEOUT, 1); + } +} + +void +event_queue_remove(struct event_base *base, struct event *ev, int queue) +{ + int docount = 1; + + if (!(ev->ev_flags & queue)) + event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, + ev, ev->ev_fd, queue); + + if (ev->ev_flags & EVLIST_INTERNAL) + docount = 0; + + if (docount) + base->event_count--; + + ev->ev_flags &= ~queue; + switch (queue) { + case EVLIST_ACTIVE: + if (docount) + base->event_count_active--; + TAILQ_REMOVE(base->activequeues[ev->ev_pri], + ev, ev_active_next); + break; + case EVLIST_SIGNAL: + TAILQ_REMOVE(&signalqueue, ev, ev_signal_next); + break; + case EVLIST_TIMEOUT: + RB_REMOVE(event_tree, &base->timetree, ev); + break; + case EVLIST_INSERTED: + TAILQ_REMOVE(&base->eventqueue, ev, ev_next); + break; + default: + event_errx(1, "%s: unknown queue %x", __func__, queue); + } +} + +void +event_queue_insert(struct event_base *base, struct event *ev, int queue) +{ + int docount = 1; + + if (ev->ev_flags & queue) { + /* Double insertion is possible for active events */ + if (queue & EVLIST_ACTIVE) + return; + + event_errx(1, "%s: %p(fd %d) already on queue %x", __func__, + ev, ev->ev_fd, queue); + } + + if (ev->ev_flags & EVLIST_INTERNAL) + docount = 0; + + if (docount) + base->event_count++; + + ev->ev_flags |= queue; + switch (queue) { + case EVLIST_ACTIVE: + if (docount) + base->event_count_active++; + TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], + ev,ev_active_next); + break; + case EVLIST_SIGNAL: + TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next); + break; + case EVLIST_TIMEOUT: { + struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev); + assert(tmp == NULL); + break; + } + case EVLIST_INSERTED: + TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); + break; + default: + event_errx(1, "%s: unknown queue %x", __func__, queue); + } +} + +/* Functions for debugging */ + +const char * +event_get_version(void) +{ + return (VERSION); +} + +/* + * No thread-safe interface needed - the information should be the same + * for all threads. + */ + +const char * +event_get_method(void) +{ + return (current_base->evsel->name); +} Added: trunk/varnish-cache/contrib/libevent/event.h =================================================================== --- trunk/varnish-cache/contrib/libevent/event.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/event.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2000-2004 Niels Provos + * 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. + */ +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +typedef unsigned char u_char; +#endif + +#define EVLIST_TIMEOUT 0x01 +#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 | 0x9f) + +#define EV_TIMEOUT 0x01 +#define EV_READ 0x02 +#define EV_WRITE 0x04 +#define EV_SIGNAL 0x08 +#define EV_PERSIST 0x10 /* Persistant event */ + +/* Fix so that ppl dont have to run with */ +#ifndef TAILQ_ENTRY +#define _EVENT_DEFINED_TQENTRY +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ +#ifndef RB_ENTRY +#define _EVENT_DEFINED_RBENTRY +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} +#endif /* !RB_ENTRY */ + +struct event_base; +struct event { + TAILQ_ENTRY (event) ev_next; + TAILQ_ENTRY (event) ev_active_next; + TAILQ_ENTRY (event) ev_signal_next; + RB_ENTRY (event) ev_timeout_node; + + struct event_base *ev_base; + int ev_fd; + short ev_events; + short ev_ncalls; + short *ev_pncalls; /* Allows deletes in callback */ + + struct timeval ev_timeout; + + int ev_pri; /* smaller numbers are higher priority */ + + void (*ev_callback)(int, short, void *arg); + void *ev_arg; + + int ev_res; /* result passed to event callback */ + int ev_flags; +}; + +#define EVENT_SIGNAL(ev) (int)ev->ev_fd +#define EVENT_FD(ev) (int)ev->ev_fd + +#ifdef _EVENT_DEFINED_TQENTRY +#undef TAILQ_ENTRY +#undef _EVENT_DEFINED_TQENTRY +#else +TAILQ_HEAD (event_list, event); +#endif /* _EVENT_DEFINED_TQENTRY */ +#ifdef _EVENT_DEFINED_RBENTRY +#undef RB_ENTRY +#undef _EVENT_DEFINED_RBENTRY +#endif /* _EVENT_DEFINED_RBENTRY */ + +struct eventop { + char *name; + void *(*init)(void); + int (*add)(void *, struct event *); + int (*del)(void *, struct event *); + int (*recalc)(struct event_base *, void *, int); + int (*dispatch)(struct event_base *, void *, struct timeval *); +}; + +#define TIMEOUT_DEFAULT {5, 0} + +void *event_init(void); +int event_dispatch(void); +int event_base_dispatch(struct event_base *); + +#define _EVENT_LOG_DEBUG 0 +#define _EVENT_LOG_MSG 1 +#define _EVENT_LOG_WARN 2 +#define _EVENT_LOG_ERR 3 +typedef void (*event_log_cb)(int severity, const char *msg); +void event_set_log_callback(event_log_cb cb); + +/* Associate a different event base with an event */ +int event_base_set(struct event_base *, struct event *); + +#define EVLOOP_ONCE 0x01 +#define EVLOOP_NONBLOCK 0x02 +int event_loop(int); +int event_base_loop(struct event_base *, int); +int event_loopexit(struct timeval *); /* Causes the loop to exit */ +int event_base_loopexit(struct event_base *, struct timeval *); + +#define evtimer_add(ev, tv) event_add(ev, tv) +#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) +#define evtimer_del(ev) event_del(ev) +#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) +#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) + +#define timeout_add(ev, tv) event_add(ev, tv) +#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) +#define timeout_del(ev) event_del(ev) +#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) +#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) + +#define signal_add(ev, tv) event_add(ev, tv) +#define signal_set(ev, x, cb, arg) \ + event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) +#define signal_del(ev) event_del(ev) +#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv) +#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) + +void event_set(struct event *, int, short, void (*)(int, short, void *), void *); +int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); + +int event_add(struct event *, struct timeval *); +int event_del(struct event *); +void event_active(struct event *, int, short); + +int event_pending(struct event *, short, struct timeval *); + +#ifdef WIN32 +#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != INVALID_HANDLE_VALUE) +#else +#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) +#endif + +/* Some simple debugging functions */ +const char *event_get_version(void); +const char *event_get_method(void); + +/* These functions deal with event priorities */ + +int event_priority_init(int); +int event_base_priority_init(struct event_base *, int); +int event_priority_set(struct event *, int); + +/* These functions deal with buffering input and output */ + +struct evbuffer { + u_char *buffer; + u_char *orig_buffer; + + size_t misalign; + size_t totallen; + size_t off; + + void (*cb)(struct evbuffer *, size_t, size_t, void *); + void *cbarg; +}; + +/* Just for error reporting - use other constants otherwise */ +#define EVBUFFER_READ 0x01 +#define EVBUFFER_WRITE 0x02 +#define EVBUFFER_EOF 0x10 +#define EVBUFFER_ERROR 0x20 +#define EVBUFFER_TIMEOUT 0x40 + +struct bufferevent; +typedef void (*evbuffercb)(struct bufferevent *, void *); +typedef void (*everrorcb)(struct bufferevent *, short what, void *); + +struct event_watermark { + size_t low; + size_t high; +}; + +struct bufferevent { + struct event ev_read; + struct event ev_write; + + struct evbuffer *input; + struct evbuffer *output; + + struct event_watermark wm_read; + struct event_watermark wm_write; + + evbuffercb readcb; + evbuffercb writecb; + everrorcb errorcb; + void *cbarg; + + int timeout_read; /* in seconds */ + int timeout_write; /* in seconds */ + + short enabled; /* events that are currently enabled */ +}; + +struct bufferevent *bufferevent_new(int fd, + evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); +int bufferevent_priority_set(struct bufferevent *bufev, int pri); +void bufferevent_free(struct bufferevent *bufev); +int bufferevent_write(struct bufferevent *bufev, void *data, size_t size); +int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); +size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); +int bufferevent_enable(struct bufferevent *bufev, short event); +int bufferevent_disable(struct bufferevent *bufev, short event); +void bufferevent_settimeout(struct bufferevent *bufev, + int timeout_read, int timeout_write); + +#define EVBUFFER_LENGTH(x) (x)->off +#define EVBUFFER_DATA(x) (x)->buffer +#define EVBUFFER_INPUT(x) (x)->input +#define EVBUFFER_OUTPUT(x) (x)->output + +struct evbuffer *evbuffer_new(void); +void evbuffer_free(struct evbuffer *); +int evbuffer_expand(struct evbuffer *, size_t); +int evbuffer_add(struct evbuffer *, void *, size_t); +int evbuffer_remove(struct evbuffer *, void *, size_t); +char *evbuffer_readline(struct evbuffer *); +int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); +int evbuffer_add_printf(struct evbuffer *, char *fmt, ...); +void evbuffer_drain(struct evbuffer *, size_t); +int evbuffer_write(struct evbuffer *, int); +int evbuffer_read(struct evbuffer *, int, int); +u_char *evbuffer_find(struct evbuffer *, u_char *, size_t); +void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *); + +#ifdef __cplusplus +} +#endif + +#endif /* _EVENT_H_ */ Added: trunk/varnish-cache/contrib/libevent/evsignal.h =================================================================== --- trunk/varnish-cache/contrib/libevent/evsignal.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/evsignal.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2002 Niels Provos + * 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. + */ +#ifndef _EVSIGNAL_H_ +#define _EVSIGNAL_H_ + +void evsignal_init(sigset_t *); +void evsignal_process(void); +int evsignal_recalc(sigset_t *); +int evsignal_deliver(sigset_t *); +int evsignal_add(sigset_t *, struct event *); +int evsignal_del(sigset_t *, struct event *); + +#endif /* _EVSIGNAL_H_ */ Added: trunk/varnish-cache/contrib/libevent/kqueue.c =================================================================== --- trunk/varnish-cache/contrib/libevent/kqueue.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/kqueue.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,398 @@ +/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */ + +/* + * Copyright 2000-2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_INTTYPES_H +#include +#endif + +#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) +#define INTPTR(x) (intptr_t)x +#else +#define INTPTR(x) x +#endif + +#include "event.h" +#include "log.h" + +#define EVLIST_X_KQINKERNEL 0x1000 + +#define NEVENT 64 + +struct kqop { + struct kevent *changes; + int nchanges; + struct kevent *events; + int nevents; + int kq; +}; + +void *kq_init (void); +int kq_add (void *, struct event *); +int kq_del (void *, struct event *); +int kq_recalc (struct event_base *, void *, int); +int kq_dispatch (struct event_base *, void *, struct timeval *); +int kq_insert (struct kqop *, struct kevent *); + +const struct eventop kqops = { + "kqueue", + kq_init, + kq_add, + kq_del, + kq_recalc, + kq_dispatch +}; + +void * +kq_init(void) +{ + int kq; + struct kqop *kqueueop; + + /* Disable kqueue when this environment variable is set */ + if (getenv("EVENT_NOKQUEUE")) + return (NULL); + + if (!(kqueueop = calloc(1, sizeof(struct kqop)))) + return (NULL); + + /* Initalize the kernel queue */ + + if ((kq = kqueue()) == -1) { + event_warn("kqueue"); + free (kqueueop); + return (NULL); + } + + kqueueop->kq = kq; + + /* Initalize fields */ + kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); + if (kqueueop->changes == NULL) { + free (kqueueop); + return (NULL); + } + kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); + if (kqueueop->events == NULL) { + free (kqueueop->changes); + free (kqueueop); + return (NULL); + } + kqueueop->nevents = NEVENT; + + /* Check for Mac OS X kqueue bug. */ + kqueueop->changes[0].ident = -1; + kqueueop->changes[0].filter = EVFILT_READ; + kqueueop->changes[0].flags = EV_ADD; + /* + * If kqueue works, then kevent will succeed, and it will + * stick an error in events[0]. If kqueue is broken, then + * kevent will fail. + */ + if (kevent(kq, + kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || + kqueueop->events[0].ident != -1 || + kqueueop->events[0].flags != EV_ERROR) { + event_warn("%s: detected broken kqueue; not using.", __func__); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + return (NULL); + } + + return (kqueueop); +} + +int +kq_recalc(struct event_base *base, void *arg, int max) +{ + return (0); +} + +int +kq_insert(struct kqop *kqop, struct kevent *kev) +{ + int nevents = kqop->nevents; + + if (kqop->nchanges == nevents) { + struct kevent *newchange; + struct kevent *newresult; + + nevents *= 2; + + newchange = realloc(kqop->changes, + nevents * sizeof(struct kevent)); + if (newchange == NULL) { + event_warn("%s: malloc", __func__); + return (-1); + } + kqop->changes = newchange; + + newresult = realloc(kqop->events, + nevents * sizeof(struct kevent)); + + /* + * If we fail, we don't have to worry about freeing, + * the next realloc will pick it up. + */ + if (newresult == NULL) { + event_warn("%s: malloc", __func__); + return (-1); + } + kqop->events = newresult; + + kqop->nevents = nevents; + } + + memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); + + event_debug(("%s: fd %d %s%s", + __func__, kev->ident, + kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", + kev->flags == EV_DELETE ? " (del)" : "")); + + return (0); +} + +static void +kq_sighandler(int sig) +{ + /* Do nothing here */ +} + +int +kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + struct kqop *kqop = arg; + struct kevent *changes = kqop->changes; + struct kevent *events = kqop->events; + struct event *ev; + struct timespec ts; + int i, res; + + TIMEVAL_TO_TIMESPEC(tv, &ts); + + res = kevent(kqop->kq, changes, kqop->nchanges, + events, kqop->nevents, &ts); + kqop->nchanges = 0; + if (res == -1) { + if (errno != EINTR) { + event_warn("kevent"); + return (-1); + } + + return (0); + } + + event_debug(("%s: kevent reports %d", __func__, res)); + + for (i = 0; i < res; i++) { + int which = 0; + + if (events[i].flags & EV_ERROR) { + /* + * Error messages that can happen, when a delete fails. + * EBADF happens when the file discriptor has been + * closed, + * ENOENT when the file discriptor was closed and + * then reopened. + * EINVAL for some reasons not understood; EINVAL + * should not be returned ever; but FreeBSD does :-\ + * An error is also indicated when a callback deletes + * an event we are still processing. In that case + * the data field is set to ENOENT. + */ + if (events[i].data == EBADF || + events[i].data == EINVAL || + events[i].data == ENOENT) + continue; + errno = events[i].data; + return (-1); + } + + ev = (struct event *)events[i].udata; + + if (events[i].filter == EVFILT_READ) { + which |= EV_READ; + } else if (events[i].filter == EVFILT_WRITE) { + which |= EV_WRITE; + } else if (events[i].filter == EVFILT_SIGNAL) { + which |= EV_SIGNAL; + } + + if (!which) + continue; + + if (!(ev->ev_events & EV_PERSIST)) { + ev->ev_flags &= ~EVLIST_X_KQINKERNEL; + event_del(ev); + } + + event_active(ev, which, + ev->ev_events & EV_SIGNAL ? events[i].data : 1); + } + + return (0); +} + + +int +kq_add(void *arg, struct event *ev) +{ + struct kqop *kqop = arg; + struct kevent kev; + + if (ev->ev_events & EV_SIGNAL) { + int nsignal = EVENT_SIGNAL(ev); + + memset(&kev, 0, sizeof(kev)); + kev.ident = nsignal; + kev.filter = EVFILT_SIGNAL; + kev.flags = EV_ADD; + if (!(ev->ev_events & EV_PERSIST)) + kev.flags |= EV_ONESHOT; + kev.udata = INTPTR(ev); + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + if (signal(nsignal, kq_sighandler) == SIG_ERR) + return (-1); + + ev->ev_flags |= EVLIST_X_KQINKERNEL; + return (0); + } + + if (ev->ev_events & EV_READ) { + memset(&kev, 0, sizeof(kev)); + kev.ident = ev->ev_fd; + kev.filter = EVFILT_READ; +#ifdef NOTE_EOF + /* Make it behave like select() and poll() */ + kev.fflags = NOTE_EOF; +#endif + kev.flags = EV_ADD; + if (!(ev->ev_events & EV_PERSIST)) + kev.flags |= EV_ONESHOT; + kev.udata = INTPTR(ev); + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + ev->ev_flags |= EVLIST_X_KQINKERNEL; + } + + if (ev->ev_events & EV_WRITE) { + memset(&kev, 0, sizeof(kev)); + kev.ident = ev->ev_fd; + kev.filter = EVFILT_WRITE; + kev.flags = EV_ADD; + if (!(ev->ev_events & EV_PERSIST)) + kev.flags |= EV_ONESHOT; + kev.udata = INTPTR(ev); + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + ev->ev_flags |= EVLIST_X_KQINKERNEL; + } + + return (0); +} + +int +kq_del(void *arg, struct event *ev) +{ + struct kqop *kqop = arg; + struct kevent kev; + + if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) + return (0); + + if (ev->ev_events & EV_SIGNAL) { + int nsignal = EVENT_SIGNAL(ev); + + memset(&kev, 0, sizeof(kev)); + kev.ident = (int)signal; + kev.filter = EVFILT_SIGNAL; + kev.flags = EV_DELETE; + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + if (signal(nsignal, SIG_DFL) == SIG_ERR) + return (-1); + + ev->ev_flags &= ~EVLIST_X_KQINKERNEL; + return (0); + } + + if (ev->ev_events & EV_READ) { + memset(&kev, 0, sizeof(kev)); + kev.ident = ev->ev_fd; + kev.filter = EVFILT_READ; + kev.flags = EV_DELETE; + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + ev->ev_flags &= ~EVLIST_X_KQINKERNEL; + } + + if (ev->ev_events & EV_WRITE) { + memset(&kev, 0, sizeof(kev)); + kev.ident = ev->ev_fd; + kev.filter = EVFILT_WRITE; + kev.flags = EV_DELETE; + + if (kq_insert(kqop, &kev) == -1) + return (-1); + + ev->ev_flags &= ~EVLIST_X_KQINKERNEL; + } + + return (0); +} Added: trunk/varnish-cache/contrib/libevent/log.c =================================================================== --- trunk/varnish-cache/contrib/libevent/log.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/log.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,219 @@ +/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * log.c + * + * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code. + * + * Copyright (c) 2005 Nick Mathewson + * + * Copyright (c) 2000 Dug Song + * + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include "misc.h" +#endif +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include "event.h" + +#include "log.h" + +static void _warn_helper(int severity, int log_errno, const char *fmt, + va_list ap); +static void event_log(int severity, const char *msg); + +static int +event_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int r; + if (size == 0) + return -1; +#ifdef WIN32 + r = _vsnprintf(str, size, format, args); +#else + r = vsnprintf(str, size, format, args); +#endif + str[size-1] = '\0'; + if (r < 0 || ((size_t)r) >= size) { + /* different platforms behave differently on overflow; + * handle both kinds. */ + return -1; + } + return r; +} + +static int +event_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int r; + va_start(ap, format); + r = event_vsnprintf(str, size, format, ap); + va_end(ap); + return r; +} + +void +event_err(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_ERR, errno, fmt, ap); + va_end(ap); + exit(eval); +} + +void +event_warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_WARN, errno, fmt, ap); + va_end(ap); +} + +void +event_errx(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_ERR, -1, fmt, ap); + va_end(ap); + exit(eval); +} + +void +event_warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_WARN, -1, fmt, ap); + va_end(ap); +} + +void +event_msgx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_MSG, -1, fmt, ap); + va_end(ap); +} + +void +_event_debugx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap); + va_end(ap); +} + +static void +_warn_helper(int severity, int log_errno, const char *fmt, va_list ap) +{ + char buf[1024]; + size_t len; + + if (fmt != NULL) + event_vsnprintf(buf, sizeof(buf), fmt, ap); + else + buf[0] = '\0'; + + if (log_errno >= 0) { + len = strlen(buf); + if (len < sizeof(buf) - 3) { + event_snprintf(buf + len, sizeof(buf) - len, ": %s", + strerror(log_errno)); + } + } + + event_log(severity, buf); +} + +static event_log_cb log_fn = NULL; + +void +event_set_log_callback(event_log_cb cb) +{ + log_fn = cb; +} + +static void +event_log(int severity, const char *msg) +{ + if (log_fn) + log_fn(severity, msg); + else { + const char *severity_str; + switch (severity) { + case _EVENT_LOG_DEBUG: + severity_str = "debug"; + break; + case _EVENT_LOG_MSG: + severity_str = "msg"; + break; + case _EVENT_LOG_WARN: + severity_str = "warn"; + break; + case _EVENT_LOG_ERR: + severity_str = "err"; + break; + default: + severity_str = "???"; + break; + } + (void)fprintf(stderr, "[%s] %s\n", severity_str, msg); + } +} Added: trunk/varnish-cache/contrib/libevent/log.h =================================================================== --- trunk/varnish-cache/contrib/libevent/log.h 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/log.h 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000-2004 Niels Provos + * 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. + */ +#ifndef _LOG_H_ +#define _LOG_H_ + +void event_err(int eval, const char *fmt, ...); +void event_warn(const char *fmt, ...); +void event_errx(int eval, const char *fmt, ...); +void event_warnx(const char *fmt, ...); +void event_msgx(const char *fmt, ...); +void _event_debugx(const char *fmt, ...); +#undef USE_DEBUG +#ifdef USE_DEBUG +#define event_debug(x) _event_debugx x +#else +#define event_debug(x) +#endif + +#endif Added: trunk/varnish-cache/contrib/libevent/poll.c =================================================================== --- trunk/varnish-cache/contrib/libevent/poll.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/poll.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,357 @@ +/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * Copyright 2000-2003 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CHECK_INVARIANTS +#include +#endif + +#include "event.h" +#include "event-internal.h" +#include "evsignal.h" +#include "log.h" + +extern volatile sig_atomic_t evsignal_caught; + +struct pollop { + int event_count; /* Highest number alloc */ + int nfds; /* Size of event_* */ + int fd_count; /* Size of idxplus1_by_fd */ + struct pollfd *event_set; + struct event **event_r_back; + struct event **event_w_back; + int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so + * that 0 (which is easy to memset) can mean + * "no entry." */ + sigset_t evsigmask; +}; + +void *poll_init (void); +int poll_add (void *, struct event *); +int poll_del (void *, struct event *); +int poll_recalc (struct event_base *, void *, int); +int poll_dispatch (struct event_base *, void *, struct timeval *); + +struct eventop pollops = { + "poll", + poll_init, + poll_add, + poll_del, + poll_recalc, + poll_dispatch +}; + +void * +poll_init(void) +{ + struct pollop *pollop; + + /* Disable kqueue when this environment variable is set */ + if (getenv("EVENT_NOPOLL")) + return (NULL); + + if (!(pollop = calloc(1, sizeof(struct pollop)))) + return (NULL); + + evsignal_init(&pollop->evsigmask); + + return (pollop); +} + +/* + * Called with the highest fd that we know about. If it is 0, completely + * recalculate everything. + */ + +int +poll_recalc(struct event_base *base, void *arg, int max) +{ + struct pollop *pop = arg; + + return (evsignal_recalc(&pop->evsigmask)); +} + +#ifdef CHECK_INVARIANTS +static void +poll_check_ok(struct pollop *pop) +{ + int i, idx; + struct event *ev; + + for (i = 0; i < pop->fd_count; ++i) { + idx = pop->idxplus1_by_fd[i]-1; + if (idx < 0) + continue; + assert(pop->event_set[idx].fd == i); + if (pop->event_set[idx].events & POLLIN) { + ev = pop->event_r_back[idx]; + assert(ev); + assert(ev->ev_events & EV_READ); + assert(ev->ev_fd == i); + } + if (pop->event_set[idx].events & POLLOUT) { + ev = pop->event_w_back[idx]; + assert(ev); + assert(ev->ev_events & EV_WRITE); + assert(ev->ev_fd == i); + } + } + for (i = 0; i < pop->nfds; ++i) { + struct pollfd *pfd = &pop->event_set[i]; + assert(pop->idxplus1_by_fd[pfd->fd] == i+1); + } +} +#else +#define poll_check_ok(pop) +#endif + +int +poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + int res, i, sec, nfds; + struct pollop *pop = arg; + + if (evsignal_deliver(&pop->evsigmask) == -1) + return (-1); + + poll_check_ok(pop); + sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + nfds = pop->nfds; + res = poll(pop->event_set, nfds, sec); + + if (evsignal_recalc(&pop->evsigmask) == -1) + return (-1); + + if (res == -1) { + if (errno != EINTR) { + event_warn("poll"); + return (-1); + } + + evsignal_process(); + return (0); + } else if (evsignal_caught) + evsignal_process(); + + event_debug(("%s: poll reports %d", __func__, res)); + + if (res == 0) + return (0); + + for (i = 0; i < nfds; i++) { + int what = pop->event_set[i].revents; + struct event *r_ev = NULL, *w_ev = NULL; + if (!what) + continue; + + res = 0; + + /* If the file gets closed notify */ + if (what & (POLLHUP|POLLERR)) + what |= POLLIN|POLLOUT; + if (what & POLLIN) { + res |= EV_READ; + r_ev = pop->event_r_back[i]; + } + if (what & POLLOUT) { + res |= EV_WRITE; + w_ev = pop->event_w_back[i]; + } + if (res == 0) + continue; + + if (r_ev && (res & r_ev->ev_events)) { + if (!(r_ev->ev_events & EV_PERSIST)) + event_del(r_ev); + event_active(r_ev, res & r_ev->ev_events, 1); + } + if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { + if (!(w_ev->ev_events & EV_PERSIST)) + event_del(w_ev); + event_active(w_ev, res & w_ev->ev_events, 1); + } + } + + return (0); +} + +int +poll_add(void *arg, struct event *ev) +{ + struct pollop *pop = arg; + struct pollfd *pfd = NULL; + int i; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&pop->evsigmask, ev)); + if (!(ev->ev_events & (EV_READ|EV_WRITE))) + return (0); + + poll_check_ok(pop); + if (pop->nfds + 1 >= pop->event_count) { + if (pop->event_count < 32) + pop->event_count = 32; + else + pop->event_count *= 2; + + /* We need more file descriptors */ + pop->event_set = realloc(pop->event_set, + pop->event_count * sizeof(struct pollfd)); + if (pop->event_set == NULL) { + event_warn("realloc"); + return (-1); + } + pop->event_r_back = realloc(pop->event_r_back, + pop->event_count * sizeof(struct event *)); + pop->event_w_back = realloc(pop->event_w_back, + pop->event_count * sizeof(struct event *)); + if (pop->event_r_back == NULL || + pop->event_w_back == NULL) { + event_warn("realloc"); + return (-1); + } + } + if (ev->ev_fd >= pop->fd_count) { + int new_count; + if (pop->fd_count < 32) + new_count = 32; + else + new_count = pop->fd_count * 2; + while (new_count <= ev->ev_fd) + new_count *= 2; + pop->idxplus1_by_fd = + realloc(pop->idxplus1_by_fd, new_count*sizeof(int)); + if (pop->idxplus1_by_fd == NULL) { + event_warn("realloc"); + return (-1); + } + memset(pop->idxplus1_by_fd + pop->fd_count, + 0, sizeof(int)*(new_count - pop->fd_count)); + pop->fd_count = new_count; + } + + i = pop->idxplus1_by_fd[ev->ev_fd] - 1; + if (i >= 0) { + pfd = &pop->event_set[i]; + } else { + i = pop->nfds++; + pfd = &pop->event_set[i]; + pfd->events = 0; + pfd->fd = ev->ev_fd; + pop->event_w_back[i] = pop->event_r_back[i] = NULL; + pop->idxplus1_by_fd[ev->ev_fd] = i + 1; + } + + pfd->revents = 0; + if (ev->ev_events & EV_WRITE) { + pfd->events |= POLLOUT; + pop->event_w_back[i] = ev; + } + if (ev->ev_events & EV_READ) { + pfd->events |= POLLIN; + pop->event_r_back[i] = ev; + } + poll_check_ok(pop); + + return (0); +} + +/* + * Nothing to be done here. + */ + +int +poll_del(void *arg, struct event *ev) +{ + struct pollop *pop = arg; + struct pollfd *pfd = NULL; + int i; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(&pop->evsigmask, ev)); + + if (!(ev->ev_events & (EV_READ|EV_WRITE))) + return (0); + + poll_check_ok(pop); + i = pop->idxplus1_by_fd[ev->ev_fd] - 1; + if (i < 0) + return (-1); + + /* Do we still want to read or write? */ + pfd = &pop->event_set[i]; + if (ev->ev_events & EV_READ) { + pfd->events &= ~POLLIN; + pop->event_r_back[i] = NULL; + } + if (ev->ev_events & EV_WRITE) { + pfd->events &= ~POLLOUT; + pop->event_w_back[i] = NULL; + } + poll_check_ok(pop); + if (pfd->events) + /* Another event cares about that fd. */ + return (0); + + /* Okay, so we aren't interested in that fd anymore. */ + pop->idxplus1_by_fd[ev->ev_fd] = 0; + + --pop->nfds; + if (i != pop->nfds) { + /* + * Shift the last pollfd down into the now-unoccupied + * position. + */ + memcpy(&pop->event_set[i], &pop->event_set[pop->nfds], + sizeof(struct pollfd)); + pop->event_r_back[i] = pop->event_r_back[pop->nfds]; + pop->event_w_back[i] = pop->event_w_back[pop->nfds]; + pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1; + } + + poll_check_ok(pop); + return (0); +} Added: trunk/varnish-cache/contrib/libevent/rtsig.c =================================================================== --- trunk/varnish-cache/contrib/libevent/rtsig.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/rtsig.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,435 @@ +#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 +#ifndef HAVE_WORKING_RTSIG +#include +#endif +#include + +#define EVLIST_X_NORT 0x1000 /* Skip RT signals (internal) */ + +#include "event.h" +#include "log.h" +extern struct event_list signalqueue; + +struct rtsigop { + sigset_t sigs; + struct pollfd *poll; + struct event **toev; + int cur, max, total; +#ifndef HAVE_WORKING_RTSIG + int pollmode; +#endif +}; + +#define INIT_MAX 16 + +static int +poll_add(struct rtsigop *op, struct event *ev) +{ + struct pollfd *pfd; + + if (op->poll == NULL) return 0; + + if (op->cur == op->max) { + void *p; + + p = realloc(op->poll, sizeof(*op->poll) * (op->max << 1)); + if (!p) { + errno = ENOMEM; + return -1; + } + op->poll = p; + p = realloc(op->toev, sizeof(*op->toev) * (op->max << 1)); + if (!p) { + op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); + errno = ENOMEM; + return -1; + } + op->toev = p; + op->max <<= 1; + } + + pfd = &op->poll[op->cur]; + pfd->fd = ev->ev_fd; + pfd->events = 0; + if (ev->ev_events & EV_READ) pfd->events |= POLLIN; + if (ev->ev_events & EV_WRITE) pfd->events |= POLLOUT; + pfd->revents = 0; + + op->toev[op->cur] = ev; + 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->toev[n] = op->toev[op->cur]; + } + if (op->max > INIT_MAX && op->cur < op->max >> 1) { + op->max >>= 1; + op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); + op->toev = realloc(op->toev, sizeof(*op->toev) * op->max); + } +} + +static void +poll_remove(struct rtsigop *op, struct event *ev) +{ + int i; + + for (i = 0; i < op->cur; i++) { + if (op->toev[i] == ev) { + poll_free(op, i); + break; + } + } +} + +static void +activate(struct event *ev, int flags) +{ + if (!(ev->ev_events & EV_PERSIST)) event_del(ev); + event_active(ev, flags, 1); +} + +void *rtsig_init(void); +int rtsig_add(void *, struct event *); +int rtsig_del(void *, struct event *); +int rtsig_recalc(struct event_base *, void *, int); +int rtsig_dispatch(struct event_base *, void *, struct timeval *); + +struct eventop rtsigops = { + "rtsig", + rtsig_init, + rtsig_add, + rtsig_del, + rtsig_recalc, + rtsig_dispatch +}; + +void * +rtsig_init(void) +{ + struct rtsigop *op; + + if (getenv("EVENT_NORTSIG")) + return (NULL); + + op = malloc(sizeof(*op)); + if (op == NULL) return (NULL); + + memset(op, 0, sizeof(*op)); + + op->max = INIT_MAX; + op->poll = malloc(sizeof(*op->poll) * op->max); + if (op->poll == NULL) { + free(op); + return (NULL); + } + op->toev = malloc(sizeof(*op->toev) * op->max); + if (op->toev == NULL) { + free(op->poll); + free(op); + return (NULL); + } + + sigemptyset(&op->sigs); + sigaddset(&op->sigs, SIGIO); + sigaddset(&op->sigs, SIGRTMIN); + sigprocmask(SIG_BLOCK, &op->sigs, NULL); + + return (op); +} + +int +rtsig_add(void *arg, struct event *ev) +{ + struct rtsigop *op = (struct rtsigop *) arg; + int flags, i; +#ifndef HAVE_WORKING_RTSIG + struct stat st; +#endif + + if (ev->ev_events & EV_SIGNAL) { + sigaddset(&op->sigs, EVENT_SIGNAL(ev)); + return sigprocmask(SIG_BLOCK, &op->sigs, NULL); + } + + if (!(ev->ev_events & (EV_READ | EV_WRITE))) return 0; + +#ifndef HAVE_WORKING_RTSIG + if (fstat(ev->ev_fd, &st) == -1) return -1; + if (S_ISFIFO(st.st_mode)) { + ev->ev_flags |= EVLIST_X_NORT; + op->pollmode++; + } +#endif + + flags = fcntl(ev->ev_fd, F_GETFL); + if (flags == -1) + return (-1); + + if (!(flags & O_ASYNC)) { + if (fcntl(ev->ev_fd, F_SETSIG, SIGRTMIN) == -1 + || fcntl(ev->ev_fd, F_SETOWN, (int) getpid()) == -1) + return (-1); + + if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC)) + return (-1); + } + +#ifdef O_ONESIGFD + fcntl(ev->ev_fd, F_SETAUXFL, O_ONESIGFD); +#endif + + op->total++; + if (poll_add(op, ev) == -1) + goto err; + + return (0); + + err: + i = errno; + fcntl(ev->ev_fd, F_SETFL, flags); + errno = i; + return (-1); +} + +int +rtsig_del(void *arg, struct event *ev) +{ + 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); + +#ifndef HAVE_WORKING_RTSIG + if (ev->ev_flags & EVLIST_X_NORT) + op->pollmode--; +#endif + poll_remove(op, ev); + op->total--; + + return (0); +} + +int +rtsig_recalc(struct event_base *base, void *arg, int max) +{ + return (0); +} + +int +rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + struct rtsigop *op = (struct rtsigop *) arg; + struct timespec ts; + int res, i; + + if (op->poll == NULL) + goto retry_poll; +#ifndef HAVE_WORKING_RTSIG + if (op->pollmode) + goto poll_all; +#endif + + if (op->cur) { + ts.tv_sec = ts.tv_nsec = 0; + } else { + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; + } + + for (;;) { + siginfo_t info; + struct event *ev; + int signum; + + signum = sigtimedwait(&op->sigs, &info, &ts); + + if (signum == -1) { + if (errno == EAGAIN) + break; + return (errno == EINTR ? 0 : -1); + } + + ts.tv_sec = ts.tv_nsec = 0; + + if (signum == SIGIO) { +#ifndef HAVE_WORKING_RTSIG + poll_all: +#endif + free(op->poll); + free(op->toev); + retry_poll: + op->cur = 0; + op->max = op->total; + op->poll = malloc(sizeof(*op->poll) * op->total); + if (op->poll == NULL) + return (-1); + op->toev = malloc(sizeof(*op->toev) * op->total); + if (op->toev == NULL) { + free(op->poll); + op->poll = NULL; + return (-1); + } + + TAILQ_FOREACH(ev, &base->eventqueue, ev_next) + if (!(ev->ev_flags & EVLIST_X_NORT)) + poll_add(op, ev); + + break; + } + + if (signum == SIGRTMIN) { + int flags, i, sigok = 0; + + if (info.si_band <= 0) { /* SI_SIGIO */ + flags = EV_READ | EV_WRITE; + } else { + flags = 0; + if (info.si_band & POLLIN) flags |= EV_READ; + if (info.si_band & POLLOUT) flags |= EV_WRITE; + if (!flags) continue; + } + + for (i = 0; flags && i < op->cur; i++) { + ev = op->toev[i]; + + if (ev->ev_fd == info.si_fd) { + flags &= ~ev->ev_events; + sigok = 1; + } + } + + for (ev = TAILQ_FIRST(&base->eventqueue); + flags && ev != TAILQ_END(&base->eventqueue); + ev = TAILQ_NEXT(ev, ev_next)) { + if (ev->ev_fd == info.si_fd) { + if (flags & ev->ev_events) { + i = poll_add(op, ev); + if (i == -1) return -1; + flags &= ~ev->ev_events; + } + sigok = 1; + } + } + + if (!sigok) { + flags = fcntl(info.si_fd, F_GETFL); + if (flags == -1) return -1; + fcntl(info.si_fd, F_SETFL, flags & ~O_ASYNC); + } + } else { + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if (EVENT_SIGNAL(ev) == signum) + activate(ev, EV_SIGNAL); + } + } + } + + if (!op->cur) + return (0); + + res = poll(op->poll, op->cur, tv->tv_sec * 1000 + + (tv->tv_usec + 999) / 1000); + if (res < 0) + return (-1); + + i = 0; +#ifdef HAVE_WORKING_RTSIG + while (i < res) { +#else + while (i < op->cur) { +#endif + if (op->poll[i].revents) { + int flags = 0; + struct event *ev = op->toev[i]; + + if (op->poll[i].revents & POLLIN) + flags |= EV_READ; + if (op->poll[i].revents & POLLOUT) + flags |= EV_WRITE; + + if (!(ev->ev_events & EV_PERSIST)) { + event_del(ev); + res--; + } else { + i++; + } + event_active(ev, flags, 1); + } else { +#ifndef HAVE_WORKING_RTSIG + if (op->toev[i]->ev_flags & EVLIST_X_NORT) { + i++; + res++; + continue; + } +#endif + for (;;) { + op->cur--; + if (i == op->cur) + break; + if (op->poll[op->cur].revents) { + memcpy(&op->poll[i], &op->poll[op->cur], sizeof(*op->poll)); + op->toev[i] = op->toev[op->cur]; + break; + } + } + } + } +#ifdef HAVE_WORKING_RTSIG + op->cur = res; +#endif + + if (!op->cur) { + op->max = INIT_MAX; + free(op->poll); + free(op->toev); + /* We just freed it, we shouldn't have a problem getting it back. */ + op->poll = malloc(sizeof(*op->poll) * op->max); + op->toev = malloc(sizeof(*op->toev) * op->max); + + if (op->poll == NULL || op->toev == NULL) + event_err(1, "%s: malloc"); + } + + return (0); +} Added: trunk/varnish-cache/contrib/libevent/sample/Makefile.am =================================================================== --- trunk/varnish-cache/contrib/libevent/sample/Makefile.am 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/sample/Makefile.am 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,15 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +LDADD = ../libevent.la +CPPFPLAGS = -I.. +CFLAGS = -I../compat + +noinst_PROGRAMS = event-test time-test signal-test + +event_test_sources = event-test.c +time_test_sources = time-test.c +signal_test_sources = signal-test.c + +verify: + +DISTCLEANFILES = *~ Added: trunk/varnish-cache/contrib/libevent/sample/Makefile.in =================================================================== --- trunk/varnish-cache/contrib/libevent/sample/Makefile.in 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/sample/Makefile.in 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,430 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + at SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = event-test$(EXEEXT) time-test$(EXEEXT) \ + signal-test$(EXEEXT) +subdir = sample +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +event_test_SOURCES = event-test.c +event_test_OBJECTS = event-test.$(OBJEXT) +event_test_LDADD = $(LDADD) +event_test_DEPENDENCIES = ../libevent.la +signal_test_SOURCES = signal-test.c +signal_test_OBJECTS = signal-test.$(OBJEXT) +signal_test_LDADD = $(LDADD) +signal_test_DEPENDENCIES = ../libevent.la +time_test_SOURCES = time-test.c +time_test_OBJECTS = time-test.$(OBJEXT) +time_test_LDADD = $(LDADD) +time_test_DEPENDENCIES = ../libevent.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = event-test.c signal-test.c time-test.c +DIST_SOURCES = event-test.c signal-test.c time-test.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = -I../compat +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AUTOMAKE_OPTIONS = foreign no-dependencies +LDADD = ../libevent.la +CPPFPLAGS = -I.. +event_test_sources = event-test.c +time_test_sources = time-test.c +signal_test_sources = signal-test.c +DISTCLEANFILES = *~ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sample/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign sample/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +event-test$(EXEEXT): $(event_test_OBJECTS) $(event_test_DEPENDENCIES) + @rm -f event-test$(EXEEXT) + $(LINK) $(event_test_LDFLAGS) $(event_test_OBJECTS) $(event_test_LDADD) $(LIBS) +signal-test$(EXEEXT): $(signal_test_OBJECTS) $(signal_test_DEPENDENCIES) + @rm -f signal-test$(EXEEXT) + $(LINK) $(signal_test_LDFLAGS) $(signal_test_OBJECTS) $(signal_test_LDADD) $(LIBS) +time-test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) + @rm -f time-test$(EXEEXT) + $(LINK) $(time_test_LDFLAGS) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + + +verify: +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Added: trunk/varnish-cache/contrib/libevent/sample/event-test.c =================================================================== --- trunk/varnish-cache/contrib/libevent/sample/event-test.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/sample/event-test.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,135 @@ +/* + * Compile with: + * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent + */ + +#include +#include +#ifndef WIN32 +#include +#include +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +#include + +void +fifo_read(int fd, short event, void *arg) +{ + char buf[255]; + int len; + struct event *ev = arg; +#ifdef WIN32 + DWORD dwBytesRead; +#endif + + /* Reschedule this event */ + event_add(ev, NULL); + + fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n", + fd, event, arg); +#ifdef WIN32 + len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL); + + // Check for end of file. + if(len && dwBytesRead == 0) { + fprintf(stderr, "End Of File"); + event_del(ev); + return; + } + + buf[dwBytesRead] = '\0'; +#else + len = read(fd, buf, sizeof(buf) - 1); + + if (len == -1) { + perror("read"); + return; + } else if (len == 0) { + fprintf(stderr, "Connection closed\n"); + return; + } + + buf[len] = '\0'; +#endif + fprintf(stdout, "Read: %s\n", buf); +} + +int +main (int argc, char **argv) +{ + struct event evfifo; +#ifdef WIN32 + HANDLE socket; + // Open a file. + socket = CreateFile("test.txt", // open File + GENERIC_READ, // open for reading + 0, // do not share + NULL, // no security + OPEN_EXISTING, // existing file only + FILE_ATTRIBUTE_NORMAL, // normal file + NULL); // no attr. template + + if(socket == INVALID_HANDLE_VALUE) + return 1; + +#else + struct stat st; + char *fifo = "event.fifo"; + int socket; + + if (lstat (fifo, &st) == 0) { + if ((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + perror("lstat"); + exit (1); + } + } + + unlink (fifo); + if (mkfifo (fifo, 0600) == -1) { + perror("mkfifo"); + exit (1); + } + + /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */ +#ifdef __linux + socket = open (fifo, O_RDWR | O_NONBLOCK, 0); +#else + socket = open (fifo, O_RDONLY | O_NONBLOCK, 0); +#endif + + if (socket == -1) { + perror("open"); + exit (1); + } + + fprintf(stderr, "Write data to %s\n", fifo); +#endif + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ +#ifdef WIN32 + event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo); +#else + event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo); +#endif + + /* Add it to the active events, without a timeout */ + event_add(&evfifo, NULL); + + event_dispatch(); +#ifdef WIN32 + CloseHandle(socket); +#endif + return (0); +} + Added: trunk/varnish-cache/contrib/libevent/sample/signal-test.c =================================================================== --- trunk/varnish-cache/contrib/libevent/sample/signal-test.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/sample/signal-test.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,62 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifndef WIN32 +#include +#include +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include + +#include + +int called = 0; + +void +signal_cb(int fd, short event, void *arg) +{ + struct event *signal = arg; + + printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal)); + + if (called >= 2) + event_del(signal); + + called++; +} + +int +main (int argc, char **argv) +{ + struct event signal_int; + + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ + event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb, + &signal_int); + + event_add(&signal_int, NULL); + + event_dispatch(); + + return (0); +} + Added: trunk/varnish-cache/contrib/libevent/sample/time-test.c =================================================================== --- trunk/varnish-cache/contrib/libevent/sample/time-test.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/sample/time-test.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,70 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifndef WIN32 +#include +#include +#else +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#include +#include +#include +#include + +#include + +int lasttime; + +void +timeout_cb(int fd, short event, void *arg) +{ + struct timeval tv; + struct event *timeout = arg; + int newtime = time(NULL); + + printf("%s: called at %d: %d\n", __func__, newtime, + newtime - lasttime); + lasttime = newtime; + + timerclear(&tv); + tv.tv_sec = 2; + event_add(timeout, &tv); +} + +int +main (int argc, char **argv) +{ + struct event timeout; + struct timeval tv; + + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ + evtimer_set(&timeout, timeout_cb, &timeout); + + timerclear(&tv); + tv.tv_sec = 2; + event_add(&timeout, &tv); + + lasttime = time(NULL); + + event_dispatch(); + + return (0); +} + Added: trunk/varnish-cache/contrib/libevent/select.c =================================================================== --- trunk/varnish-cache/contrib/libevent/select.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/select.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,352 @@ +/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * Copyright 2000-2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CHECK_INVARIANTS +#include +#endif + +#include "event.h" +#include "event-internal.h" +#include "evsignal.h" +#include "log.h" + +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif + +extern volatile sig_atomic_t evsignal_caught; + +struct selectop { + int event_fds; /* Highest fd in fd set */ + int event_fdsz; + fd_set *event_readset_in; + fd_set *event_writeset_in; + fd_set *event_readset_out; + fd_set *event_writeset_out; + struct event **event_r_by_fd; + struct event **event_w_by_fd; + sigset_t evsigmask; +}; + +void *select_init (void); +int select_add (void *, struct event *); +int select_del (void *, struct event *); +int select_recalc (struct event_base *, void *, int); +int select_dispatch (struct event_base *, void *, struct timeval *); + +const struct eventop selectops = { + "select", + select_init, + select_add, + select_del, + select_recalc, + select_dispatch +}; + +static int select_resize(struct selectop *sop, int fdsz); + +void * +select_init(void) +{ + struct selectop *sop; + + /* Disable kqueue when this environment variable is set */ + if (getenv("EVENT_NOSELECT")) + return (NULL); + + if (!(sop = calloc(1, sizeof(struct selectop)))) + return (NULL); + + select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); + + evsignal_init(&sop->evsigmask); + + return (sop); +} + +#ifdef CHECK_INVARIANTS +static void +check_selectop(struct selectop *sop) +{ + int i; + for (i=0;i<=sop->event_fds;++i) { + if (FD_ISSET(i, sop->event_readset_in)) { + assert(sop->event_r_by_fd[i]); + assert(sop->event_r_by_fd[i]->ev_events & EV_READ); + assert(sop->event_r_by_fd[i]->ev_fd == i); + } else { + assert(! sop->event_r_by_fd[i]); + } + if (FD_ISSET(i, sop->event_writeset_in)) { + assert(sop->event_w_by_fd[i]); + assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE); + assert(sop->event_w_by_fd[i]->ev_fd == i); + } else { + assert(! sop->event_w_by_fd[i]); + } + } + +} +#else +#define check_selectop(sop) +#endif + +/* + * Called with the highest fd that we know about. If it is 0, completely + * recalculate everything. + */ + +int +select_recalc(struct event_base *base, void *arg, int max) +{ + struct selectop *sop = arg; + + check_selectop(sop); + + return (evsignal_recalc(&sop->evsigmask)); +} + +int +select_dispatch(struct event_base *base, void *arg, struct timeval *tv) +{ + int res, i; + struct selectop *sop = arg; + + check_selectop(sop); + + memcpy(sop->event_readset_out, sop->event_readset_in, + sop->event_fdsz); + memcpy(sop->event_writeset_out, sop->event_writeset_in, + sop->event_fdsz); + + if (evsignal_deliver(&sop->evsigmask) == -1) + return (-1); + + res = select(sop->event_fds + 1, sop->event_readset_out, + sop->event_writeset_out, NULL, tv); + + check_selectop(sop); + if (evsignal_recalc(&sop->evsigmask) == -1) + return (-1); + + if (res == -1) { + if (errno != EINTR) { + event_warn("select"); + return (-1); + } + + evsignal_process(); + return (0); + } else if (evsignal_caught) + evsignal_process(); + + event_debug(("%s: select reports %d", __func__, res)); + + check_selectop(sop); + for (i = 0; i <= sop->event_fds; ++i) { + struct event *r_ev = NULL, *w_ev = NULL; + res = 0; + if (FD_ISSET(i, sop->event_readset_out)) { + r_ev = sop->event_r_by_fd[i]; + res |= EV_READ; + } + if (FD_ISSET(i, sop->event_writeset_out)) { + w_ev = sop->event_w_by_fd[i]; + res |= EV_WRITE; + } + if (r_ev && (res & r_ev->ev_events)) { + if (!(r_ev->ev_events & EV_PERSIST)) + event_del(r_ev); + event_active(r_ev, res & r_ev->ev_events, 1); + } + if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { + if (!(w_ev->ev_events & EV_PERSIST)) + event_del(w_ev); + event_active(w_ev, res & w_ev->ev_events, 1); + } + } + check_selectop(sop); + + return (0); +} + + +static int +select_resize(struct selectop *sop, int fdsz) +{ + int n_events, n_events_old; + + fd_set *readset_in = NULL; + fd_set *writeset_in = NULL; + fd_set *readset_out = NULL; + fd_set *writeset_out = NULL; + struct event **r_by_fd = NULL; + struct event **w_by_fd = NULL; + + n_events = (fdsz/sizeof(fd_mask)) * NFDBITS; + n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS; + + if (sop->event_readset_in) + check_selectop(sop); + + if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL) + goto error; + sop->event_readset_in = readset_in; + if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL) + goto error; + sop->event_readset_out = readset_out; + if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL) + goto error; + sop->event_writeset_in = writeset_in; + if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL) + goto error; + sop->event_writeset_out = writeset_out; + if ((r_by_fd = realloc(sop->event_r_by_fd, + n_events*sizeof(struct event*))) == NULL) + goto error; + sop->event_r_by_fd = r_by_fd; + if ((w_by_fd = realloc(sop->event_w_by_fd, + n_events * sizeof(struct event*))) == NULL) + goto error; + sop->event_w_by_fd = w_by_fd; + + memset((char *)sop->event_readset_in + sop->event_fdsz, 0, + fdsz - sop->event_fdsz); + memset((char *)sop->event_writeset_in + sop->event_fdsz, 0, + fdsz - sop->event_fdsz); + memset(sop->event_r_by_fd + n_events_old, 0, + (n_events-n_events_old) * sizeof(struct event*)); + memset(sop->event_w_by_fd + n_events_old, 0, + (n_events-n_events_old) * sizeof(struct event*)); + + sop->event_fdsz = fdsz; + check_selectop(sop); + + return (0); + + error: + event_warn("malloc"); + return (-1); +} + + +int +select_add(void *arg, struct event *ev) +{ + struct selectop *sop = arg; + + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(&sop->evsigmask, ev)); + + check_selectop(sop); + /* + * Keep track of the highest fd, so that we can calculate the size + * of the fd_sets for select(2) + */ + if (sop->event_fds < ev->ev_fd) { + int fdsz = sop->event_fdsz; + + if (fdsz < sizeof(fd_mask)) + fdsz = sizeof(fd_mask); + + while (fdsz < + (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask))) + fdsz *= 2; + + if (fdsz != sop->event_fdsz) { + if (select_resize(sop, fdsz)) { + check_selectop(sop); + return (-1); + } + } + + sop->event_fds = ev->ev_fd; + } + + if (ev->ev_events & EV_READ) { + FD_SET(ev->ev_fd, sop->event_readset_in); + sop->event_r_by_fd[ev->ev_fd] = ev; + } + if (ev->ev_events & EV_WRITE) { + FD_SET(ev->ev_fd, sop->event_writeset_in); + sop->event_w_by_fd[ev->ev_fd] = ev; + } + check_selectop(sop); + + return (0); +} + +/* + * Nothing to be done here. + */ + +int +select_del(void *arg, struct event *ev) +{ + struct selectop *sop = arg; + + check_selectop(sop); + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(&sop->evsigmask, ev)); + + if (sop->event_fds < ev->ev_fd) { + check_selectop(sop); + return (0); + } + + if (ev->ev_events & EV_READ) { + FD_CLR(ev->ev_fd, sop->event_readset_in); + sop->event_r_by_fd[ev->ev_fd] = NULL; + } + + if (ev->ev_events & EV_WRITE) { + FD_CLR(ev->ev_fd, sop->event_writeset_in); + sop->event_w_by_fd[ev->ev_fd] = NULL; + } + + check_selectop(sop); + return (0); +} Added: trunk/varnish-cache/contrib/libevent/signal.c =================================================================== --- trunk/varnish-cache/contrib/libevent/signal.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/signal.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,204 @@ +/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ + +/* + * Copyright 2000-2002 Niels Provos + * 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. + */ +#include "config.h" + +#include +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "event.h" +#include "evsignal.h" +#include "log.h" + +extern struct event_list signalqueue; + +static short evsigcaught[NSIG]; +static int needrecalc; +volatile sig_atomic_t evsignal_caught = 0; + +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) + event_err(1, "%s: read", __func__); + event_add(ev, NULL); +} + +#ifdef HAVE_SETFD +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + event_warn("fcntl(%d, F_SETFD)", x); \ +} while (0) +#else +#define FD_CLOSEONEXEC(x) +#endif + +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) + event_err(1, "%s: socketpair", __func__); + + FD_CLOSEONEXEC(ev_signal_pair[0]); + FD_CLOSEONEXEC(ev_signal_pair[1]); + + event_set(&ev_signal, ev_signal_pair[1], EV_READ, + evsignal_cb, &ev_signal); + ev_signal.ev_flags |= EVLIST_INTERNAL; +} + +int +evsignal_add(sigset_t *evsigmask, struct event *ev) +{ + int evsignal; + + if (ev->ev_events & (EV_READ|EV_WRITE)) + event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); + evsignal = EVENT_SIGNAL(ev); + sigaddset(evsigmask, evsignal); + + return (0); +} + +/* + * Nothing to be done here. + */ + +int +evsignal_del(sigset_t *evsigmask, struct event *ev) +{ + int evsignal; + + evsignal = EVENT_SIGNAL(ev); + sigdelset(evsigmask, evsignal); + needrecalc = 1; + + return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); +} + +static void +evsignal_handler(int sig) +{ + evsigcaught[sig]++; + evsignal_caught = 1; + + /* Wake up our notification mechanism */ + write(ev_signal_pair[0], "a", 1); +} + +int +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); + needrecalc = 0; + + if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1) + return (-1); + + /* Reinstall our signal handler. */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = evsignal_handler; + sa.sa_mask = *evsigmask; + sa.sa_flags |= SA_RESTART; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1) + return (-1); + } + return (0); +} + +int +evsignal_deliver(sigset_t *evsigmask) +{ + if (TAILQ_FIRST(&signalqueue) == NULL) + return (0); + + return (sigprocmask(SIG_UNBLOCK, evsigmask, NULL)); + /* XXX - pending signals handled here */ +} + +void +evsignal_process(void) +{ + struct event *ev; + short ncalls; + + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + ncalls = evsigcaught[EVENT_SIGNAL(ev)]; + if (ncalls) { + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, EV_SIGNAL, ncalls); + } + } + + memset(evsigcaught, 0, sizeof(evsigcaught)); + evsignal_caught = 0; +} + Added: trunk/varnish-cache/contrib/libevent/test/Makefile.am =================================================================== --- trunk/varnish-cache/contrib/libevent/test/Makefile.am 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/Makefile.am 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,23 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +LDADD = ../libevent.la +CPPFPLAGS = -I.. +CFLAGS = -I../compat @CFLAGS@ + +noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench + +test_init_sources = test-init.c +test_eof_sources = test-eof.c +test_weof_sources = test-weof.c +test_time_sources = test-time.c +regress_sources = regress.c +bench_sources = bench.c + +DISTCLEANFILES = *~ + +test: test-init test-eof test-weof test-time regress + +verify: test + @./test.sh + +bench test-init test-eof test-weof test-time regress: ../libevent.la Added: trunk/varnish-cache/contrib/libevent/test/Makefile.in =================================================================== --- trunk/varnish-cache/contrib/libevent/test/Makefile.in 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/Makefile.in 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,462 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + at SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = test-init$(EXEEXT) test-eof$(EXEEXT) \ + test-weof$(EXEEXT) test-time$(EXEEXT) regress$(EXEEXT) \ + bench$(EXEEXT) +subdir = test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +bench_SOURCES = bench.c +bench_OBJECTS = bench.$(OBJEXT) +bench_LDADD = $(LDADD) +bench_DEPENDENCIES = ../libevent.la +regress_SOURCES = regress.c +regress_OBJECTS = regress.$(OBJEXT) +regress_LDADD = $(LDADD) +regress_DEPENDENCIES = ../libevent.la +test_eof_SOURCES = test-eof.c +test_eof_OBJECTS = test-eof.$(OBJEXT) +test_eof_LDADD = $(LDADD) +test_eof_DEPENDENCIES = ../libevent.la +test_init_SOURCES = test-init.c +test_init_OBJECTS = test-init.$(OBJEXT) +test_init_LDADD = $(LDADD) +test_init_DEPENDENCIES = ../libevent.la +test_time_SOURCES = test-time.c +test_time_OBJECTS = test-time.$(OBJEXT) +test_time_LDADD = $(LDADD) +test_time_DEPENDENCIES = ../libevent.la +test_weof_SOURCES = test-weof.c +test_weof_OBJECTS = test-weof.$(OBJEXT) +test_weof_LDADD = $(LDADD) +test_weof_DEPENDENCIES = ../libevent.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = bench.c regress.c test-eof.c test-init.c test-time.c \ + test-weof.c +DIST_SOURCES = bench.c regress.c test-eof.c test-init.c test-time.c \ + test-weof.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = -I../compat @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AUTOMAKE_OPTIONS = foreign no-dependencies +LDADD = ../libevent.la +CPPFPLAGS = -I.. +test_init_sources = test-init.c +test_eof_sources = test-eof.c +test_weof_sources = test-weof.c +test_time_sources = test-time.c +regress_sources = regress.c +bench_sources = bench.c +DISTCLEANFILES = *~ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +bench$(EXEEXT): $(bench_OBJECTS) $(bench_DEPENDENCIES) + @rm -f bench$(EXEEXT) + $(LINK) $(bench_LDFLAGS) $(bench_OBJECTS) $(bench_LDADD) $(LIBS) +regress$(EXEEXT): $(regress_OBJECTS) $(regress_DEPENDENCIES) + @rm -f regress$(EXEEXT) + $(LINK) $(regress_LDFLAGS) $(regress_OBJECTS) $(regress_LDADD) $(LIBS) +test-eof$(EXEEXT): $(test_eof_OBJECTS) $(test_eof_DEPENDENCIES) + @rm -f test-eof$(EXEEXT) + $(LINK) $(test_eof_LDFLAGS) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS) +test-init$(EXEEXT): $(test_init_OBJECTS) $(test_init_DEPENDENCIES) + @rm -f test-init$(EXEEXT) + $(LINK) $(test_init_LDFLAGS) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS) +test-time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) + @rm -f test-time$(EXEEXT) + $(LINK) $(test_time_LDFLAGS) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) +test-weof$(EXEEXT): $(test_weof_OBJECTS) $(test_weof_DEPENDENCIES) + @rm -f test-weof$(EXEEXT) + $(LINK) $(test_weof_LDFLAGS) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + + +test: test-init test-eof test-weof test-time regress + +verify: test + @./test.sh + +bench test-init test-eof test-weof test-time regress: ../libevent.la +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Added: trunk/varnish-cache/contrib/libevent/test/bench.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/bench.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/bench.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,181 @@ +/* + * Copyright 2003 Niels Provos + * 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. + * 4. 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. + * + * + * Mon 03/10/2003 - Modified by Davide Libenzi + * + * Added chain event propagation to improve the sensitivity of + * the measure respect to the event loop efficency. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static int count, writes, fired; +static int *pipes; +static int num_pipes, num_active, num_writes; +static struct event *events; + + + +void +read_cb(int fd, short which, void *arg) +{ + int idx = (int) arg, widx = idx + 1; + u_char ch; + + count += read(fd, &ch, sizeof(ch)); + if (writes) { + if (widx >= num_pipes) + widx -= num_pipes; + write(pipes[2 * widx + 1], "e", 1); + writes--; + fired++; + } +} + +struct timeval * +run_once(void) +{ + int *cp, i, space; + static struct timeval ts, te; + + for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { + event_del(&events[i]); + event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *) i); + event_add(&events[i], NULL); + } + + event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); + + fired = 0; + space = num_pipes / num_active; + space = space * 2; + for (i = 0; i < num_active; i++, fired++) + write(pipes[i * space + 1], "e", 1); + + count = 0; + writes = num_writes; + { int xcount = 0; + gettimeofday(&ts, NULL); + do { + event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); + xcount++; + } while (count != fired); + gettimeofday(&te, NULL); + + if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); + } + + timersub(&te, &ts, &te); + + return (&te); +} + +int +main (int argc, char **argv) +{ + struct rlimit rl; + int i, c; + struct timeval *tv; + int *cp; + extern char *optarg; + + num_pipes = 100; + num_active = 1; + num_writes = num_pipes; + while ((c = getopt(argc, argv, "n:a:w:")) != -1) { + switch (c) { + case 'n': + num_pipes = atoi(optarg); + break; + case 'a': + num_active = atoi(optarg); + break; + case 'w': + num_writes = atoi(optarg); + break; + default: + fprintf(stderr, "Illegal argument \"%c\"\n", c); + exit(1); + } + } + + rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; + if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { + perror("setrlimit"); + exit(1); + } + + events = calloc(num_pipes, sizeof(struct event)); + pipes = calloc(num_pipes * 2, sizeof(int)); + if (events == NULL || pipes == NULL) { + perror("malloc"); + exit(1); + } + + event_init(); + + for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { +#ifdef USE_PIPES + if (pipe(cp) == -1) { +#else + if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { +#endif + perror("pipe"); + exit(1); + } + } + + for (i = 0; i < 25; i++) { + tv = run_once(); + if (tv == NULL) + exit(1); + fprintf(stdout, "%ld\n", + tv->tv_sec * 1000000L + tv->tv_usec); + } + + exit(0); +} Added: trunk/varnish-cache/contrib/libevent/test/regress.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/regress.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/regress.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2003, 2004 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include +#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 + +static int pair[2]; +static int test_ok; +static int called; +static char wbuf[4096]; +static char rbuf[4096]; +static int woff; +static int roff; +static int usepersist; +static struct timeval tset; +static struct timeval tcalled; +static struct event_base *event_base; + +#define TEST1 "this is a test" +#define SECONDS 1 + +void +simple_read_cb(int fd, short event, void *arg) +{ + char buf[256]; + int len; + + len = read(fd, buf, sizeof(buf)); + + if (len) { + if (!called) { + if (event_add(arg, NULL) == -1) + exit(1); + } + } else if (called == 1) + test_ok = 1; + + called++; +} + +void +simple_write_cb(int fd, short event, void *arg) +{ + int len; + + len = write(fd, TEST1, strlen(TEST1) + 1); + if (len == -1) + test_ok = 0; + else + test_ok = 1; +} + +void +multiple_write_cb(int fd, short event, void *arg) +{ + struct event *ev = arg; + int len; + + len = 128; + if (woff + len >= sizeof(wbuf)) + len = sizeof(wbuf) - woff; + + len = write(fd, wbuf + woff, len); + if (len == -1) { + fprintf(stderr, "%s: write\n", __func__); + if (usepersist) + event_del(ev); + return; + } + + woff += len; + + if (woff >= sizeof(wbuf)) { + shutdown(fd, SHUT_WR); + if (usepersist) + event_del(ev); + return; + } + + if (!usepersist) { + if (event_add(ev, NULL) == -1) + exit(1); + } +} + +void +multiple_read_cb(int fd, short event, void *arg) +{ + struct event *ev = arg; + int len; + + len = read(fd, rbuf + roff, sizeof(rbuf) - roff); + if (len == -1) + fprintf(stderr, "%s: read\n", __func__); + if (len <= 0) { + if (usepersist) + event_del(ev); + return; + } + + roff += len; + if (!usepersist) { + if (event_add(ev, NULL) == -1) + exit(1); + } +} + +void +timeout_cb(int fd, short event, void *arg) +{ + struct timeval tv; + int diff; + + gettimeofday(&tcalled, NULL); + if (timercmp(&tcalled, &tset, >)) + timersub(&tcalled, &tset, &tv); + else + timersub(&tset, &tcalled, &tv); + + diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000; + if (diff < 0) + diff = -diff; + + if (diff < 100) + test_ok = 1; +} + +void +signal_cb(int fd, short event, void *arg) +{ + struct event *ev = arg; + + signal_del(ev); + test_ok = 1; +} + +struct both { + struct event ev; + int nread; +}; + +void +combined_read_cb(int fd, short event, void *arg) +{ + struct both *both = arg; + char buf[128]; + int len; + + len = read(fd, buf, sizeof(buf)); + if (len == -1) + fprintf(stderr, "%s: read\n", __func__); + if (len <= 0) + return; + + both->nread += len; + if (event_add(&both->ev, NULL) == -1) + exit(1); +} + +void +combined_write_cb(int fd, short event, void *arg) +{ + struct both *both = arg; + char buf[128]; + int len; + + len = sizeof(buf); + if (len > both->nread) + len = both->nread; + + len = write(fd, buf, len); + if (len == -1) + fprintf(stderr, "%s: write\n", __func__); + if (len <= 0) { + shutdown(fd, SHUT_WR); + return; + } + + both->nread -= len; + if (event_add(&both->ev, NULL) == -1) + exit(1); +} + +/* Test infrastructure */ + +int +setup_test(char *name) +{ + + fprintf(stdout, "%s", name); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + fprintf(stderr, "%s: socketpair\n", __func__); + exit(1); + } + +#ifdef HAVE_FCNTL + if (fcntl(pair[0], F_SETFL, O_NONBLOCK) == -1) + fprintf(stderr, "fcntl(O_NONBLOCK)"); + + if (fcntl(pair[1], F_SETFL, O_NONBLOCK) == -1) + fprintf(stderr, "fcntl(O_NONBLOCK)"); +#endif + + test_ok = 0; + called = 0; + return (0); +} + +int +cleanup_test(void) +{ +#ifndef WIN32 + close(pair[0]); + close(pair[1]); +#else + CloseHandle((HANDLE)pair[0]); + CloseHandle((HANDLE)pair[1]); +#endif + if (test_ok) + fprintf(stdout, "OK\n"); + else { + fprintf(stdout, "FAILED\n"); + exit(1); + } + + return (0); +} + +void +test1(void) +{ + struct event ev; + + /* Very simple read test */ + setup_test("Simple read: "); + + write(pair[0], TEST1, strlen(TEST1)+1); + shutdown(pair[0], SHUT_WR); + + event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + event_dispatch(); + + cleanup_test(); +} + +void +test2(void) +{ + struct event ev; + + /* Very simple write test */ + setup_test("Simple write: "); + + event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + event_dispatch(); + + cleanup_test(); +} + +void +test3(void) +{ + struct event ev, ev2; + int i; + + /* Multiple read and write test */ + setup_test("Multiple read/write: "); + memset(rbuf, 0, sizeof(rbuf)); + for (i = 0; i < sizeof(wbuf); i++) + wbuf[i] = i; + + roff = woff = 0; + usepersist = 0; + + event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2); + if (event_add(&ev2, NULL) == -1) + exit(1); + event_dispatch(); + + if (roff == woff) + test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; + + cleanup_test(); +} + +void +test4(void) +{ + struct event ev, ev2; + int i; + + /* Multiple read and write test with persist */ + setup_test("Persist read/write: "); + memset(rbuf, 0, sizeof(rbuf)); + for (i = 0; i < sizeof(wbuf); i++) + wbuf[i] = i; + + roff = woff = 0; + usepersist = 1; + + event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2); + if (event_add(&ev2, NULL) == -1) + exit(1); + event_dispatch(); + + if (roff == woff) + test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; + + cleanup_test(); +} + +void +test5(void) +{ + struct both r1, r2, w1, w2; + + setup_test("Combined read/write: "); + memset(&r1, 0, sizeof(r1)); + memset(&r2, 0, sizeof(r2)); + memset(&w1, 0, sizeof(w1)); + memset(&w2, 0, sizeof(w2)); + + w1.nread = 4096; + w2.nread = 8192; + + event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1); + event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1); + event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2); + event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2); + if (event_add(&r1.ev, NULL) == -1) + exit(1); + if (event_add(&w1.ev, NULL)) + exit(1); + if (event_add(&r2.ev, NULL)) + exit(1); + if (event_add(&w2.ev, NULL)) + exit(1); + + event_dispatch(); + + if (r1.nread == 8192 && r2.nread == 4096) + test_ok = 1; + + cleanup_test(); +} + +void +test6(void) +{ + struct timeval tv; + struct event ev; + + setup_test("Simple timeout: "); + + tv.tv_usec = 0; + tv.tv_sec = SECONDS; + evtimer_set(&ev, timeout_cb, NULL); + evtimer_add(&ev, &tv); + + gettimeofday(&tset, NULL); + event_dispatch(); + + cleanup_test(); +} + +#ifndef WIN32 +void +test7(void) +{ + struct event ev; + struct itimerval itv; + + setup_test("Simple signal: "); + signal_set(&ev, SIGALRM, signal_cb, &ev); + signal_add(&ev, NULL); + + memset(&itv, 0, sizeof(itv)); + itv.it_value.tv_sec = 1; + if (setitimer(ITIMER_REAL, &itv, NULL) == -1) + goto skip_simplesignal; + + event_dispatch(); + skip_simplesignal: + signal_del(&ev); + + cleanup_test(); +} +#endif + +void +test8(void) +{ + struct timeval tv, tv_start, tv_end; + struct event ev; + + setup_test("Loop exit: "); + + tv.tv_usec = 0; + tv.tv_sec = 60*60*24; + evtimer_set(&ev, timeout_cb, NULL); + evtimer_add(&ev, &tv); + + tv.tv_usec = 0; + tv.tv_sec = 1; + event_loopexit(&tv); + + gettimeofday(&tv_start, NULL); + event_dispatch(); + gettimeofday(&tv_end, NULL); + timersub(&tv_end, &tv_start, &tv_end); + + evtimer_del(&ev); + + if (tv.tv_sec < 2) + test_ok = 1; + + cleanup_test(); +} + +void +readcb(struct bufferevent *bev, void *arg) +{ + if (EVBUFFER_LENGTH(bev->input) == 8333) { + bufferevent_disable(bev, EV_READ); + test_ok++; + } +} + +void +writecb(struct bufferevent *bev, void *arg) +{ + if (EVBUFFER_LENGTH(bev->output) == 0) + test_ok++; +} + +void +errorcb(struct bufferevent *bev, short what, void *arg) +{ + test_ok = -2; +} + +void +test9(void) +{ + struct bufferevent *bev1, *bev2; + char buffer[8333]; + int i; + + setup_test("Bufferevent: "); + + bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); + bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); + + bufferevent_disable(bev1, EV_READ); + bufferevent_enable(bev2, EV_READ); + + for (i = 0; i < sizeof(buffer); i++) + buffer[0] = i; + + bufferevent_write(bev1, buffer, sizeof(buffer)); + + event_dispatch(); + + bufferevent_free(bev1); + bufferevent_free(bev2); + + if (test_ok != 2) + test_ok = 0; + + cleanup_test(); +} + +struct test_pri_event { + struct event ev; + int count; +}; + +void +test_priorities_cb(int fd, short what, void *arg) +{ + struct test_pri_event *pri = arg; + struct timeval tv; + + if (pri->count == 3) { + event_loopexit(NULL); + return; + } + + pri->count++; + + timerclear(&tv); + event_add(&pri->ev, &tv); +} + +void +test_priorities(int npriorities) +{ + char buf[32]; + struct test_pri_event one, two; + struct timeval tv; + + snprintf(buf, sizeof(buf), "Priorities %d: ", npriorities); + setup_test(buf); + + event_base_priority_init(event_base, npriorities); + + memset(&one, 0, sizeof(one)); + memset(&two, 0, sizeof(two)); + + timeout_set(&one.ev, test_priorities_cb, &one); + if (event_priority_set(&one.ev, 0) == -1) { + fprintf(stderr, "%s: failed to set priority", __func__); + exit(1); + } + + timeout_set(&two.ev, test_priorities_cb, &two); + if (event_priority_set(&two.ev, npriorities - 1) == -1) { + fprintf(stderr, "%s: failed to set priority", __func__); + exit(1); + } + + timerclear(&tv); + + if (event_add(&one.ev, &tv) == -1) + exit(1); + if (event_add(&two.ev, &tv) == -1) + exit(1); + + event_dispatch(); + + event_del(&one.ev); + event_del(&two.ev); + + if (npriorities == 1) { + if (one.count == 3 && two.count == 3) + test_ok = 1; + } else if (npriorities == 2) { + /* Two is called once because event_loopexit is priority 1 */ + if (one.count == 3 && two.count == 1) + test_ok = 1; + } else { + if (one.count == 3 && two.count == 0) + test_ok = 1; + } + + cleanup_test(); +} + +static void +test_multiple_cb(int fd, short event, void *arg) +{ + if (event & EV_READ) + test_ok |= 1; + else if (event & EV_WRITE) + test_ok |= 2; +} + +void +test_multiple_events_for_same_fd(void) +{ + struct event e1, e2; + + setup_test("Multiple events for same fd: "); + + event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL); + event_add(&e1, NULL); + event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL); + event_add(&e2, NULL); + event_loop(EVLOOP_ONCE); + event_del(&e2); + write(pair[1], TEST1, strlen(TEST1)+1); + event_loop(EVLOOP_ONCE); + event_del(&e1); + + if (test_ok != 3) + test_ok = 0; + + cleanup_test(); +} + + +int +main (int argc, char **argv) +{ +#ifdef WIN32 + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 2 ); + + err = WSAStartup( wVersionRequested, &wsaData ); +#endif + + setvbuf(stdout, NULL, _IONBF, 0); + + /* Initalize the event library */ + event_base = event_init(); + + test1(); + + test2(); + + test3(); + + test4(); + + test5(); + + test6(); +#ifndef WIN32 + test7(); +#endif + test8(); + + test9(); + + test_priorities(1); + test_priorities(2); + test_priorities(3); + + test_multiple_events_for_same_fd(); + + return (0); +} + Added: trunk/varnish-cache/contrib/libevent/test/test-eof.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/test-eof.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/test-eof.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,68 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int test_okay = 1; +int called = 0; + +void +read_cb(int fd, short event, void *arg) +{ + char buf[256]; + int len; + + len = read(fd, buf, sizeof(buf)); + + printf("%s: read %d%s\n", __func__, + len, len ? "" : " - means EOF"); + + if (len) { + if (!called) + event_add(arg, NULL); + } else if (called == 1) + test_okay = 0; + + called++; +} + +int +main (int argc, char **argv) +{ + struct event ev; + char *test = "test string"; + int pair[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + return (1); + + + write(pair[0], test, strlen(test)+1); + shutdown(pair[0], SHUT_WR); + + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ + event_set(&ev, pair[1], EV_READ, read_cb, &ev); + + event_add(&ev, NULL); + + event_dispatch(); + + return (test_okay); +} + Added: trunk/varnish-cache/contrib/libevent/test/test-init.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/test-init.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/test-init.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,27 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +main(int argc, char **argv) +{ + /* Initalize the event library */ + event_init(); + + return (0); +} + Added: trunk/varnish-cache/contrib/libevent/test/test-time.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/test-time.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/test-time.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,68 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int called = 0; + +#define NEVENT 20000 + +struct event *ev[NEVENT]; + +void +time_cb(int fd, short event, void *arg) +{ + struct timeval tv; + int i, j; + + called++; + + if (called < 10*NEVENT) { + for (i = 0; i < 10; i++) { + j = random() % NEVENT; + tv.tv_sec = 0; + tv.tv_usec = random() % 50000L; + if (tv.tv_usec % 2) + evtimer_add(ev[j], &tv); + else + evtimer_del(ev[j]); + } + } +} + +int +main (int argc, char **argv) +{ + struct timeval tv; + int i; + + /* Initalize the event library */ + event_init(); + + for (i = 0; i < NEVENT; i++) { + ev[i] = malloc(sizeof(struct event)); + + /* Initalize one event */ + evtimer_set(ev[i], time_cb, ev[i]); + tv.tv_sec = 0; + tv.tv_usec = random() % 50000L; + evtimer_add(ev[i], &tv); + } + + event_dispatch(); + + return (called < NEVENT); +} + Added: trunk/varnish-cache/contrib/libevent/test/test-weof.c =================================================================== --- trunk/varnish-cache/contrib/libevent/test/test-weof.c 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/test-weof.c 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,68 @@ +/* + * Compile with: + * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int pair[2]; +int test_okay = 1; +int called = 0; + +void +write_cb(int fd, short event, void *arg) +{ + char *test = "test string"; + int len; + + len = write(fd, test, strlen(test) + 1); + + printf("%s: write %d%s\n", __func__, + len, len ? "" : " - means EOF"); + + if (len > 0) { + if (!called) + event_add(arg, NULL); + close(pair[0]); + } else if (called == 1) + test_okay = 0; + + called++; +} + +int +main (int argc, char **argv) +{ + struct event ev; + + if (signal(SIGPIPE, SIG_IGN) == SIG_IGN) + return (1); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + return (1); + + /* Initalize the event library */ + event_init(); + + /* Initalize one event */ + event_set(&ev, pair[1], EV_WRITE, write_cb, &ev); + + event_add(&ev, NULL); + + event_dispatch(); + + return (test_okay); +} + Added: trunk/varnish-cache/contrib/libevent/test/test.sh =================================================================== --- trunk/varnish-cache/contrib/libevent/test/test.sh 2006-03-14 12:00:35 UTC (rev 50) +++ trunk/varnish-cache/contrib/libevent/test/test.sh 2006-03-14 12:54:13 UTC (rev 51) @@ -0,0 +1,83 @@ +#!/bin/sh + +setup () { + export EVENT_NOKQUEUE=yes + export EVENT_NODEVPOLL=yes + export EVENT_NOPOLL=yes + export EVENT_NOSELECT=yes + export EVENT_NOEPOLL=yes + export EVENT_NORTSIG=yes +} + +test () { + if ! ./test-init 2>/dev/null ; + then + echo Skipping test + return + fi + +echo -n " test-eof: " +if ./test-eof >/dev/null ; +then + echo OKAY ; +else + echo FAILED ; +fi +echo -n " test-weof: " +if ./test-weof >/dev/null ; +then + echo OKAY ; +else + echo FAILED ; +fi +echo -n " test-time: " +if ./test-time >/dev/null ; +then + echo OKAY ; +else + echo FAILED ; +fi +echo -n " regress: " +if ./regress >/dev/null ; +then + echo OKAY ; +else + echo FAILED ; +fi +} + +echo "Running tests:" + +# Need to do this by hand? +setup +unset EVENT_NOKQUEUE +echo "KQUEUE" +test + +setup +unset EVENT_NODEVPOLL +echo "DEVPOLL" +test + +setup +unset EVENT_NOPOLL +echo "POLL" +test + +setup +unset EVENT_NOSELECT +echo "SELECT" +test + +setup +unset EVENT_NORTSIG +echo "RTSIG" +test + +setup +unset EVENT_NOEPOLL +echo "EPOLL" +test + + + Property changes on: trunk/varnish-cache/contrib/libevent/test/test.sh ___________________________________________________________________ Name: svn:executable + * From phk at projects.linpro.no Wed Mar 15 20:34:10 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Wed, 15 Mar 2006 21:34:10 +0100 (CET) Subject: r52 - trunk/varnish-cache/include Message-ID: <20060315203410.1A9181ED508@projects.linpro.no> Author: phk Date: 2006-03-15 21:34:10 +0100 (Wed, 15 Mar 2006) New Revision: 52 Added: trunk/varnish-cache/include/cli.h Log: Add definitions pertaining to the ascii-protocol which will be used multiple different places in the varnish architecture. Added: trunk/varnish-cache/include/cli.h =================================================================== --- trunk/varnish-cache/include/cli.h 2006-03-14 12:54:13 UTC (rev 51) +++ trunk/varnish-cache/include/cli.h 2006-03-15 20:34:10 UTC (rev 52) @@ -0,0 +1,130 @@ +/* + * $Id$ + */ + +#define CLI_URL_QUERY \ + "url.query", \ + "url.query ", \ + "\tQuery the cache status of a specific URL.\n" \ + "\tReturns the TTL, size and checksum of the object." + +#define CLI_URL_PURGE \ + "url.purge", \ + "url.purge ", \ + "\tAll urls matching regexp will consider currently cached\n" \ + "\tobjects obsolete" + +#define CLI_URL_STATUS \ + "url.status", \ + "url.status ", \ + "\tReturns all metadata for the specified URL" + +#define CLI_CONFIG_LOAD \ + "config.load", \ + "config.load ", \ + "\tCompile and load the VCL file under the name provided." + +#define CLI_CONFIG_INLINE \ + "config.inline", \ + "config.inline ", \ + "\tCompile and load the VCL data under the name provided." + +#define CLI_CONFIG_UNLOAD \ + "config.unload", \ + "config.unload ", \ + "\tUnload the named configuration (when possible)." + +#define CLI_CONFIG_LIST \ + "config.list", \ + "config.list", \ + "\tList all loaded configuration." + +#define CLI_CONFIG_USE \ + "config.use", \ + "config.use ", \ + "\tSwitch to the named configuration immediately." + +#define CLI_SERVER_FREEZE \ + "server.freeze", \ + "server.freeze", \ + "\tStop the clock, freeze object store." + +#define CLI_SERVER_THAW \ + "thaw", \ + "thaw", \ + "\tRestart the clock, unfreeze object store." + +#define CLI_SERVER_SUSPEND \ + "suspend", \ + "suspend", \ + "\tStop accepting requests." + +#define CLI_SERVER_RESUME \ + "resume", \ + "resume", \ + "\tAccept requests." + +#define CLI_SERVER_STOP \ + "stop", \ + "stop", \ + "\tStop the Varnish cache process" + +#define CLI_SERVER_START \ + "start", \ + "start", \ + "\tStart the Varnish cache process." + +#define CLI_SERVER_RESTART \ + "restart", \ + "restart", \ + "\tRestart the Varnish cache process." + +#define CLI_PING \ + "ping", \ + "ping [timestamp]", \ + "\tKeep connection alive" + +#define CLI_STATS \ + "stats", \ + "stats", \ + "\tShow summary statistics" + +#define CLI_ZERO \ + "zero", \ + "zero", \ + "\tZero summary statistics" + +#define CLI_HELP \ + "help", \ + "help [command]", \ + "\tShow command/protocol help" + +#define CLI_VERBOSE \ + "verbose", \ + "verbose", \ + "\tEnable/Disable verbosity" + +#define CLI_EXIT \ + "exit", \ + "exit", \ + "\tClose connection" + +#define CLI_QUIT \ + "quit", \ + "quit", \ + "\tClose connection" + +#define CLI_BYE \ + "bye", \ + "bye", \ + "\tClose connection" + +enum cli_status_e { + CLIS_SYNTAX = 100, + CLIS_UNKNOWN = 101, + CLIS_UNIMPL = 102, + CLIS_TOOFEW = 104, + CLIS_TOOMANY = 105, + CLIS_PARAM = 106, + CLIS_OK = 200 +}; From phk at projects.linpro.no Thu Mar 16 08:30:04 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 16 Mar 2006 09:30:04 +0100 (CET) Subject: r53 - trunk/varnish-cache/include Message-ID: <20060316083004.3E99F1ED584@projects.linpro.no> Author: phk Date: 2006-03-16 09:30:04 +0100 (Thu, 16 Mar 2006) New Revision: 53 Modified: trunk/varnish-cache/include/cli.h Log: add min+max argument counts Modified: trunk/varnish-cache/include/cli.h =================================================================== --- trunk/varnish-cache/include/cli.h 2006-03-15 20:34:10 UTC (rev 52) +++ trunk/varnish-cache/include/cli.h 2006-03-16 08:30:04 UTC (rev 53) @@ -6,118 +6,141 @@ "url.query", \ "url.query ", \ "\tQuery the cache status of a specific URL.\n" \ - "\tReturns the TTL, size and checksum of the object." + "\tReturns the TTL, size and checksum of the object.", \ + 1, 1 #define CLI_URL_PURGE \ "url.purge", \ "url.purge ", \ "\tAll urls matching regexp will consider currently cached\n" \ - "\tobjects obsolete" + "\tobjects obsolete", \ + 1, 1 #define CLI_URL_STATUS \ "url.status", \ "url.status ", \ - "\tReturns all metadata for the specified URL" + "\tReturns all metadata for the specified URL", \ + 1, 1 #define CLI_CONFIG_LOAD \ "config.load", \ "config.load ", \ - "\tCompile and load the VCL file under the name provided." + "\tCompile and load the VCL file under the name provided.", \ + 2, 2 #define CLI_CONFIG_INLINE \ "config.inline", \ "config.inline ", \ - "\tCompile and load the VCL data under the name provided." + "\tCompile and load the VCL data under the name provided.", \ + 2, 2 #define CLI_CONFIG_UNLOAD \ "config.unload", \ "config.unload ", \ - "\tUnload the named configuration (when possible)." + "\tUnload the named configuration (when possible).", \ + 1, 1 #define CLI_CONFIG_LIST \ "config.list", \ "config.list", \ - "\tList all loaded configuration." + "\tList all loaded configuration.", \ + 0, 0 #define CLI_CONFIG_USE \ "config.use", \ "config.use ", \ - "\tSwitch to the named configuration immediately." + "\tSwitch to the named configuration immediately.", \ + 1, 1 #define CLI_SERVER_FREEZE \ "server.freeze", \ "server.freeze", \ - "\tStop the clock, freeze object store." + "\tStop the clock, freeze object store.", \ + 0, 0 #define CLI_SERVER_THAW \ "thaw", \ "thaw", \ - "\tRestart the clock, unfreeze object store." + "\tRestart the clock, unfreeze object store.", \ + 0, 0 #define CLI_SERVER_SUSPEND \ "suspend", \ "suspend", \ - "\tStop accepting requests." + "\tStop accepting requests.", \ + 0, 0 #define CLI_SERVER_RESUME \ "resume", \ "resume", \ - "\tAccept requests." + "\tAccept requests.", \ + 0, 0 #define CLI_SERVER_STOP \ "stop", \ "stop", \ - "\tStop the Varnish cache process" + "\tStop the Varnish cache process", \ + 0, 0 #define CLI_SERVER_START \ "start", \ "start", \ - "\tStart the Varnish cache process." + "\tStart the Varnish cache process.", \ + 0, 0 #define CLI_SERVER_RESTART \ "restart", \ "restart", \ - "\tRestart the Varnish cache process." + "\tRestart the Varnish cache process.", \ + 0, 0 #define CLI_PING \ "ping", \ "ping [timestamp]", \ - "\tKeep connection alive" + "\tKeep connection alive", \ + 0, 1 #define CLI_STATS \ "stats", \ "stats", \ - "\tShow summary statistics" + "\tShow summary statistics", \ + 0, 0 #define CLI_ZERO \ "zero", \ "zero", \ - "\tZero summary statistics" + "\tZero summary statistics", \ + 0, 0 #define CLI_HELP \ "help", \ "help [command]", \ - "\tShow command/protocol help" + "\tShow command/protocol help", \ + 0, 1 #define CLI_VERBOSE \ "verbose", \ "verbose", \ - "\tEnable/Disable verbosity" + "\tEnable/Disable verbosity", \ + 0, 0 #define CLI_EXIT \ "exit", \ "exit", \ - "\tClose connection" + "\tClose connection", \ + 0, 0 #define CLI_QUIT \ "quit", \ "quit", \ - "\tClose connection" + "\tClose connection", \ + 0, 0 #define CLI_BYE \ "bye", \ "bye", \ - "\tClose connection" + "\tClose connection", \ + 0, 0 enum cli_status_e { CLIS_SYNTAX = 100, From phk at projects.linpro.no Thu Mar 16 09:02:24 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 16 Mar 2006 10:02:24 +0100 (CET) Subject: r54 - in trunk/varnish-cache: include lib/libvarnish lib/libvcl Message-ID: <20060316090224.542AE1ED583@projects.linpro.no> Author: phk Date: 2006-03-16 10:02:24 +0100 (Thu, 16 Mar 2006) New Revision: 54 Added: trunk/varnish-cache/include/cli_priv.h trunk/varnish-cache/lib/libvarnish/cli.c Modified: trunk/varnish-cache/include/cli.h trunk/varnish-cache/lib/libvarnish/Makefile.am trunk/varnish-cache/lib/libvcl/Makefile Log: Generic and public stuff for CLI protocol handling. Modified: trunk/varnish-cache/include/cli.h =================================================================== --- trunk/varnish-cache/include/cli.h 2006-03-16 08:30:04 UTC (rev 53) +++ trunk/varnish-cache/include/cli.h 2006-03-16 09:02:24 UTC (rev 54) @@ -1,7 +1,26 @@ /* * $Id$ + * + * Public definition of the CLI protocol, part of the published Varnish-API. + * */ +/* + * These macros define the common data for requests in the CLI protocol. + * The fields are: + * const char * request_name + * const char * request_syntax (for short help) + * const char * request_help (for long help) + * unsigned minimum_arguments + * unsigned maximum_arguments + * + * If you only want a subset of these fields do this: + * #define CLIF145(a,b,c,d,e) a,d,e + * [...] + * CLIF145(CLI_URL_QUERY) + * + */ + #define CLI_URL_QUERY \ "url.query", \ "url.query ", \ @@ -142,6 +161,10 @@ "\tClose connection", \ 0, 0 +/* + * Status/return codes in the CLI protocol + */ + enum cli_status_e { CLIS_SYNTAX = 100, CLIS_UNKNOWN = 101, Added: trunk/varnish-cache/include/cli_priv.h =================================================================== --- trunk/varnish-cache/include/cli_priv.h 2006-03-16 08:30:04 UTC (rev 53) +++ trunk/varnish-cache/include/cli_priv.h 2006-03-16 09:02:24 UTC (rev 54) @@ -0,0 +1,34 @@ +/* + * $Id$ + * + * Varnish process internal CLI stuff. + * + * XXX: at a latter date we may want to move some to cli.h/libvarnishapi + * + */ + +struct cli; /* NB: struct cli is opaque at this level. */ + +typedef void cli_func_t(struct cli*, char **av, void *priv); + +struct cli_proto { + /* These must match the CLI_* macros in cli.h */ + const char *request; + const char *syntax; + const char *help; + unsigned minarg; + unsigned maxarg; + + /* Dispatch information */ + cli_func_t *func; + void *priv; +}; + +/* The implementation must provide these functions */ +void cli_out(struct cli *cli, const char *fmt, ...); +void cli_param(struct cli *cli); +void cli_result(struct cli *cli, unsigned r); + +/* From libvarnish/cli.c */ +void cli_dispatch(struct cli *cli, struct cli_proto *clp, const char *line); +cli_func_t cli_func_help; Modified: trunk/varnish-cache/lib/libvarnish/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvarnish/Makefile.am 2006-03-16 08:30:04 UTC (rev 53) +++ trunk/varnish-cache/lib/libvarnish/Makefile.am 2006-03-16 09:02:24 UTC (rev 54) @@ -5,4 +5,5 @@ lib_LTLIBRARIES = libvarnish.la libvarnish_la_SOURCES = \ - argv.c + argv.c \ + cli.c Added: trunk/varnish-cache/lib/libvarnish/cli.c =================================================================== --- trunk/varnish-cache/lib/libvarnish/cli.c 2006-03-16 08:30:04 UTC (rev 53) +++ trunk/varnish-cache/lib/libvarnish/cli.c 2006-03-16 09:02:24 UTC (rev 54) @@ -0,0 +1,103 @@ +/* + * $Id$ + * + * Stuff for handling the CLI protocol + */ + +#include +#include + +#include +#include +#include + +/* + * Generic help function. + * + * priv must point to cli_proto array + */ + +void +cli_func_help(struct cli *cli, char **av, void *priv) +{ + unsigned u; + struct cli_proto *cp; + + if (av[2] == NULL) { + cli_out(cli, "Available commands:\n"); + for (cp = priv; cp->request != NULL; cp++) + cli_out(cli, "%s\n", cp->syntax); + return; + } + for (cp = priv; cp->request != NULL; cp++) { + if (!strcmp(cp->request, av[2])) { + cli_out(cli, "%s\n%s\n", cp->syntax, cp->help); + return; + } + } + cli_param(cli); +} + +void +cli_dispatch(struct cli *cli, struct cli_proto *clp, const char *line) +{ + char **av; + unsigned u; + struct cli_proto *cp; + + cli_result(cli, CLIS_OK); + /* XXX: syslog commands */ + av = ParseArgv(line, 0); + do { + if (av[0] != NULL) { + cli_out(cli, "Syntax Error: %s\n", av[0]); + cli_result(cli, CLIS_SYNTAX); + break; + } + if (av[1] == NULL) + break; + if (isupper(av[1][0])) { + cli_out(cli, + "all commands are in lower-case.\n"); + cli_result(cli, CLIS_UNKNOWN); + break; + } + for (cp = clp; cp->request != NULL; cp++) + if (!strcmp(av[1], cp->request)) + break; + if (cp->request == NULL) { + cli_out(cli, + "Unknown request, type 'help' for more info.\n"); + cli_result(cli, CLIS_UNKNOWN); + break; + } + + if (cp->func == NULL) { + cli_out(cli, "Unimplemented\n"); + cli_result(cli, CLIS_UNIMPL); + break; + } + + for (u = 0; u <= cp->minarg; u++) { + if (av[u + 1] != NULL) + continue; + cli_out(cli, "Too few parameters\n"); + cli_result(cli, CLIS_TOOFEW); + break; + } + if (u <= cp->minarg) + break; + for (; u <= cp->maxarg; u++) + if (av[u + 1] == NULL) + break; + if (av[u + 1] != NULL) { + cli_out(cli, "Too many parameters\n"); + cli_result(cli, CLIS_TOOMANY); + break; + } + + cp->func(cli, av, cp->priv); + + } while (0); + FreeArgv(av); +} Modified: trunk/varnish-cache/lib/libvcl/Makefile =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile 2006-03-16 08:30:04 UTC (rev 53) +++ trunk/varnish-cache/lib/libvcl/Makefile 2006-03-16 09:02:24 UTC (rev 54) @@ -18,3 +18,6 @@ flint: flint flint.lnt -I/usr/include -I. ${SRCS} + +distclean: clean + From phk at projects.linpro.no Thu Mar 16 10:46:01 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 16 Mar 2006 11:46:01 +0100 (CET) Subject: r55 - trunk/varnish-cache/bin/varnishd Message-ID: <20060316104601.9F9F91ED58C@projects.linpro.no> Author: phk Date: 2006-03-16 11:46:01 +0100 (Thu, 16 Mar 2006) New Revision: 55 Added: trunk/varnish-cache/bin/varnishd/cli_event.c trunk/varnish-cache/bin/varnishd/cli_event.h Log: Functions to handle the CLI with event(3)'s buffer events. This may eventually belong in a library for wider use. Added: trunk/varnish-cache/bin/varnishd/cli_event.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-16 09:02:24 UTC (rev 54) +++ trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-16 10:46:01 UTC (rev 55) @@ -0,0 +1,139 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include "heritage.h" +#include "cli_event.h" + +void +cli_out(struct cli *cli, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sbuf_vprintf(cli->sb, fmt, ap); + va_end(ap); +} + +void +cli_param(struct cli *cli) +{ + + cli->result = CLIS_PARAM; + cli_out(cli, "Parameter error, use \"help [command]\" for more info.\n"); +} + +void +cli_result(struct cli *cli, unsigned res) +{ + + cli->result = res; +} + +static void +encode_output(struct cli *cli) +{ + const char *p, *q; + + if (cli->verbose) { + if (cli->result != CLIS_OK) + evbuffer_add_printf(cli->bev1->output, "ERROR %d ", + cli->result); + evbuffer_add(cli->bev1->output, + sbuf_data(cli->sb), sbuf_len(cli->sb)); + if (cli->result == CLIS_OK) + evbuffer_add_printf(cli->bev1->output, "OK\n"); + return; + } + evbuffer_add_printf(cli->bev1->output, "%d \"", cli->result); + for (p = q = sbuf_data(cli->sb); *p != '\0'; p++) { + if (*p != '"' && *p != '\\' && isgraph(*p) || *p == ' ') + continue; + if (p != q) + evbuffer_add(cli->bev1->output, q, p - q); + if (*p == '\n') + evbuffer_add_printf(cli->bev1->output, "\\n"); + else + evbuffer_add_printf(cli->bev1->output, "\\x%02x", *p); + q = p + 1; + } + if (p != q) + evbuffer_add(cli->bev1->output, q, p - q); + evbuffer_add_printf(cli->bev1->output, "\"\n"); +} + +static void +rdcb(struct bufferevent *bev, void *arg) +{ + const char *p; + char **av; + struct cli *cli = arg; + unsigned u; + struct cli_proto *cp; + + p = evbuffer_readline(bev->input); + if (p == NULL) + return; + sbuf_clear(cli->sb); + cli_dispatch(cli, cli->cli_proto, p); + sbuf_finish(cli->sb); + /* XXX: syslog results ? */ + encode_output(cli); + bufferevent_enable(cli->bev1, EV_WRITE); +} + +static void +wrcb(struct bufferevent *bev, void *arg) +{ + struct cli *cli = arg; + + bufferevent_disable(cli->bev1, EV_WRITE); +} + +static void +excb(struct bufferevent *bev, short what, void *arg) +{ + printf("Exception\n"); +} + +struct cli * +cli_setup(int fdr, int fdw, int ver, struct cli_proto *cli_proto) +{ + struct cli *cli; + + cli = calloc(sizeof *cli, 1); + assert(cli != NULL); + + cli->bev0 = bufferevent_new(fdr, rdcb, wrcb, excb, cli); + assert(cli->bev0 != NULL); + if (fdr == fdw) + cli->bev1 = cli->bev0; + else + cli->bev1 = bufferevent_new(fdw, rdcb, wrcb, excb, cli); + assert(cli->bev1 != NULL); + cli->sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(cli->sb != NULL); + + cli->verbose = ver; + cli->cli_proto = cli_proto; + + bufferevent_enable(cli->bev0, EV_READ); + return (cli); +} Added: trunk/varnish-cache/bin/varnishd/cli_event.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.h 2006-03-16 09:02:24 UTC (rev 54) +++ trunk/varnish-cache/bin/varnishd/cli_event.h 2006-03-16 10:46:01 UTC (rev 55) @@ -0,0 +1,14 @@ +/* + * $Id$ + */ + +struct cli { + struct bufferevent *bev0, *bev1; + struct sbuf *sb; + unsigned verbose; + enum cli_status_e result; + struct cli_proto *cli_proto; +}; + +struct cli *cli_setup(int fdr, int fdw, int ver, struct cli_proto *cli_proto); + From phk at projects.linpro.no Thu Mar 16 10:48:50 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 16 Mar 2006 11:48:50 +0100 (CET) Subject: r56 - trunk/varnish-cache/bin/varnishd Message-ID: <20060316104850.A13481ED58F@projects.linpro.no> Author: phk Date: 2006-03-16 11:48:50 +0100 (Thu, 16 Mar 2006) New Revision: 56 Added: trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/heritage.h Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/varnishd.c Log: Expand the empty shell a bit. Add CLI handler on stdin (for now, in production only if debug is specified). Implement help, verbos, ping and start. start forks the child process, sets up listeners on its stdout/stderr (where nothing should arrive in production). Add SIGCHLD handler to reap and restart the child. Add shell "main" for the child: Set up a CLI handler on the pipes passed as heritage. Add ping command and keepalive timeout. Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-16 10:46:01 UTC (rev 55) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-16 10:48:50 UTC (rev 56) @@ -1,10 +1,15 @@ # $Id$ -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/contrib/libevent bin_PROGRAMS = varnishd varnishd_SOURCES = \ + cache_main.c \ + cli_event.c \ varnishd.c -#varnishd_LDADD = $(top_builddir)/lib/libvarnish/libvarnish.la +varnishd_LDADD = \ + $(top_builddir)/lib/libvarnish/libvarnish.la \ + $(top_builddir)/lib/libsbuf/libsbuf.la \ + $(top_builddir)/contrib/libevent/libevent.la Added: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-16 10:46:01 UTC (rev 55) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-16 10:48:50 UTC (rev 56) @@ -0,0 +1,87 @@ +/* + * $Id$ + */ + +#include +#include +#include + +#include + +#include +#include + +#include "heritage.h" + +static struct event ev_keepalive; + +/*--------------------------------------------------------------------*/ + +static void +timer_keepalive(int a, short b, void *c) +{ + + printf("%s(%d, %d, %p)\n", __func__, a, b, c); + printf("Heeellloooo ? Ohh bother...\n"); + exit (1); +} + +static void +arm_keepalive(void) +{ + struct timeval tv; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + evtimer_del(&ev_keepalive); + evtimer_add(&ev_keepalive, &tv); +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_ping(struct cli *cli, char **av, void *priv __unused) +{ + time_t t; + + arm_keepalive(); + if (av[2] != NULL) + cli_out(cli, "Got your %s\n", av[2]); + time(&t); + cli_out(cli, "PONG %ld\n", t); +} + +/*--------------------------------------------------------------------*/ + +static struct cli_proto cli_proto[] = { + { CLI_PING }, + { NULL } +}; + +void +child_main(void) +{ + struct event_base *eb; + struct cli *cli; + int i; + + setbuf(stdout, NULL); + setbuf(stderr, NULL); + printf("Child starts\n"); + + eb = event_init(); + assert(eb != NULL); + + cli = cli_setup(heritage.fds[0], heritage.fds[1], 0, cli_proto); + + evtimer_set(&ev_keepalive, timer_keepalive, NULL); + arm_keepalive(); + + i = event_dispatch(); + if (i != 0) + printf("event_dispatch() = %d\n", i); + + printf("Child dies\n"); +} + Added: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-16 10:46:01 UTC (rev 55) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-16 10:48:50 UTC (rev 56) @@ -0,0 +1,13 @@ +/* + * $Id$ + * + * This file contains the heritage passed when mgt forks cache + */ + +struct heritage { + int fds[2]; +}; + +extern struct heritage heritage; + +void child_main(void); Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-16 10:46:01 UTC (rev 55) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-16 10:48:50 UTC (rev 56) @@ -3,11 +3,241 @@ */ #include +#include +#include #include #include #include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "heritage.h" +#include "cli_event.h" + +/*--------------------------------------------------------------------*/ + +static enum { + H_STOP = 0, + H_START, +} desired; +static pid_t child_pid; +static int child_fds[2]; + +struct heritage heritage; + +static struct event_base *eb; + +static struct bufferevent *child_std; + +/*--------------------------------------------------------------------*/ + static void +std_rdcb(struct bufferevent *bev, void *arg) +{ + const char *p; + + p = evbuffer_readline(bev->input); + if (p == NULL) + return; + printf("Child said <%s>\n", p); +} + +static void +std_wrcb(struct bufferevent *bev, void *arg) +{ + + printf("%s(%p, %p)\n", __func__, bev, arg); + exit (2); +} + +static void +std_excb(struct bufferevent *bev, short what, void *arg) +{ + + printf("%s(%p, %d, %p)\n", __func__, bev, what, arg); + exit (2); +} + + + +/*--------------------------------------------------------------------*/ + +static void +start_child(void) +{ + int i; + + assert(pipe(heritage.fds) == 0); + assert(pipe(child_fds) == 0); + i = fork(); + if (i < 0) + errx(1, "Could not fork child"); + if (i == 0) { + /* XXX: close fds */ + /* XXX: (re)set signals */ + + /* Redirect stdin/out/err */ + close(0); + i = open("/dev/null", O_RDONLY); + assert(i == 0); + close(child_fds[0]); + dup2(child_fds[1], 1); + dup2(child_fds[1], 2); + close(child_fds[1]); + + child_main(); + + exit (1); + } + child_pid = i; + printf("start child pid %d\n", i); + + /* + * We do not close the unused ends of the pipes here to avoid + * doing SIGPIPE handling. + */ + child_std = bufferevent_new(child_fds[0], + std_rdcb, std_wrcb, std_excb, NULL); + assert(child_std != NULL); + bufferevent_enable(child_std, EV_READ); +} + +/*--------------------------------------------------------------------*/ + +static void +sig_chld(int a, short b, void *c) +{ + pid_t p; + int status; + + printf("sig_chld(%d, %d, %p)\n", a, b, c); + + p = wait4(-1, &status, WNOHANG, NULL); + printf("pid = %d status = 0x%x\n", p, status); + assert(p == child_pid); + + bufferevent_free(child_std); /* XXX: is this enough ? */ + child_std = NULL; + + close(heritage.fds[0]); + close(heritage.fds[1]); + close(child_fds[0]); + close(child_fds[1]); + + if (desired == H_START) + start_child(); +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_server_start(struct cli *cli, char **av __unused, void *priv __unused) +{ + + if (desired != H_START) { + desired = H_START; + start_child(); + } +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_server_stop(struct cli *cli, char **av __unused, void *priv __unused) +{ + + if (desired != H_STOP) { + desired = H_STOP; +#if 0 + stop_child(); +#endif + } +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_verbose(struct cli *cli, char **av __unused, void *priv) +{ + + cli->verbose = !cli->verbose; +} + +static void +cli_func_ping(struct cli *cli, char **av, void *priv __unused) +{ + time_t t; + + if (av[2] != NULL) { + cli_out(cli, "Got your %s\n", av[2]); + } + time(&t); + cli_out(cli, "PONG %ld\n", t); +} + +/*--------------------------------------------------------------------*/ + +static struct cli_proto cli_proto[] = { + /* URL manipulation */ + { CLI_URL_QUERY }, + { CLI_URL_PURGE }, + { CLI_URL_STATUS }, + { CLI_CONFIG_LOAD }, + { CLI_CONFIG_INLINE }, + { CLI_CONFIG_UNLOAD }, + { CLI_CONFIG_LIST }, + { CLI_CONFIG_USE }, + { CLI_SERVER_FREEZE }, + { CLI_SERVER_THAW }, + { CLI_SERVER_SUSPEND }, + { CLI_SERVER_RESUME }, + { CLI_SERVER_STOP, cli_func_server_stop, NULL }, + { CLI_SERVER_START, cli_func_server_start, NULL }, + { CLI_SERVER_RESTART }, + { CLI_PING, cli_func_ping, NULL }, + { CLI_STATS }, + { CLI_ZERO }, + { CLI_HELP, cli_func_help, cli_proto }, + { CLI_VERBOSE, cli_func_verbose, NULL }, + { CLI_EXIT }, + { CLI_QUIT }, + { CLI_BYE }, + { NULL } +}; + +static void +testme(void) +{ + struct event e_sigchld; + struct cli *cli; + int i; + + eb = event_init(); + assert(eb != NULL); + + cli = cli_setup(0, 1, 1, cli_proto); + + signal_set(&e_sigchld, SIGCHLD, sig_chld, NULL); + signal_add(&e_sigchld, NULL); + + i = event_dispatch(); + if (i != 0) + printf("event_dispatch() = %d\n", i); + +} + +/*--------------------------------------------------------------------*/ + +static void usage(void) { fprintf(stderr, "usage: varnishd [options]\n"); @@ -26,6 +256,8 @@ exit(1); } +/*--------------------------------------------------------------------*/ + int main(int argc, char *argv[]) { @@ -51,5 +283,8 @@ if (argc != 0) usage(); + testme(); + + exit(0); } From phk at projects.linpro.no Thu Mar 16 12:14:59 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 16 Mar 2006 13:14:59 +0100 (CET) Subject: r57 - in trunk/varnish-cache: bin/varnishd lib/libvarnish Message-ID: <20060316121459.681751ED508@projects.linpro.no> Author: phk Date: 2006-03-16 13:14:59 +0100 (Thu, 16 Mar 2006) New Revision: 57 Modified: trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cli_event.c trunk/varnish-cache/bin/varnishd/varnishd.c trunk/varnish-cache/lib/libvarnish/argv.c trunk/varnish-cache/lib/libvarnish/cli.c Log: cleanup Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-16 10:48:50 UTC (rev 56) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-16 12:14:59 UTC (rev 57) @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -12,6 +13,7 @@ #include #include "heritage.h" +#include "cli_event.h" static struct event ev_keepalive; @@ -55,7 +57,7 @@ /*--------------------------------------------------------------------*/ static struct cli_proto cli_proto[] = { - { CLI_PING }, + { CLI_PING, cli_func_ping }, { NULL } }; Modified: trunk/varnish-cache/bin/varnishd/cli_event.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-16 10:48:50 UTC (rev 56) +++ trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-16 12:14:59 UTC (rev 57) @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ static void encode_output(struct cli *cli) { - const char *p, *q; + char *p, *q; if (cli->verbose) { if (cli->result != CLIS_OK) @@ -64,7 +65,7 @@ } evbuffer_add_printf(cli->bev1->output, "%d \"", cli->result); for (p = q = sbuf_data(cli->sb); *p != '\0'; p++) { - if (*p != '"' && *p != '\\' && isgraph(*p) || *p == ' ') + if ((*p != '"' && *p != '\\' && isgraph(*p)) || *p == ' ') continue; if (p != q) evbuffer_add(cli->bev1->output, q, p - q); @@ -83,10 +84,7 @@ rdcb(struct bufferevent *bev, void *arg) { const char *p; - char **av; struct cli *cli = arg; - unsigned u; - struct cli_proto *cp; p = evbuffer_readline(bev->input); if (p == NULL) Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-16 10:48:50 UTC (rev 56) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-16 12:14:59 UTC (rev 57) @@ -2,14 +2,16 @@ * $Id$ */ +#include +#include #include -#include +#include +#include #include #include #include +#include #include -#include -#include #include @@ -27,7 +29,7 @@ static enum { H_STOP = 0, - H_START, + H_START } desired; static pid_t child_pid; static int child_fds[2]; @@ -55,7 +57,7 @@ std_wrcb(struct bufferevent *bev, void *arg) { - printf("%s(%p, %p)\n", __func__, bev, arg); + printf("%s(%p, %p)\n", __func__, (void*)bev, arg); exit (2); } @@ -63,7 +65,7 @@ std_excb(struct bufferevent *bev, short what, void *arg) { - printf("%s(%p, %d, %p)\n", __func__, bev, what, arg); + printf("%s(%p, %d, %p)\n", __func__, (void*)bev, what, arg); exit (2); } Modified: trunk/varnish-cache/lib/libvarnish/argv.c =================================================================== --- trunk/varnish-cache/lib/libvarnish/argv.c 2006-03-16 10:48:50 UTC (rev 56) +++ trunk/varnish-cache/lib/libvarnish/argv.c 2006-03-16 12:14:59 UTC (rev 57) @@ -23,6 +23,7 @@ BackSlash(const char *s, int *res) { int i, r; + unsigned u; assert(*s == '\\'); r = i = 0; @@ -59,8 +60,10 @@ } break; case 'x': - if (1 == sscanf(s + 1, "x%02x", &i)) + if (1 == sscanf(s + 1, "x%02x", &u)) { + i = u; r = 4; + } break; default: break; Modified: trunk/varnish-cache/lib/libvarnish/cli.c =================================================================== --- trunk/varnish-cache/lib/libvarnish/cli.c 2006-03-16 10:48:50 UTC (rev 56) +++ trunk/varnish-cache/lib/libvarnish/cli.c 2006-03-16 12:14:59 UTC (rev 57) @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -20,7 +21,6 @@ void cli_func_help(struct cli *cli, char **av, void *priv) { - unsigned u; struct cli_proto *cp; if (av[2] == NULL) { From phk at projects.linpro.no Fri Mar 17 10:03:05 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 17 Mar 2006 11:03:05 +0100 (CET) Subject: r58 - trunk/varnish-cache/bin/varnishd Message-ID: <20060317100305.DADC91ED464@projects.linpro.no> Author: phk Date: 2006-03-17 11:03:05 +0100 (Fri, 17 Mar 2006) New Revision: 58 Added: trunk/varnish-cache/bin/varnishd/mgt.h trunk/varnish-cache/bin/varnishd/mgt_child.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cli_event.c trunk/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/varnishd.c Log: Add multiplexing for the mgt->child cli connection and get ping/pong working across it. The management process will now keep the child process watchdog from expiring. Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-17 10:03:05 UTC (rev 58) @@ -7,6 +7,7 @@ varnishd_SOURCES = \ cache_main.c \ cli_event.c \ + mgt_child.c \ varnishd.c varnishd_LDADD = \ Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-17 10:03:05 UTC (rev 58) @@ -33,7 +33,7 @@ { struct timeval tv; - tv.tv_sec = 5; + tv.tv_sec = 30; tv.tv_usec = 0; evtimer_del(&ev_keepalive); @@ -48,8 +48,10 @@ time_t t; arm_keepalive(); - if (av[2] != NULL) - cli_out(cli, "Got your %s\n", av[2]); + if (av[2] != NULL) { + /* XXX: check clock skew is pointless here */ + printf("Got your ping %s\n", av[2]); + } time(&t); cli_out(cli, "PONG %ld\n", t); } @@ -75,7 +77,7 @@ eb = event_init(); assert(eb != NULL); - cli = cli_setup(heritage.fds[0], heritage.fds[1], 0, cli_proto); + cli = cli_setup(heritage.fds[2], heritage.fds[1], 0, cli_proto); evtimer_set(&ev_keepalive, timer_keepalive, NULL); arm_keepalive(); Modified: trunk/varnish-cache/bin/varnishd/cli_event.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-17 10:03:05 UTC (rev 58) @@ -108,7 +108,7 @@ static void excb(struct bufferevent *bev, short what, void *arg) { - printf("Exception\n"); + printf("%s(%p, %d, %p)\n", __func__, (void*)bev, what, arg); } struct cli * Modified: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-17 10:03:05 UTC (rev 58) @@ -5,7 +5,7 @@ */ struct heritage { - int fds[2]; + int fds[4]; }; extern struct heritage heritage; Added: trunk/varnish-cache/bin/varnishd/mgt.h =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-17 10:03:05 UTC (rev 58) @@ -0,0 +1,12 @@ +/* + * $Id$ + */ + +extern struct event_base *eb; + +void mgt_child_start(void); +void mgt_child_stop(void); +void mgt_sigchld(int, short, void *); + +typedef void mgt_ccb_f(unsigned, const char *, void *); +void mgt_child_request(mgt_ccb_f *, void *, const char *fmt, ...); Added: trunk/varnish-cache/bin/varnishd/mgt_child.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-17 10:03:05 UTC (rev 58) @@ -0,0 +1,291 @@ +/* + * $Id$ + * + * The mechanics of handling the child process + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "heritage.h" +#include "mgt.h" + +/*--------------------------------------------------------------------*/ + +static enum { + H_STOP = 0, + H_START +} desired; + +static pid_t child_pid; +static int child_fds[2]; + +static struct bufferevent *child_std; +static struct bufferevent *child_cli0, *child_cli1; + +static struct event ev_child_pingpong; + +struct creq { + TAILQ_ENTRY(creq) list; + char *req; + mgt_ccb_f *func; + void *priv; +}; + +static TAILQ_HEAD(,creq) creqhead = TAILQ_HEAD_INITIALIZER(creqhead); + +/*-------------------------------------------------------------------- + * Handle stdout+stderr from the child. + */ + +static void +std_rdcb(struct bufferevent *bev, void *arg) +{ + const char *p; + + p = evbuffer_readline(bev->input); + if (p == NULL) + return; + printf("Child said <%s>\n", p); +} + +static void +std_wrcb(struct bufferevent *bev, void *arg) +{ + + printf("%s(%p, %p)\n", __func__, (void*)bev, arg); + exit (2); +} + +static void +std_excb(struct bufferevent *bev, short what, void *arg) +{ + + printf("%s(%p, %d, %p)\n", __func__, (void*)bev, what, arg); + exit (2); +} + +/*-------------------------------------------------------------------- + * Multiplex requests/answers to the child + */ + +static void +send_req(void) +{ + struct creq *cr; + + cr = TAILQ_FIRST(&creqhead); + if (cr == NULL) + return; + printf("Send Request <%s>\n", cr->req); + evbuffer_add_printf(child_cli1->output, "%s\n", cr->req); + bufferevent_enable(child_cli1, EV_WRITE); +} + +void +mgt_child_request(mgt_ccb_f *func, void *priv, const char *fmt, ...) +{ + struct creq *cr; + va_list ap; + int i; + + cr = calloc(sizeof *cr, 1); + assert(cr != NULL); + cr->func = func; + cr->priv = priv; + va_start(ap, fmt); + vasprintf(&cr->req, fmt, ap); + va_end(ap); + i = TAILQ_EMPTY(&creqhead); + TAILQ_INSERT_TAIL(&creqhead, cr, list); + if (i) + send_req(); +} + +static void +cli_rdcb(struct bufferevent *bev, void *arg) +{ + const char *p; + char **av; + struct creq *cr; + + p = evbuffer_readline(bev->input); + if (p == NULL) + return; + cr = TAILQ_FIRST(&creqhead); + assert(cr != NULL); + av = ParseArgv(p, 0); + if (av[0] != NULL) + cr->func(CLIS_SYNTAX, av[0], cr->priv); + else + cr->func(strtoul(av[1], NULL, 0), av[2], cr->priv); + FreeArgv(av); + TAILQ_REMOVE(&creqhead, cr, list); + free(cr->req); + free(cr); + send_req(); +} + +static void +cli_wrcb(struct bufferevent *bev __unused, void *arg __unused) +{ + +} + +static void +cli_excb(struct bufferevent *bev, short what, void *arg) +{ + + printf("%s(%p, %d, %p)\n", __func__, (void*)bev, what, arg); + exit (2); +} + +/*--------------------------------------------------------------------*/ + +static void +child_pingpong_ccb(unsigned u, const char *r, void *priv) +{ + printf("%s(%u, \"%s\", %p)\n", __func__, u, r, priv); + /* XXX: reset keepalive timer */ +} + + +static void +child_pingpong(int a, short b, void *c) +{ + time_t t; + struct timeval tv; + + printf("%s(%d, %d, %p)\n", __func__, a, b, c); + time(&t); + mgt_child_request(child_pingpong_ccb, NULL, "ping %ld", t); + if (1) { + tv.tv_sec = 3; + tv.tv_usec = 0; + evtimer_del(&ev_child_pingpong); + evtimer_add(&ev_child_pingpong, &tv); + } +} + + +/*--------------------------------------------------------------------*/ + +static void +start_child(void) +{ + int i; + + assert(pipe(&heritage.fds[0]) == 0); + assert(pipe(&heritage.fds[2]) == 0); + assert(pipe(child_fds) == 0); + i = fork(); + if (i < 0) + errx(1, "Could not fork child"); + if (i == 0) { + /* XXX: close fds */ + /* XXX: (re)set signals */ + + /* Redirect stdin/out/err */ + close(0); + i = open("/dev/null", O_RDONLY); + assert(i == 0); + close(child_fds[0]); + dup2(child_fds[1], 1); + dup2(child_fds[1], 2); + close(child_fds[1]); + + child_main(); + + exit (1); + } + child_pid = i; + printf("start child pid %d\n", i); + + /* + * We do not close the unused ends of the pipes here to avoid + * doing SIGPIPE handling. + */ + child_std = bufferevent_new(child_fds[0], + std_rdcb, std_wrcb, std_excb, NULL); + assert(child_std != NULL); + bufferevent_enable(child_std, EV_READ); + child_cli0 = bufferevent_new(heritage.fds[0], + cli_rdcb, cli_wrcb, cli_excb, NULL); + assert(child_cli0 != NULL); + bufferevent_enable(child_cli0, EV_READ); + child_cli1 = bufferevent_new(heritage.fds[3], + cli_rdcb, cli_wrcb, cli_excb, NULL); + assert(child_cli1 != NULL); + + evtimer_set(&ev_child_pingpong, child_pingpong, NULL); + child_pingpong(0, 0, NULL); +} + + +/*--------------------------------------------------------------------*/ + +void +mgt_child_start(void) +{ + + if (desired == H_START) + return; + desired = H_START; + start_child(); +} + +/*--------------------------------------------------------------------*/ + +void +mgt_child_stop(void) +{ + + if (desired == H_STOP) + return; + desired = H_STOP; +} + +/*--------------------------------------------------------------------*/ + +void +mgt_sigchld(int a, short b, void *c) +{ + pid_t p; + int status; + + printf("sig_chld(%d, %d, %p)\n", a, b, c); + + p = wait4(-1, &status, WNOHANG, NULL); + printf("pid = %d status = 0x%x\n", p, status); + assert(p == child_pid); + + bufferevent_free(child_std); /* XXX: is this enough ? */ + child_std = NULL; + + close(heritage.fds[0]); + close(heritage.fds[1]); + close(heritage.fds[2]); + close(heritage.fds[3]); + close(child_fds[0]); + close(child_fds[1]); + + if (desired == H_START) + start_child(); +} Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-16 12:14:59 UTC (rev 57) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-17 10:03:05 UTC (rev 58) @@ -1,5 +1,7 @@ /* * $Id$ + * + * The management process and CLI handling */ #include @@ -22,133 +24,39 @@ #include #include +#include "mgt.h" #include "heritage.h" #include "cli_event.h" /*--------------------------------------------------------------------*/ -static enum { - H_STOP = 0, - H_START -} desired; -static pid_t child_pid; -static int child_fds[2]; - struct heritage heritage; +struct event_base *eb; -static struct event_base *eb; - -static struct bufferevent *child_std; - /*--------------------------------------------------------------------*/ -static void -std_rdcb(struct bufferevent *bev, void *arg) +void +xxx_ccb(unsigned u, const char *r, void *priv) { - const char *p; - - p = evbuffer_readline(bev->input); - if (p == NULL) - return; - printf("Child said <%s>\n", p); + printf("%s(%u, %s, %p)\n", __func__, u, r, priv); } -static void -std_wrcb(struct bufferevent *bev, void *arg) -{ - - printf("%s(%p, %p)\n", __func__, (void*)bev, arg); - exit (2); -} - -static void -std_excb(struct bufferevent *bev, short what, void *arg) -{ - - printf("%s(%p, %d, %p)\n", __func__, (void*)bev, what, arg); - exit (2); -} - - - /*--------------------------------------------------------------------*/ static void -start_child(void) +cli_func_url_query(struct cli *cli, char **av __unused, void *priv __unused) { - int i; - assert(pipe(heritage.fds) == 0); - assert(pipe(child_fds) == 0); - i = fork(); - if (i < 0) - errx(1, "Could not fork child"); - if (i == 0) { - /* XXX: close fds */ - /* XXX: (re)set signals */ - - /* Redirect stdin/out/err */ - close(0); - i = open("/dev/null", O_RDONLY); - assert(i == 0); - close(child_fds[0]); - dup2(child_fds[1], 1); - dup2(child_fds[1], 2); - close(child_fds[1]); - - child_main(); - - exit (1); - } - child_pid = i; - printf("start child pid %d\n", i); - - /* - * We do not close the unused ends of the pipes here to avoid - * doing SIGPIPE handling. - */ - child_std = bufferevent_new(child_fds[0], - std_rdcb, std_wrcb, std_excb, NULL); - assert(child_std != NULL); - bufferevent_enable(child_std, EV_READ); + mgt_child_request(xxx_ccb, NULL, "url.query %s", av[2]); } /*--------------------------------------------------------------------*/ static void -sig_chld(int a, short b, void *c) -{ - pid_t p; - int status; - - printf("sig_chld(%d, %d, %p)\n", a, b, c); - - p = wait4(-1, &status, WNOHANG, NULL); - printf("pid = %d status = 0x%x\n", p, status); - assert(p == child_pid); - - bufferevent_free(child_std); /* XXX: is this enough ? */ - child_std = NULL; - - close(heritage.fds[0]); - close(heritage.fds[1]); - close(child_fds[0]); - close(child_fds[1]); - - if (desired == H_START) - start_child(); -} - -/*--------------------------------------------------------------------*/ - -static void cli_func_server_start(struct cli *cli, char **av __unused, void *priv __unused) { - if (desired != H_START) { - desired = H_START; - start_child(); - } + mgt_child_start(); } /*--------------------------------------------------------------------*/ @@ -157,12 +65,7 @@ cli_func_server_stop(struct cli *cli, char **av __unused, void *priv __unused) { - if (desired != H_STOP) { - desired = H_STOP; -#if 0 - stop_child(); -#endif - } + mgt_child_stop(); } /*--------------------------------------------------------------------*/ @@ -174,6 +77,7 @@ cli->verbose = !cli->verbose; } + static void cli_func_ping(struct cli *cli, char **av, void *priv __unused) { @@ -190,7 +94,7 @@ static struct cli_proto cli_proto[] = { /* URL manipulation */ - { CLI_URL_QUERY }, + { CLI_URL_QUERY, cli_func_url_query, NULL }, { CLI_URL_PURGE }, { CLI_URL_STATUS }, { CLI_CONFIG_LOAD }, @@ -228,7 +132,7 @@ cli = cli_setup(0, 1, 1, cli_proto); - signal_set(&e_sigchld, SIGCHLD, sig_chld, NULL); + signal_set(&e_sigchld, SIGCHLD, mgt_sigchld, NULL); signal_add(&e_sigchld, NULL); i = event_dispatch(); From phk at projects.linpro.no Fri Mar 17 13:41:32 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 17 Mar 2006 14:41:32 +0100 (CET) Subject: r59 - trunk/varnish-cache/bin/varnishd Message-ID: <20060317134132.EBB1F1ED508@projects.linpro.no> Author: phk Date: 2006-03-17 14:41:32 +0100 (Fri, 17 Mar 2006) New Revision: 59 Modified: trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cli_event.c trunk/varnish-cache/bin/varnishd/cli_event.h trunk/varnish-cache/bin/varnishd/mgt.h trunk/varnish-cache/bin/varnishd/mgt_child.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: Make it possible to suspend and resume a cli connection while we wait for response from the child (or otherwise). Add a generic "pass-through" handler for cli requests we just pass on to the child. Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-17 13:41:32 UTC (rev 59) @@ -3,6 +3,7 @@ */ #include +#include #include #include #include @@ -43,6 +44,17 @@ /*--------------------------------------------------------------------*/ static void +cli_func_url_query(struct cli *cli, char **av, void *priv __unused) +{ + + cli_out(cli, "url <%s>", av[2]); + sleep(1); + cli_result(cli, CLIS_UNIMPL); +} + +/*--------------------------------------------------------------------*/ + +static void cli_func_ping(struct cli *cli, char **av, void *priv __unused) { time_t t; @@ -59,6 +71,7 @@ /*--------------------------------------------------------------------*/ static struct cli_proto cli_proto[] = { + { CLI_URL_QUERY, cli_func_url_query }, { CLI_PING, cli_func_ping }, { NULL } }; Modified: trunk/varnish-cache/bin/varnishd/cli_event.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/cli_event.c 2006-03-17 13:41:32 UTC (rev 59) @@ -24,6 +24,29 @@ #include "cli_event.h" void +cli_encode_string(struct evbuffer *buf, char *b) +{ + char *p, *q; + + evbuffer_add_printf(buf, "\""); + for (p = q = b; *p != '\0'; p++) { + if ((*p != '"' && *p != '\\' && isgraph(*p)) || *p == ' ') + continue; + if (p != q) + evbuffer_add(buf, q, p - q); + if (*p == '\n') + evbuffer_add_printf(buf, "\\n"); + else + evbuffer_add_printf(buf, "\\x%02x", *p); + q = p + 1; + } + if (p != q) + evbuffer_add(buf, q, p - q); + evbuffer_add_printf(buf, "\""); +} + + +void cli_out(struct cli *cli, const char *fmt, ...) { va_list ap; @@ -51,7 +74,6 @@ static void encode_output(struct cli *cli) { - char *p, *q; if (cli->verbose) { if (cli->result != CLIS_OK) @@ -63,21 +85,9 @@ evbuffer_add_printf(cli->bev1->output, "OK\n"); return; } - evbuffer_add_printf(cli->bev1->output, "%d \"", cli->result); - for (p = q = sbuf_data(cli->sb); *p != '\0'; p++) { - if ((*p != '"' && *p != '\\' && isgraph(*p)) || *p == ' ') - continue; - if (p != q) - evbuffer_add(cli->bev1->output, q, p - q); - if (*p == '\n') - evbuffer_add_printf(cli->bev1->output, "\\n"); - else - evbuffer_add_printf(cli->bev1->output, "\\x%02x", *p); - q = p + 1; - } - if (p != q) - evbuffer_add(cli->bev1->output, q, p - q); - evbuffer_add_printf(cli->bev1->output, "\"\n"); + evbuffer_add_printf(cli->bev1->output, "%d ", cli->result); + cli_encode_string(cli->bev1->output, sbuf_data(cli->sb)); + evbuffer_add_printf(cli->bev1->output, "\n"); } static void @@ -91,10 +101,12 @@ return; sbuf_clear(cli->sb); cli_dispatch(cli, cli->cli_proto, p); - sbuf_finish(cli->sb); - /* XXX: syslog results ? */ - encode_output(cli); - bufferevent_enable(cli->bev1, EV_WRITE); + if (!cli->suspend) { + sbuf_finish(cli->sb); + /* XXX: syslog results ? */ + encode_output(cli); + bufferevent_enable(cli->bev1, EV_WRITE); + } } static void @@ -135,3 +147,23 @@ bufferevent_enable(cli->bev0, EV_READ); return (cli); } + +void +cli_suspend(struct cli *cli) +{ + + cli->suspend = 1; + bufferevent_disable(cli->bev0, EV_READ); +} + +void +cli_resume(struct cli *cli) +{ + sbuf_finish(cli->sb); + /* XXX: syslog results ? */ + encode_output(cli); + bufferevent_enable(cli->bev1, EV_WRITE); + cli->suspend = 0; + bufferevent_enable(cli->bev0, EV_READ); +} + Modified: trunk/varnish-cache/bin/varnishd/cli_event.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cli_event.h 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/cli_event.h 2006-03-17 13:41:32 UTC (rev 59) @@ -6,9 +6,12 @@ struct bufferevent *bev0, *bev1; struct sbuf *sb; unsigned verbose; + unsigned suspend; enum cli_status_e result; struct cli_proto *cli_proto; }; struct cli *cli_setup(int fdr, int fdw, int ver, struct cli_proto *cli_proto); - +void cli_suspend(struct cli *cli); +void cli_resume(struct cli *cli); +void cli_encode_string(struct evbuffer *buf, char *b); Modified: trunk/varnish-cache/bin/varnishd/mgt.h =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-17 13:41:32 UTC (rev 59) @@ -9,4 +9,4 @@ void mgt_sigchld(int, short, void *); typedef void mgt_ccb_f(unsigned, const char *, void *); -void mgt_child_request(mgt_ccb_f *, void *, const char *fmt, ...); +void mgt_child_request(mgt_ccb_f *, void *, char **argv, const char *fmt, ...); Modified: trunk/varnish-cache/bin/varnishd/mgt_child.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-17 13:41:32 UTC (rev 59) @@ -24,6 +24,7 @@ #include #include +#include "cli_event.h" /* for cli_encode_string */ #include "heritage.h" #include "mgt.h" @@ -45,6 +46,7 @@ struct creq { TAILQ_ENTRY(creq) list; char *req; + char **argv; mgt_ccb_f *func; void *priv; }; @@ -90,17 +92,23 @@ send_req(void) { struct creq *cr; + int u; cr = TAILQ_FIRST(&creqhead); if (cr == NULL) return; printf("Send Request <%s>\n", cr->req); - evbuffer_add_printf(child_cli1->output, "%s\n", cr->req); + evbuffer_add_printf(child_cli1->output, "%s", cr->req); + for (u = 0; cr->argv != NULL && cr->argv[u] != NULL; u++) { + evbuffer_add_printf(child_cli1->output, " "); + cli_encode_string(child_cli1->output, cr->argv[u]); + } + evbuffer_add_printf(child_cli1->output, "\n"); bufferevent_enable(child_cli1, EV_WRITE); } void -mgt_child_request(mgt_ccb_f *func, void *priv, const char *fmt, ...) +mgt_child_request(mgt_ccb_f *func, void *priv, char **argv, const char *fmt, ...) { struct creq *cr; va_list ap; @@ -110,6 +118,7 @@ assert(cr != NULL); cr->func = func; cr->priv = priv; + cr->argv = argv; va_start(ap, fmt); vasprintf(&cr->req, fmt, ap); va_end(ap); @@ -175,7 +184,7 @@ printf("%s(%d, %d, %p)\n", __func__, a, b, c); time(&t); - mgt_child_request(child_pingpong_ccb, NULL, "ping %ld", t); + mgt_child_request(child_pingpong_ccb, NULL, NULL, "ping %ld", t); if (1) { tv.tv_sec = 3; tv.tv_usec = 0; Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-17 10:03:05 UTC (rev 58) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-17 13:41:32 UTC (rev 59) @@ -33,21 +33,26 @@ struct heritage heritage; struct event_base *eb; -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Generic passthrough for CLI functions + */ void -xxx_ccb(unsigned u, const char *r, void *priv) +cli_passthrough_cb(unsigned u, const char *r, void *priv) { - printf("%s(%u, %s, %p)\n", __func__, u, r, priv); + struct cli *cli = priv; + + cli_out(cli, "%s\n", r); + cli_result(cli, u); + cli_resume(cli); } -/*--------------------------------------------------------------------*/ - static void -cli_func_url_query(struct cli *cli, char **av __unused, void *priv __unused) +cli_func_passthrough(struct cli *cli, char **av __unused, void *priv) { - mgt_child_request(xxx_ccb, NULL, "url.query %s", av[2]); + cli_suspend(cli); + mgt_child_request(cli_passthrough_cb, cli, &av[2], av[1]); } /*--------------------------------------------------------------------*/ @@ -94,18 +99,18 @@ static struct cli_proto cli_proto[] = { /* URL manipulation */ - { CLI_URL_QUERY, cli_func_url_query, NULL }, - { CLI_URL_PURGE }, - { CLI_URL_STATUS }, + { CLI_URL_QUERY, cli_func_passthrough, NULL }, + { CLI_URL_PURGE, cli_func_passthrough, NULL }, + { CLI_URL_STATUS, cli_func_passthrough, NULL }, { CLI_CONFIG_LOAD }, { CLI_CONFIG_INLINE }, { CLI_CONFIG_UNLOAD }, { CLI_CONFIG_LIST }, { CLI_CONFIG_USE }, - { CLI_SERVER_FREEZE }, - { CLI_SERVER_THAW }, - { CLI_SERVER_SUSPEND }, - { CLI_SERVER_RESUME }, + { CLI_SERVER_FREEZE, cli_func_passthrough, NULL }, + { CLI_SERVER_THAW, cli_func_passthrough, NULL }, + { CLI_SERVER_SUSPEND, cli_func_passthrough, NULL }, + { CLI_SERVER_RESUME, cli_func_passthrough, NULL }, { CLI_SERVER_STOP, cli_func_server_stop, NULL }, { CLI_SERVER_START, cli_func_server_start, NULL }, { CLI_SERVER_RESTART }, From phk at projects.linpro.no Thu Mar 23 08:45:44 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 23 Mar 2006 09:45:44 +0100 (CET) Subject: r60 - trunk/varnish-cache/bin/varnishd Message-ID: <20060323084544.9FF9F1ED57E@projects.linpro.no> Author: phk Date: 2006-03-23 09:45:44 +0100 (Thu, 23 Mar 2006) New Revision: 60 Added: trunk/varnish-cache/bin/varnishd/tcp.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/mgt.h trunk/varnish-cache/bin/varnishd/varnishd.c Log: Open TCP sockets Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-17 13:41:32 UTC (rev 59) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-23 08:45:44 UTC (rev 60) @@ -8,6 +8,7 @@ cache_main.c \ cli_event.c \ mgt_child.c \ + tcp.c \ varnishd.c varnishd_LDADD = \ Modified: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-17 13:41:32 UTC (rev 59) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-23 08:45:44 UTC (rev 60) @@ -5,7 +5,21 @@ */ struct heritage { + + /* + * Two pipe(2)'s for CLI connection between cache and mgt. + * cache reads [2] and writes [1]. Mgt reads [0] and writes [3]. + */ int fds[4]; + + /* + * Two sockets from which to accept connections, one bound to + * loopback only and one bound for wildcard (or possibly a specific + * interface IP number). + */ +#define HERITAGE_NSOCKS 2 /* IPv4 + IPv6 */ + int sock_local[HERITAGE_NSOCKS]; + int sock_remote[HERITAGE_NSOCKS]; }; extern struct heritage heritage; Modified: trunk/varnish-cache/bin/varnishd/mgt.h =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-17 13:41:32 UTC (rev 59) +++ trunk/varnish-cache/bin/varnishd/mgt.h 2006-03-23 08:45:44 UTC (rev 60) @@ -10,3 +10,6 @@ typedef void mgt_ccb_f(unsigned, const char *, void *); void mgt_child_request(mgt_ccb_f *, void *, char **argv, const char *fmt, ...); + +/* tcp.c */ +int open_tcp(const char *port); Added: trunk/varnish-cache/bin/varnishd/tcp.c =================================================================== --- trunk/varnish-cache/bin/varnishd/tcp.c 2006-03-17 13:41:32 UTC (rev 59) +++ trunk/varnish-cache/bin/varnishd/tcp.c 2006-03-23 08:45:44 UTC (rev 60) @@ -0,0 +1,66 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include +#include +#include + +#include "heritage.h" + +static void +create_listen_socket(const char *addr, const char *port, int *sp, int nsp) +{ + struct addrinfo ai, *r0, *r1; + int i, j, s; + + memset(&ai, 0, sizeof ai); + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = SOCK_STREAM; + ai.ai_flags = AI_PASSIVE; + i = getaddrinfo(addr, port, &ai, &r0); + + if (i) { + fprintf("getaddrinfo failed: %s\n", gai_strerror(i)); + return; + } + + for (r1 = r0; r1 != NULL && nsp > 0; r1 = r1->ai_next) { + s = socket(r1->ai_family, r1->ai_socktype, r1->ai_protocol); + if (s < 0) + continue; + j = 1; + i = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof j); + assert(i == 0); + + i = bind(s, r1->ai_addr, r1->ai_addrlen); + assert(i == 0); + *sp = s; + sp++; + nsp--; + } + + freeaddrinfo(r0); +} + +int +open_tcp(const char *port) +{ + unsigned u; + + for (u = 0; u < HERITAGE_NSOCKS; u++) { + heritage.sock_local[u] = -1; + heritage.sock_remote[u] = -1; + } + + create_listen_socket("localhost", port, + &heritage.sock_local[0], HERITAGE_NSOCKS); + + create_listen_socket(NULL, port, + &heritage.sock_remote[0], HERITAGE_NSOCKS); + + return (0); +} Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-17 13:41:32 UTC (rev 59) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-23 08:45:44 UTC (rev 60) @@ -169,6 +169,9 @@ /*--------------------------------------------------------------------*/ +/* for development purposes */ +#include + int main(int argc, char *argv[]) { @@ -176,6 +179,10 @@ unsigned portnumber = 8080; unsigned dflag = 1; /* XXX: debug=on for now */ + register_printf_render_std((const unsigned char *)"HVQ"); + + open_tcp("8080"); + while ((o = getopt(argc, argv, "dp:")) != -1) switch (o) { case 'd': From phk at projects.linpro.no Thu Mar 23 12:20:31 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 23 Mar 2006 13:20:31 +0100 (CET) Subject: r61 - trunk/varnish-cache/bin/varnishd Message-ID: <20060323122031.223881ED586@projects.linpro.no> Author: phk Date: 2006-03-23 13:20:30 +0100 (Thu, 23 Mar 2006) New Revision: 61 Added: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_acceptor.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/mgt_child.c trunk/varnish-cache/bin/varnishd/tcp.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: Now we're starting to get somewhere: Accept connections and assemble a HTTP request. Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-23 12:20:30 UTC (rev 61) @@ -5,6 +5,7 @@ bin_PROGRAMS = varnishd varnishd_SOURCES = \ + cache_acceptor.c \ cache_main.c \ cli_event.c \ mgt_child.c \ @@ -14,4 +15,5 @@ varnishd_LDADD = \ $(top_builddir)/lib/libvarnish/libvarnish.la \ $(top_builddir)/lib/libsbuf/libsbuf.la \ - $(top_builddir)/contrib/libevent/libevent.la + $(top_builddir)/contrib/libevent/libevent.la \ + -lpthread Added: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-23 12:20:30 UTC (rev 61) @@ -0,0 +1,14 @@ +/* + * $Id$ + */ + +#define VCA_RXBUFSIZE 1024 +struct sess { + int fd; + char rcv[VCA_RXBUFSIZE + 1]; + unsigned rcv_len; + struct event rd_e; +}; + +/* cache_acceptor.c */ +void *vca_main(void *arg); Added: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-23 12:20:30 UTC (rev 61) @@ -0,0 +1,111 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "heritage.h" +#include "cache.h" + +static struct event_base *evb; + +static struct event accept_e[2 * HERITAGE_NSOCKS]; + +static void +http_read_f(int fd, short event, void *arg) +{ + struct sess *sp = arg; + const char *p; + int i; + + printf("%s(%d, %d, ...)\n", __func__, fd, event); + assert(VCA_RXBUFSIZE - sp->rcv_len > 0); + i = read(fd, sp->rcv + sp->rcv_len, VCA_RXBUFSIZE - sp->rcv_len); + assert(i > 0); + sp->rcv_len += i; + sp->rcv[sp->rcv_len] = '\0'; + + p = sp->rcv; + while (1) { + /* XXX: we could save location of all linebreaks for later */ + p = strchr(p, '\n'); + if (p == NULL) + return; + p++; + if (*p == '\r') + p++; + if (*p != '\n') + continue; + break; + } + printf("full <%s>\n", sp->rcv); + event_del(&sp->rd_e); +} + +static void +accept_f(int fd, short event, void *arg __unused) +{ + socklen_t l; + struct sockaddr addr; + struct sess *sp; + + sp = calloc(sizeof *sp, 1); + assert(sp != NULL); + + printf("%s(%d, %d, ...)\n", __func__, fd, event); + + l = sizeof addr; + sp->fd = accept(fd, &addr, &l); + if (sp->fd < 0) { + free(sp); + return; + } + + event_set(&sp->rd_e, sp->fd, EV_READ | EV_PERSIST, + http_read_f, sp); + event_base_set(evb, &sp->rd_e); + event_add(&sp->rd_e, NULL); /* XXX: timeout */ +} + +void * +vca_main(void *arg) +{ + unsigned u; + struct event *ep; + + evb = event_init(); + + ep = accept_e; + for (u = 0; u < HERITAGE_NSOCKS; u++) { + if (heritage.sock_local[u] >= 0) { + event_set(ep, heritage.sock_local[u], + EV_READ | EV_PERSIST, + accept_f, NULL); + event_base_set(evb, ep); + event_add(ep, NULL); + ep++; + } + if (heritage.sock_remote[u] >= 0) { + event_set(ep, heritage.sock_remote[u], + EV_READ | EV_PERSIST, + accept_f, NULL); + event_base_set(evb, ep); + event_add(ep, NULL); + ep++; + } + } + + event_base_loop(evb, 0); + + return ("FOOBAR"); +} Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-23 12:20:30 UTC (rev 61) @@ -8,12 +8,16 @@ #include #include +#include + #include #include #include +#include "libvarnish.h" #include "heritage.h" +#include "cache.h" #include "cli_event.h" static struct event ev_keepalive; @@ -48,7 +52,6 @@ { cli_out(cli, "url <%s>", av[2]); - sleep(1); cli_result(cli, CLIS_UNIMPL); } @@ -76,6 +79,8 @@ { NULL } }; +static pthread_t vca_thread; + void child_main(void) { @@ -87,6 +92,8 @@ setbuf(stderr, NULL); printf("Child starts\n"); + AZ(pthread_create(&vca_thread, NULL, vca_main, NULL)); + eb = event_init(); assert(eb != NULL); Modified: trunk/varnish-cache/bin/varnishd/mgt_child.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-23 12:20:30 UTC (rev 61) @@ -62,10 +62,12 @@ { const char *p; - p = evbuffer_readline(bev->input); - if (p == NULL) - return; - printf("Child said <%s>\n", p); + while (1) { + p = evbuffer_readline(bev->input); + if (p == NULL) + return; + printf("Child said <%s>\n", p); + } } static void Modified: trunk/varnish-cache/bin/varnishd/tcp.c =================================================================== --- trunk/varnish-cache/bin/varnishd/tcp.c 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/tcp.c 2006-03-23 12:20:30 UTC (rev 61) @@ -10,6 +10,7 @@ #include #include "heritage.h" +#include "libvarnish.h" static void create_listen_socket(const char *addr, const char *port, int *sp, int nsp) @@ -24,7 +25,7 @@ i = getaddrinfo(addr, port, &ai, &r0); if (i) { - fprintf("getaddrinfo failed: %s\n", gai_strerror(i)); + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(i)); return; } @@ -62,5 +63,11 @@ create_listen_socket(NULL, port, &heritage.sock_remote[0], HERITAGE_NSOCKS); + for (u = 0; u < HERITAGE_NSOCKS; u++) { + if (heritage.sock_local[u] >= 0) + AZ(listen(heritage.sock_local[u], 16)); + if (heritage.sock_remote[u] >= 0) + AZ(listen(heritage.sock_remote[u], 16)); + } return (0); } Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-23 08:45:44 UTC (rev 60) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-23 12:20:30 UTC (rev 61) @@ -176,20 +176,18 @@ main(int argc, char *argv[]) { int o; - unsigned portnumber = 8080; + const char *portnumber = "8080"; unsigned dflag = 1; /* XXX: debug=on for now */ register_printf_render_std((const unsigned char *)"HVQ"); - open_tcp("8080"); - while ((o = getopt(argc, argv, "dp:")) != -1) switch (o) { case 'd': dflag++; break; case 'p': - portnumber = strtoul(optarg, NULL, 0); + portnumber = optarg; break; default: usage(); @@ -201,6 +199,15 @@ if (argc != 0) usage(); + /* + * XXX: Lacking the suspend/resume facility (due to the socket API + * missing an unlisten(2) facility) we may want to push this into + * the child to limit the amount of time where the socket(s) exists + * but do not answer. That, on the other hand, would eliminate the + * possibility of doing a "no-glitch" restart of the child process. + */ + open_tcp(portnumber); + testme(); From phk at projects.linpro.no Thu Mar 23 15:31:20 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 23 Mar 2006 16:31:20 +0100 (CET) Subject: r62 - trunk/varnish-cache/bin/varnishd Message-ID: <20060323153120.D7A931ED59F@projects.linpro.no> Author: phk Date: 2006-03-23 16:31:20 +0100 (Thu, 23 Mar 2006) New Revision: 62 Added: trunk/varnish-cache/bin/varnishd/cache_shmlog.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/varnishd.c Log: Add shared memory log setup and stuffer function in the child process. Log whenever we get a CLI ping Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-23 15:31:20 UTC (rev 62) @@ -7,6 +7,7 @@ varnishd_SOURCES = \ cache_acceptor.c \ cache_main.c \ + cache_shmlog.c \ cli_event.c \ mgt_child.c \ tcp.c \ Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-23 15:31:20 UTC (rev 62) @@ -12,3 +12,11 @@ /* cache_acceptor.c */ void *vca_main(void *arg); + +/* cache_shmlog.c */ +void VSL_Init(void); +#ifdef SHMLOGHEAD_MAGIC +void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...); +#endif + + Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-23 15:31:20 UTC (rev 62) @@ -17,6 +17,7 @@ #include "libvarnish.h" #include "heritage.h" +#include "shmlog.h" #include "cache.h" #include "cli_event.h" @@ -62,6 +63,7 @@ { time_t t; + VSL(SLT_CLI, 0, av[1]); arm_keepalive(); if (av[2] != NULL) { /* XXX: check clock skew is pointless here */ @@ -92,6 +94,8 @@ setbuf(stderr, NULL); printf("Child starts\n"); + VSL_Init(); + AZ(pthread_create(&vca_thread, NULL, vca_main, NULL)); eb = event_init(); @@ -100,9 +104,10 @@ cli = cli_setup(heritage.fds[2], heritage.fds[1], 0, cli_proto); evtimer_set(&ev_keepalive, timer_keepalive, NULL); + event_base_set(eb, &ev_keepalive); arm_keepalive(); - i = event_dispatch(); + i = event_base_loop(eb, 0); if (i != 0) printf("event_dispatch() = %d\n", i); Added: trunk/varnish-cache/bin/varnishd/cache_shmlog.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_shmlog.c 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/cache_shmlog.c 2006-03-23 15:31:20 UTC (rev 62) @@ -0,0 +1,87 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include + +#include "shmlog.h" + +#include "heritage.h" + +static struct shmloghead *loghead; +static unsigned char *logstart, *logend; + +void +VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...) +{ + va_list ap; + unsigned char *p, *q; + unsigned m, n; + + va_start(ap, fmt); + + /* XXX: Lock */ + q = NULL; + p = logstart + loghead->ptr; + assert(p < logend); + + /* + * Wrap early if we approach the end + * 32 is arbitraryly larger than minimum of 4. + */ + if (p + 32 > logend) { + q = p; + p = logstart; + *p = SLT_ENDMARKER; + } + n = 0; + if (fmt != NULL) { + while (1) { + m = logend - (p + 4); + if (m > 256) + m = 256; + n = vsnprintf((char *)p + 4, m, fmt, ap); + if (n >= 255) + n = 255; /* we truncate long fields */ + if (n < m) + break; + /* wraparound */ + assert(q == NULL); + q = p; + p = logstart; + *p = SLT_ENDMARKER; + continue; /* Try again */ + } + } + p[1] = n; + p[2] = id >> 8; + p[3] = id & 0xff; + p[0] = tag; + + if (q != NULL) + *q = SLT_WRAPMARKER; + + loghead->ptr = (p + 4 + n) - logstart; + + /* XXX: Unlock */ + + va_end(ap); +} + +void +VSL_Init(void) +{ + + loghead = mmap(NULL, heritage.vsl_size, + PROT_READ|PROT_WRITE, + MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED, + heritage.vsl_fd, 0); + assert(loghead != MAP_FAILED); + + /* XXX check sanity of loghead */ + logstart = (unsigned char *)loghead + loghead->start; + logend = logstart + loghead->size; +} Modified: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-23 15:31:20 UTC (rev 62) @@ -20,6 +20,10 @@ #define HERITAGE_NSOCKS 2 /* IPv4 + IPv6 */ int sock_local[HERITAGE_NSOCKS]; int sock_remote[HERITAGE_NSOCKS]; + + /* Share memory log fd and size (incl header) */ + int vsl_fd; + unsigned vsl_size; }; extern struct heritage heritage; Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-23 12:20:30 UTC (rev 61) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-23 15:31:20 UTC (rev 62) @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include @@ -169,6 +169,39 @@ /*--------------------------------------------------------------------*/ +#include "shmlog.h" + +static void +init_vsl(const char *fn, unsigned size) +{ + struct shmloghead slh; + int i; + + heritage.vsl_fd = open(fn, O_RDWR | O_CREAT, 0600); + if (heritage.vsl_fd < 0) { + fprintf(stderr, "Could not open %s: %s\n", + fn, strerror(errno)); + exit (1); + } + i = read(heritage.vsl_fd, &slh, sizeof slh); + if (i == sizeof slh && slh.magic == SHMLOGHEAD_MAGIC) { + /* XXX more checks */ + heritage.vsl_size = slh.size + slh.start; + return; + } + slh.magic = SHMLOGHEAD_MAGIC; + slh.size = size; + slh.ptr = 0; + slh.start = sizeof slh; + AZ(lseek(heritage.vsl_fd, 0, SEEK_SET)); + i = write(heritage.vsl_fd, &slh, sizeof slh); + assert(i == sizeof slh); + AZ(ftruncate(heritage.vsl_fd, sizeof slh + size)); + heritage.vsl_size = slh.size + slh.start; +} + +/*--------------------------------------------------------------------*/ + /* for development purposes */ #include @@ -208,6 +241,8 @@ */ open_tcp(portnumber); + init_vsl("/tmp/_vsl", 1000); + testme(); From phk at projects.linpro.no Fri Mar 24 08:43:48 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 09:43:48 +0100 (CET) Subject: r63 - trunk/varnish-cache/include Message-ID: <20060324084348.7B69D1ED492@projects.linpro.no> Author: phk Date: 2006-03-24 09:43:48 +0100 (Fri, 24 Mar 2006) New Revision: 63 Added: trunk/varnish-cache/include/shmlog.h trunk/varnish-cache/include/shmlog_tags.h Modified: trunk/varnish-cache/include/cli.h trunk/varnish-cache/include/libvarnish.h Log: Move the SHM tags into a resuable .h file. Minor nits Modified: trunk/varnish-cache/include/cli.h =================================================================== --- trunk/varnish-cache/include/cli.h 2006-03-23 15:31:20 UTC (rev 62) +++ trunk/varnish-cache/include/cli.h 2006-03-24 08:43:48 UTC (rev 63) @@ -3,6 +3,12 @@ * * Public definition of the CLI protocol, part of the published Varnish-API. * + * The overall structure of the protocol is a command-line like + * "command+arguments" request and a IETF style "number + string" response. + * + * Arguments can contain arbitrary sequences of bytes which are encoded + * in back-slash notation in double-quoted, if necessary. + * */ /* Modified: trunk/varnish-cache/include/libvarnish.h =================================================================== --- trunk/varnish-cache/include/libvarnish.h 2006-03-23 15:31:20 UTC (rev 62) +++ trunk/varnish-cache/include/libvarnish.h 2006-03-24 08:43:48 UTC (rev 63) @@ -5,3 +5,8 @@ /* from libvarnish/argv.c */ void FreeArgv(char **argv); char **ParseArgv(const char *s, int comment); + + +/* Assert zero return value */ +#define AZ(foo) do { assert((foo) == 0); } while (0) + Added: trunk/varnish-cache/include/shmlog.h =================================================================== --- trunk/varnish-cache/include/shmlog.h 2006-03-23 15:31:20 UTC (rev 62) +++ trunk/varnish-cache/include/shmlog.h 2006-03-24 08:43:48 UTC (rev 63) @@ -0,0 +1,48 @@ +/* + * $Id$ + * + * Define the layout of the shared memory log segment. + * + * NB: THIS IS NOT A PUBLIC API TO VARNISH! + * + */ + +#define SHMLOG_FILENAME "/tmp/_.vsl" + +struct shmloghead { +#define SHMLOGHEAD_MAGIC 4185512498U /* From /dev/random */ + unsigned magic; + + /* + * Byte offset into the file where the fifolog starts + * This allows the header to expand later. + */ + unsigned start; + + /* Length of the fifolog area in bytes */ + unsigned size; + + /* Current write position relative to the beginning of start */ + unsigned ptr; +}; + +/* + * Record format is as follows: + * + * 1 byte field type (enum shmlogtag) + * 1 byte length of contents + * 2 byte record identifier + * n bytes field contents (isgraph(c) || isspace(c)) allowed. + */ + +/* + * The identifiers in shmlogtag are "SLT_" + XML tag. A script may be run + * on this file to extract the table rather than handcode it + */ +enum shmlogtag { + SLT_ENDMARKER = 0, +#define SLTM(foo) SLT_##foo, +#include "shmlog_tags.h" +#undef SLTM + SLT_WRAPMARKER = 255 +}; Added: trunk/varnish-cache/include/shmlog_tags.h =================================================================== --- trunk/varnish-cache/include/shmlog_tags.h 2006-03-23 15:31:20 UTC (rev 62) +++ trunk/varnish-cache/include/shmlog_tags.h 2006-03-24 08:43:48 UTC (rev 63) @@ -0,0 +1,14 @@ +/* + * $Id$ + * + * Define the tags in the shared memory in a reusable format. + * Whoever includes this get to define what the SLTM macro does. + * + */ + +SLTM(CLI) +SLTM(SessionId) +SLTM(ClientAddr) +SLTM(Request) +SLTM(URL) +SLTM(Protocol) From phk at projects.linpro.no Fri Mar 24 09:05:19 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 10:05:19 +0100 (CET) Subject: r64 - in trunk/varnish-cache: . bin bin/varnishd bin/varnishlog Message-ID: <20060324090519.DAF9C1ED5A7@projects.linpro.no> Author: phk Date: 2006-03-24 10:05:19 +0100 (Fri, 24 Mar 2006) New Revision: 64 Added: trunk/varnish-cache/bin/varnishlog/ trunk/varnish-cache/bin/varnishlog/Makefile.am trunk/varnish-cache/bin/varnishlog/varnishlog.c Modified: trunk/varnish-cache/bin/Makefile.am trunk/varnish-cache/bin/varnishd/varnishd.c trunk/varnish-cache/configure.ac Log: Add a minimal log tailer. Modified: trunk/varnish-cache/bin/Makefile.am =================================================================== --- trunk/varnish-cache/bin/Makefile.am 2006-03-24 08:43:48 UTC (rev 63) +++ trunk/varnish-cache/bin/Makefile.am 2006-03-24 09:05:19 UTC (rev 64) @@ -1,3 +1,3 @@ # $Id$ -SUBDIRS = varnishd +SUBDIRS = varnishd varnishlog Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-24 08:43:48 UTC (rev 63) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-24 09:05:19 UTC (rev 64) @@ -241,7 +241,7 @@ */ open_tcp(portnumber); - init_vsl("/tmp/_vsl", 1000); + init_vsl(SHMLOG_FILENAME, 1024*1024); testme(); Added: trunk/varnish-cache/bin/varnishlog/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishlog/Makefile.am 2006-03-24 08:43:48 UTC (rev 63) +++ trunk/varnish-cache/bin/varnishlog/Makefile.am 2006-03-24 09:05:19 UTC (rev 64) @@ -0,0 +1,9 @@ +# $Id: Makefile.am 62 2006-03-23 15:31:20Z phk $ + +INCLUDES = -I$(top_srcdir)/include + +bin_PROGRAMS = varnishlog + +varnishlog_SOURCES = varnishlog.c + +# varnishlog_LDADD = $(top_builddir)/lib/libvarnishapi/libvarnishapi.la Added: trunk/varnish-cache/bin/varnishlog/varnishlog.c =================================================================== --- trunk/varnish-cache/bin/varnishlog/varnishlog.c 2006-03-24 08:43:48 UTC (rev 63) +++ trunk/varnish-cache/bin/varnishlog/varnishlog.c 2006-03-24 09:05:19 UTC (rev 64) @@ -0,0 +1,319 @@ +/* + * $Id$ + * + * Log tailer for Varnish + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct shmloghead *loghead; +static unsigned char *logstart, *logend; + +int +main(int argc, char **argv) +{ + int fd; + int i; + struct shmloghead slh; + unsigned char *p; + + fd = open(SHMLOG_FILENAME, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", + SHMLOG_FILENAME, strerror(errno)); + exit (1); + } + i = read(fd, &slh, sizeof slh); + if (i != sizeof slh) { + fprintf(stderr, "Cannot read %s: %s\n", + SHMLOG_FILENAME, strerror(errno)); + exit (1); + } + if (slh.magic != SHMLOGHEAD_MAGIC) { + fprintf(stderr, "Wrong magic number in file %s\n", + SHMLOG_FILENAME); + exit (1); + } + + loghead = mmap(NULL, slh.size + sizeof slh, + PROT_READ, MAP_HASSEMAPHORE, fd, 0); + if (loghead == MAP_FAILED) { + fprintf(stderr, "Cannot mmap %s: %s\n", + SHMLOG_FILENAME, strerror(errno)); + exit (1); + } + logstart = (unsigned char *)loghead + loghead->start; + logend = logstart + loghead->size; + + while (1) { + p = logstart; + while (1) { + if (*p == SLT_WRAPMARKER) + break; + while (*p == SLT_ENDMARKER) + sleep(1); + printf("%02x %02d %02x%02x <", + p[0], p[1], p[2], p[3]); + if (p[1] > 0) + fwrite(p + 4, p[1], 1, stdout); + printf(">\n"); + p += p[1] + 4; + } + } +} + + +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include "mgt.h" +#include "heritage.h" +#include "cli_event.h" + +/*--------------------------------------------------------------------*/ + +struct heritage heritage; +struct event_base *eb; + +/*-------------------------------------------------------------------- + * Generic passthrough for CLI functions + */ + +void +cli_passthrough_cb(unsigned u, const char *r, void *priv) +{ + struct cli *cli = priv; + + cli_out(cli, "%s\n", r); + cli_result(cli, u); + cli_resume(cli); +} + +static void +cli_func_passthrough(struct cli *cli, char **av __unused, void *priv) +{ + + cli_suspend(cli); + mgt_child_request(cli_passthrough_cb, cli, &av[2], av[1]); +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_server_start(struct cli *cli, char **av __unused, void *priv __unused) +{ + + mgt_child_start(); +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_server_stop(struct cli *cli, char **av __unused, void *priv __unused) +{ + + mgt_child_stop(); +} + +/*--------------------------------------------------------------------*/ + +static void +cli_func_verbose(struct cli *cli, char **av __unused, void *priv) +{ + + cli->verbose = !cli->verbose; +} + + +static void +cli_func_ping(struct cli *cli, char **av, void *priv __unused) +{ + time_t t; + + if (av[2] != NULL) { + cli_out(cli, "Got your %s\n", av[2]); + } + time(&t); + cli_out(cli, "PONG %ld\n", t); +} + +/*--------------------------------------------------------------------*/ + +static struct cli_proto cli_proto[] = { + /* URL manipulation */ + { CLI_URL_QUERY, cli_func_passthrough, NULL }, + { CLI_URL_PURGE, cli_func_passthrough, NULL }, + { CLI_URL_STATUS, cli_func_passthrough, NULL }, + { CLI_CONFIG_LOAD }, + { CLI_CONFIG_INLINE }, + { CLI_CONFIG_UNLOAD }, + { CLI_CONFIG_LIST }, + { CLI_CONFIG_USE }, + { CLI_SERVER_FREEZE, cli_func_passthrough, NULL }, + { CLI_SERVER_THAW, cli_func_passthrough, NULL }, + { CLI_SERVER_SUSPEND, cli_func_passthrough, NULL }, + { CLI_SERVER_RESUME, cli_func_passthrough, NULL }, + { CLI_SERVER_STOP, cli_func_server_stop, NULL }, + { CLI_SERVER_START, cli_func_server_start, NULL }, + { CLI_SERVER_RESTART }, + { CLI_PING, cli_func_ping, NULL }, + { CLI_STATS }, + { CLI_ZERO }, + { CLI_HELP, cli_func_help, cli_proto }, + { CLI_VERBOSE, cli_func_verbose, NULL }, + { CLI_EXIT }, + { CLI_QUIT }, + { CLI_BYE }, + { NULL } +}; + +static void +testme(void) +{ + struct event e_sigchld; + struct cli *cli; + int i; + + eb = event_init(); + assert(eb != NULL); + + cli = cli_setup(0, 1, 1, cli_proto); + + signal_set(&e_sigchld, SIGCHLD, mgt_sigchld, NULL); + signal_add(&e_sigchld, NULL); + + i = event_dispatch(); + if (i != 0) + printf("event_dispatch() = %d\n", i); + +} + +/*--------------------------------------------------------------------*/ + +static void +usage(void) +{ + fprintf(stderr, "usage: varnishd [options]\n"); + fprintf(stderr, " %-20s # %s\n", "-d", "debug"); + fprintf(stderr, " %-20s # %s\n", "-p number", "TCP listen port"); +#if 0 + -c clusterid at cluster_controller + -f config_file + -m memory_limit + -s kind[,storage-options] + -l logfile,logsize + -b backend ip... + -u uid + -a CLI_port +#endif + exit(1); +} + +/*--------------------------------------------------------------------*/ + +#include "shmlog.h" + +static void +init_vsl(const char *fn, unsigned size) +{ + struct shmloghead slh; + int i; + + heritage.vsl_fd = open(fn, O_RDWR | O_CREAT, 0600); + if (heritage.vsl_fd < 0) { + fprintf(stderr, "Could not open %s: %s\n", + fn, strerror(errno)); + exit (1); + } + i = read(heritage.vsl_fd, &slh, sizeof slh); + if (i == sizeof slh && slh.magic == SHMLOGHEAD_MAGIC) { + /* XXX more checks */ + heritage.vsl_size = slh.size + slh.start; + return; + } + slh.magic = SHMLOGHEAD_MAGIC; + slh.size = size; + slh.ptr = 0; + slh.start = sizeof slh; + AZ(lseek(heritage.vsl_fd, 0, SEEK_SET)); + i = write(heritage.vsl_fd, &slh, sizeof slh); + assert(i == sizeof slh); + AZ(ftruncate(heritage.vsl_fd, sizeof slh + size)); + heritage.vsl_size = slh.size + slh.start; +} + +/*--------------------------------------------------------------------*/ + +/* for development purposes */ +#include + +int +main(int argc, char *argv[]) +{ + int o; + const char *portnumber = "8080"; + unsigned dflag = 1; /* XXX: debug=on for now */ + + register_printf_render_std((const unsigned char *)"HVQ"); + + while ((o = getopt(argc, argv, "dp:")) != -1) + switch (o) { + case 'd': + dflag++; + break; + case 'p': + portnumber = optarg; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + /* + * XXX: Lacking the suspend/resume facility (due to the socket API + * missing an unlisten(2) facility) we may want to push this into + * the child to limit the amount of time where the socket(s) exists + * but do not answer. That, on the other hand, would eliminate the + * possibility of doing a "no-glitch" restart of the child process. + */ + open_tcp(portnumber); + + init_vsl(SHMLOG_FILENAME, 1024*1024); + + testme(); + + + exit(0); +} +#endif Modified: trunk/varnish-cache/configure.ac =================================================================== --- trunk/varnish-cache/configure.ac 2006-03-24 08:43:48 UTC (rev 63) +++ trunk/varnish-cache/configure.ac 2006-03-24 09:05:19 UTC (rev 64) @@ -70,5 +70,6 @@ lib/libvarnishapi/Makefile bin/Makefile bin/varnishd/Makefile + bin/varnishlog/Makefile ]) AC_OUTPUT From phk at projects.linpro.no Fri Mar 24 09:14:06 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 10:14:06 +0100 (CET) Subject: r65 - trunk/varnish-cache/bin/varnishlog Message-ID: <20060324091406.C6A3F1ED586@projects.linpro.no> Author: phk Date: 2006-03-24 10:14:06 +0100 (Fri, 24 Mar 2006) New Revision: 65 Modified: trunk/varnish-cache/bin/varnishlog/varnishlog.c Log: put symbolic names on the tags Modified: trunk/varnish-cache/bin/varnishlog/varnishlog.c =================================================================== --- trunk/varnish-cache/bin/varnishlog/varnishlog.c 2006-03-24 09:05:19 UTC (rev 64) +++ trunk/varnish-cache/bin/varnishlog/varnishlog.c 2006-03-24 09:14:06 UTC (rev 65) @@ -14,6 +14,23 @@ #include +/* + * It would be simpler to use sparse array initialization and put it + * directly in tagnames, but -pedantic gets in the way + */ + +static struct tagnames { + enum shmlogtag tag; + const char *name; +} stagnames[] = { +#define SLTM(foo) { SLT_##foo, #foo }, +#include "shmlog_tags.h" +#undef SLTM + { SLT_ENDMARKER, NULL} +}; + +static const char *tagnames[256]; + static struct shmloghead *loghead; static unsigned char *logstart, *logend; @@ -53,6 +70,9 @@ logstart = (unsigned char *)loghead + loghead->start; logend = logstart + loghead->size; + for (i = 0; stagnames[i].tag != SLT_ENDMARKER; i++) + tagnames[stagnames[i].tag] = stagnames[i].name; + while (1) { p = logstart; while (1) { @@ -60,8 +80,9 @@ break; while (*p == SLT_ENDMARKER) sleep(1); - printf("%02x %02d %02x%02x <", - p[0], p[1], p[2], p[3]); + printf("%02x %02d %02x%02x %-12s <", + p[0], p[1], p[2], p[3], + tagnames[p[0]]); if (p[1] > 0) fwrite(p + 4, p[1], 1, stdout); printf(">\n"); From phk at projects.linpro.no Fri Mar 24 09:45:39 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 10:45:39 +0100 (CET) Subject: r66 - in trunk/varnish-cache: bin/varnishd include Message-ID: <20060324094539.392C91ED5AF@projects.linpro.no> Author: phk Date: 2006-03-24 10:45:39 +0100 (Fri, 24 Mar 2006) New Revision: 66 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/include/shmlog_tags.h Log: Log remote IP#:port on session open Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 09:14:06 UTC (rev 65) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 09:45:39 UTC (rev 66) @@ -3,9 +3,11 @@ */ #define VCA_RXBUFSIZE 1024 +#define VCA_ADDRBUFSIZE 32 struct sess { int fd; char rcv[VCA_RXBUFSIZE + 1]; + char addr[VCA_ADDRBUFSIZE]; unsigned rcv_len; struct event rd_e; }; Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 09:14:06 UTC (rev 65) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 09:45:39 UTC (rev 66) @@ -11,10 +11,14 @@ #include #include +#include + #include #include +#include "libvarnish.h" #include "heritage.h" +#include "shmlog.h" #include "cache.h" static struct event_base *evb; @@ -31,7 +35,14 @@ printf("%s(%d, %d, ...)\n", __func__, fd, event); assert(VCA_RXBUFSIZE - sp->rcv_len > 0); i = read(fd, sp->rcv + sp->rcv_len, VCA_RXBUFSIZE - sp->rcv_len); - assert(i > 0); + if (i <= 0) { + VSL(SLT_SessionClose, sp->fd, "remote %d", sp->rcv_len); + event_del(&sp->rd_e); + close(sp->fd); + free(sp); + return; + } + sp->rcv_len += i; sp->rcv[sp->rcv_len] = '\0'; @@ -58,19 +69,26 @@ socklen_t l; struct sockaddr addr; struct sess *sp; + char port[10]; sp = calloc(sizeof *sp, 1); - assert(sp != NULL); + assert(sp != NULL); /* + * XXX: this is probably one we should handle + * XXX: accept, emit error NNN and close + */ - printf("%s(%d, %d, ...)\n", __func__, fd, event); - l = sizeof addr; sp->fd = accept(fd, &addr, &l); if (sp->fd < 0) { free(sp); return; } - + AZ(getnameinfo(&addr, l, + sp->addr, VCA_ADDRBUFSIZE, + port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV)); + strlcat(sp->addr, ":", VCA_ADDRBUFSIZE); + strlcat(sp->addr, port, VCA_ADDRBUFSIZE); + VSL(SLT_SessionOpen, sp->fd, "%s", sp->addr); event_set(&sp->rd_e, sp->fd, EV_READ | EV_PERSIST, http_read_f, sp); event_base_set(evb, &sp->rd_e); Modified: trunk/varnish-cache/include/shmlog_tags.h =================================================================== --- trunk/varnish-cache/include/shmlog_tags.h 2006-03-24 09:14:06 UTC (rev 65) +++ trunk/varnish-cache/include/shmlog_tags.h 2006-03-24 09:45:39 UTC (rev 66) @@ -7,7 +7,8 @@ */ SLTM(CLI) -SLTM(SessionId) +SLTM(SessionOpen) +SLTM(SessionClose) SLTM(ClientAddr) SLTM(Request) SLTM(URL) From phk at projects.linpro.no Fri Mar 24 10:22:47 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 11:22:47 +0100 (CET) Subject: r67 - trunk/varnish-cache/bin/varnishd Message-ID: <20060324102247.7AFBC1ED5B3@projects.linpro.no> Author: phk Date: 2006-03-24 11:22:47 +0100 (Fri, 24 Mar 2006) New Revision: 67 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_shmlog.c Log: Add a VSLR() variant which logs a byte range without spending time in sprintf Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 09:45:39 UTC (rev 66) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 10:22:47 UTC (rev 67) @@ -9,15 +9,20 @@ char rcv[VCA_RXBUFSIZE + 1]; char addr[VCA_ADDRBUFSIZE]; unsigned rcv_len; - struct event rd_e; + struct event *rd_e; + struct sessmem *mem; }; /* cache_acceptor.c */ void *vca_main(void *arg); +/* cache_httpd.c */ +void HttpdAnalyze(struct sess *sp); + /* cache_shmlog.c */ void VSL_Init(void); #ifdef SHMLOGHEAD_MAGIC +void VSLR(enum shmlogtag tag, unsigned id, const char *b, const char *e); void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...); #endif Modified: trunk/varnish-cache/bin/varnishd/cache_shmlog.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_shmlog.c 2006-03-24 09:45:39 UTC (rev 66) +++ trunk/varnish-cache/bin/varnishd/cache_shmlog.c 2006-03-24 10:22:47 UTC (rev 67) @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -14,7 +15,55 @@ static struct shmloghead *loghead; static unsigned char *logstart, *logend; +/* + * This variant copies a byte-range directly to the log, without + * taking the detour over sprintf() + */ + void +VSLR(enum shmlogtag tag, unsigned id, const char *b, const char *e) +{ + va_list ap; + unsigned char *p, *q; + + assert(b != NULL); + if (e == NULL) + e = strchr(b, '\0'); + assert(e != NULL); + + /* Truncate */ + if (e - b > 255) + e = b + 255; + + /* XXX: Lock */ + q = NULL; + p = logstart + loghead->ptr; + assert(p < logend); + + /* Wrap if necessary */ + if (p + 4 + (e - b) > logend) { + q = p; + p = logstart; + *p = SLT_ENDMARKER; + } + p[1] = e - b; + p[2] = id >> 8; + p[3] = id & 0xff; + memcpy(p + 4, b, e - b); + p[0] = tag; + + if (q != NULL) + *q = SLT_WRAPMARKER; + + loghead->ptr = (p + 4 + (e - b)) - logstart; + + /* XXX: Unlock */ + + va_end(ap); +} + + +void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...) { va_list ap; From phk at projects.linpro.no Fri Mar 24 10:23:43 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 11:23:43 +0100 (CET) Subject: r68 - trunk/varnish-cache/bin/varnishd Message-ID: <20060324102343.D52CE1ED5B4@projects.linpro.no> Author: phk Date: 2006-03-24 11:23:43 +0100 (Fri, 24 Mar 2006) New Revision: 68 Added: trunk/varnish-cache/bin/varnishd/cache_httpd.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache_acceptor.c Log: Change session memory management to avoid pollution Add fledling httpd parsing Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-24 10:22:47 UTC (rev 67) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-24 10:23:43 UTC (rev 68) @@ -6,6 +6,7 @@ varnishd_SOURCES = \ cache_acceptor.c \ + cache_httpd.c \ cache_main.c \ cache_shmlog.c \ cli_event.c \ Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 10:22:47 UTC (rev 67) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 10:23:43 UTC (rev 68) @@ -25,6 +25,11 @@ static struct event accept_e[2 * HERITAGE_NSOCKS]; +struct sessmem { + struct sess s; + struct event e; +}; + static void http_read_f(int fd, short event, void *arg) { @@ -37,9 +42,9 @@ i = read(fd, sp->rcv + sp->rcv_len, VCA_RXBUFSIZE - sp->rcv_len); if (i <= 0) { VSL(SLT_SessionClose, sp->fd, "remote %d", sp->rcv_len); - event_del(&sp->rd_e); + event_del(sp->rd_e); close(sp->fd); - free(sp); + free(sp->mem); return; } @@ -59,24 +64,30 @@ continue; break; } + event_del(sp->rd_e); + HttpdAnalyze(sp); printf("full <%s>\n", sp->rcv); - event_del(&sp->rd_e); } static void accept_f(int fd, short event, void *arg __unused) { socklen_t l; + struct sessmem *sm; struct sockaddr addr; struct sess *sp; char port[10]; - sp = calloc(sizeof *sp, 1); - assert(sp != NULL); /* + sm = calloc(sizeof *sm, 1); + assert(sm != NULL); /* * XXX: this is probably one we should handle * XXX: accept, emit error NNN and close */ + sp = &sm->s; + sp->rd_e = &sm->e; + sp->mem = sm; + l = sizeof addr; sp->fd = accept(fd, &addr, &l); if (sp->fd < 0) { @@ -89,10 +100,10 @@ strlcat(sp->addr, ":", VCA_ADDRBUFSIZE); strlcat(sp->addr, port, VCA_ADDRBUFSIZE); VSL(SLT_SessionOpen, sp->fd, "%s", sp->addr); - event_set(&sp->rd_e, sp->fd, EV_READ | EV_PERSIST, + event_set(sp->rd_e, sp->fd, EV_READ | EV_PERSIST, http_read_f, sp); - event_base_set(evb, &sp->rd_e); - event_add(&sp->rd_e, NULL); /* XXX: timeout */ + event_base_set(evb, sp->rd_e); + event_add(sp->rd_e, NULL); /* XXX: timeout */ } void * Added: trunk/varnish-cache/bin/varnishd/cache_httpd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-24 10:22:47 UTC (rev 67) +++ trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-24 10:23:43 UTC (rev 68) @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * Stuff relating to HTTP server side + */ + +#include +#include + +#include "libvarnish.h" +#include "shmlog.h" +#include "cache.h" + +void +HttpdAnalyze(struct sess *sp) +{ + const char *p, *q, *u; + + p = sp->rcv; + + if (p[0] == 'G' && p[1] == 'E' && p[2] == 'T' && p[3] == ' ') { + p += 4; + VSL(SLT_Request, sp->fd, "GET"); + } else if (p[0] == 'H' && p[1] == 'E' && p[2] == 'A' && p[3] == 'D' + && p[4] == ' ') { + p += 5; + VSL(SLT_Request, sp->fd, "HEAD"); + } else { + for (q = p; isupper(*q); q++) + ; + VSLR(SLT_Request, sp->fd, p, q); + p = q; + } + while (isspace(*p)) + p++; + u = p; + while (!isspace(*p)) + p++; + VSLR(SLT_URL, sp->fd, u, p); +} From phk at projects.linpro.no Fri Mar 24 10:46:46 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 24 Mar 2006 11:46:46 +0100 (CET) Subject: r69 - in trunk/varnish-cache: bin/varnishd include Message-ID: <20060324104646.1E60F1ED5B3@projects.linpro.no> Author: phk Date: 2006-03-24 11:46:46 +0100 (Fri, 24 Mar 2006) New Revision: 69 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/cache_httpd.c trunk/varnish-cache/include/shmlog_tags.h Log: More complete HTTP parsing and logging. Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 10:23:43 UTC (rev 68) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-24 10:46:46 UTC (rev 69) @@ -4,11 +4,34 @@ #define VCA_RXBUFSIZE 1024 #define VCA_ADDRBUFSIZE 32 + struct sess { int fd; + + /* formatted ascii client address */ + char addr[VCA_ADDRBUFSIZE]; + + /* Receive buffer for HTTP header */ char rcv[VCA_RXBUFSIZE + 1]; - char addr[VCA_ADDRBUFSIZE]; unsigned rcv_len; + + /* HTTP request info, points into rcv */ + const char *req_b; + const char *req_e; + const char *url_b; + const char *url_e; + const char *proto_b; + const char *proto_e; + const char *hdr_b; + const char *hdr_e; + + enum { + HND_Unclass, + HND_Handle, + HND_Pass + } handling; + + /* Various internal stuff */ struct event *rd_e; struct sessmem *mem; }; Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 10:23:43 UTC (rev 68) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-24 10:46:46 UTC (rev 69) @@ -64,9 +64,9 @@ continue; break; } + sp->hdr_e = p; event_del(sp->rd_e); HttpdAnalyze(sp); - printf("full <%s>\n", sp->rcv); } static void Modified: trunk/varnish-cache/bin/varnishd/cache_httpd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-24 10:23:43 UTC (rev 68) +++ trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-24 10:46:46 UTC (rev 69) @@ -14,27 +14,60 @@ void HttpdAnalyze(struct sess *sp) { - const char *p, *q, *u; + const char *p, *q; - p = sp->rcv; + sp->handling = HND_Unclass; + /* First, isolate and possibly identify request type */ + p = sp->req_b = sp->rcv; if (p[0] == 'G' && p[1] == 'E' && p[2] == 'T' && p[3] == ' ') { - p += 4; - VSL(SLT_Request, sp->fd, "GET"); + p = sp->req_e = p + 4; + sp->handling = HND_Handle; } else if (p[0] == 'H' && p[1] == 'E' && p[2] == 'A' && p[3] == 'D' && p[4] == ' ') { - p += 5; - VSL(SLT_Request, sp->fd, "HEAD"); + p = sp->req_e = p + 5; + sp->handling = HND_Handle; } else { - for (q = p; isupper(*q); q++) + /* + * We don't bother to identify the rest, we won't handle + * them in any case + */ + for (q = p; isalpha(*q); q++) ; - VSLR(SLT_Request, sp->fd, p, q); - p = q; + p = sp->req_e = q; + sp->handling = HND_Pass; } + VSLR(SLT_Request, sp->fd, sp->req_b, sp->req_e); + + /* Next find the URI */ while (isspace(*p)) p++; - u = p; + sp->url_b = p; while (!isspace(*p)) p++; - VSLR(SLT_URL, sp->fd, u, p); + sp->url_e = p; + VSLR(SLT_URL, sp->fd, sp->url_b, sp->url_e); + + /* Finally, look for protocol, if any */ + while (isspace(*p) && *p != '\n') + p++; + sp->proto_b = sp->proto_e = p; + if (*p != '\n') { + while (!isspace(*p)) + p++; + sp->proto_e = p; + } + VSLR(SLT_Protocol, sp->fd, sp->proto_b, sp->proto_e); + + /* + * And mark the start of headers. The end of headers + * is already set in acceptor where we detected the complete request. + */ + while (*p != '\n') + p++; + p++; + while (isspace(*p) && *p != '\n') + p++; + sp->hdr_b = p; + VSLR(SLT_Headers, sp->fd, sp->hdr_b, sp->hdr_e); } Modified: trunk/varnish-cache/include/shmlog_tags.h =================================================================== --- trunk/varnish-cache/include/shmlog_tags.h 2006-03-24 10:23:43 UTC (rev 68) +++ trunk/varnish-cache/include/shmlog_tags.h 2006-03-24 10:46:46 UTC (rev 69) @@ -13,3 +13,4 @@ SLTM(Request) SLTM(URL) SLTM(Protocol) +SLTM(Headers) From phk at projects.linpro.no Mon Mar 27 09:00:51 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 11:00:51 +0200 (CEST) Subject: r70 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327090051.270541ED5A2@projects.linpro.no> Author: phk Date: 2006-03-27 11:00:51 +0200 (Mon, 27 Mar 2006) New Revision: 70 Modified: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl Log: Don't generate sparse array code. Modified: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-24 10:46:46 UTC (rev 69) +++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-27 09:00:51 UTC (rev 70) @@ -158,14 +158,17 @@ puts $fo "}" puts $fo "" -puts $fo "const char *tnames\[256\] = {" +puts $fo "const char *tnames\[256\];\n" +puts $fo "void" +puts $fo "init_tnames(void)" +puts $fo "{" foreach i $token2 { - puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 0]\" /* t2 $i */," + puts $fo "\ttnames\[[lindex $i 0]\] = \"[lindex $i 0]\";" } foreach i $tokens { - puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 1]\" /* t $i */," + puts $fo "\ttnames\[[lindex $i 0]\] = \"[lindex $i 1]\";" } -puts $fo "};" +puts $fo "}" close $foh close $fo From phk at projects.linpro.no Mon Mar 27 09:01:06 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 11:01:06 +0200 (CEST) Subject: r71 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327090106.6DB6F1ED5C3@projects.linpro.no> Author: phk Date: 2006-03-27 11:01:06 +0200 (Mon, 27 Mar 2006) New Revision: 71 Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c Log: Newly generated code Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-27 09:00:51 UTC (rev 70) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-27 09:01:06 UTC (rev 71) @@ -305,61 +305,65 @@ } } -const char *tnames[256] = { - ['!'] = "'!'" /* t2 '!' T! */, - ['%'] = "'%'" /* t2 '%' T% */, - ['&'] = "'&'" /* t2 '&' T& */, - ['('] = "'('" /* t2 '(' T( */, - [')'] = "')'" /* t2 ')' T) */, - ['*'] = "'*'" /* t2 '*' T* */, - ['+'] = "'+'" /* t2 '+' T+ */, - [','] = "','" /* t2 ',' T, */, - ['-'] = "'-'" /* t2 '-' T- */, - ['.'] = "'.'" /* t2 '.' T. */, - ['/'] = "'/'" /* t2 '/' T/ */, - ['<'] = "'<'" /* t2 '<' T< */, - ['='] = "'='" /* t2 '=' T= */, - ['>'] = "'>'" /* t2 '>' T> */, - ['{'] = "'{'" /* t2 '\{' T\{ */, - ['}'] = "'}'" /* t2 '\}' T\} */, - ['|'] = "'|'" /* t2 '|' T| */, - ['~'] = "'~'" /* t2 '~' T~ */, - [';'] = "';'" /* t2 {';'} {T;} */, - [CNUM] = "CNUM" /* t CNUM CNUM */, - [CSTR] = "CSTR" /* t CSTR CSTR */, - [EOI] = "EOI" /* t EOI EOI */, - [ID] = "ID" /* t ID ID */, - [T_ACL] = "acl" /* t T_ACL acl */, - [T_BACKEND] = "backend" /* t T_BACKEND backend */, - [T_CALL] = "call" /* t T_CALL call */, - [T_CAND] = "&&" /* t T_CAND && */, - [T_COR] = "||" /* t T_COR || */, - [T_DEC] = "--" /* t T_DEC -- */, - [T_DECR] = "/=" /* t T_DECR /= */, - [T_DIV] = "/=" /* t T_DIV /= */, - [T_ELSE] = "else" /* t T_ELSE else */, - [T_ELSEIF] = "elseif" /* t T_ELSEIF elseif */, - [T_ELSIF] = "elsif" /* t T_ELSIF elsif */, - [T_EQ] = "==" /* t T_EQ == */, - [T_ERROR] = "error" /* t T_ERROR error */, - [T_FETCH] = "fetch" /* t T_FETCH fetch */, - [T_FINISH] = "finish" /* t T_FINISH finish */, - [T_FUNC] = "func" /* t T_FUNC func */, - [T_GEQ] = ">=" /* t T_GEQ >= */, - [T_IF] = "if" /* t T_IF if */, - [T_INC] = "++" /* t T_INC ++ */, - [T_INCR] = "+=" /* t T_INCR += */, - [T_LEQ] = "<=" /* t T_LEQ <= */, - [T_MUL] = "*=" /* t T_MUL *= */, - [T_NEQ] = "!=" /* t T_NEQ != */, - [T_NO_CACHE] = "no_cache" /* t T_NO_CACHE no_cache */, - [T_NO_NEW_CACHE] = "no_new_cache" /* t T_NO_NEW_CACHE no_new_cache */, - [T_PROC] = "proc" /* t T_PROC proc */, - [T_REWRITE] = "rewrite" /* t T_REWRITE rewrite */, - [T_SET] = "set" /* t T_SET set */, - [T_SHL] = "<<" /* t T_SHL << */, - [T_SHR] = ">>" /* t T_SHR >> */, - [T_SUB] = "sub" /* t T_SUB sub */, - [T_SWITCH_CONFIG] = "switch_config" /* t T_SWITCH_CONFIG switch_config */, - [VAR] = "VAR" /* t VAR VAR */, -}; +const char *tnames[256]; + +void +init_tnames(void) +{ + tnames['!'] = "'!'"; + tnames['%'] = "'%'"; + tnames['&'] = "'&'"; + tnames['('] = "'('"; + tnames[')'] = "')'"; + tnames['*'] = "'*'"; + tnames['+'] = "'+'"; + tnames[','] = "','"; + tnames['-'] = "'-'"; + tnames['.'] = "'.'"; + tnames['/'] = "'/'"; + tnames['<'] = "'<'"; + tnames['='] = "'='"; + tnames['>'] = "'>'"; + tnames['{'] = "'{'"; + tnames['}'] = "'}'"; + tnames['|'] = "'|'"; + tnames['~'] = "'~'"; + tnames[';'] = "';'"; + tnames[CNUM] = "CNUM"; + tnames[CSTR] = "CSTR"; + tnames[EOI] = "EOI"; + tnames[ID] = "ID"; + tnames[T_ACL] = "acl"; + tnames[T_BACKEND] = "backend"; + tnames[T_CALL] = "call"; + tnames[T_CAND] = "&&"; + tnames[T_COR] = "||"; + tnames[T_DEC] = "--"; + tnames[T_DECR] = "/="; + tnames[T_DIV] = "/="; + tnames[T_ELSE] = "else"; + tnames[T_ELSEIF] = "elseif"; + tnames[T_ELSIF] = "elsif"; + tnames[T_EQ] = "=="; + tnames[T_ERROR] = "error"; + tnames[T_FETCH] = "fetch"; + tnames[T_FINISH] = "finish"; + tnames[T_FUNC] = "func"; + tnames[T_GEQ] = ">="; + tnames[T_IF] = "if"; + tnames[T_INC] = "++"; + tnames[T_INCR] = "+="; + tnames[T_LEQ] = "<="; + tnames[T_MUL] = "*="; + tnames[T_NEQ] = "!="; + tnames[T_NO_CACHE] = "no_cache"; + tnames[T_NO_NEW_CACHE] = "no_new_cache"; + tnames[T_PROC] = "proc"; + tnames[T_REWRITE] = "rewrite"; + tnames[T_SET] = "set"; + tnames[T_SHL] = "<<"; + tnames[T_SHR] = ">>"; + tnames[T_SUB] = "sub"; + tnames[T_SWITCH_CONFIG] = "switch_config"; + tnames[VAR] = "VAR"; +} From phk at projects.linpro.no Mon Mar 27 09:01:56 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 11:01:56 +0200 (CEST) Subject: r72 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327090156.A085B1ED5D0@projects.linpro.no> Author: phk Date: 2006-03-27 11:01:56 +0200 (Mon, 27 Mar 2006) New Revision: 72 Added: trunk/varnish-cache/lib/libvcl/Makefile.am Removed: trunk/varnish-cache/lib/libvcl/Makefile Log: Put under control of auto* tools Deleted: trunk/varnish-cache/lib/libvcl/Makefile =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile 2006-03-27 09:01:06 UTC (rev 71) +++ trunk/varnish-cache/lib/libvcl/Makefile 2006-03-27 09:01:56 UTC (rev 72) @@ -1,23 +0,0 @@ -PROG = vpc - -SRCS += vcl_compile.c -SRCS += vcl_fixed_token.c - -NO_MAN = yes - -WARNS ?= 5 - -LDADD += -lsbuf - -.include - - -test: ${PROG} - ./${PROG} ${.CURDIR}/sample.vcl - cc -Wall -c _.c - -flint: - flint flint.lnt -I/usr/include -I. ${SRCS} - -distclean: clean - Added: trunk/varnish-cache/lib/libvcl/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile.am 2006-03-27 09:01:06 UTC (rev 71) +++ trunk/varnish-cache/lib/libvcl/Makefile.am 2006-03-27 09:01:56 UTC (rev 72) @@ -0,0 +1,9 @@ +# $Id$ + +INCLUDES = -I$(top_srcdir)/include + +lib_LTLIBRARIES = libvcl.la + +libvcl_la_SOURCES = \ + vcl_compile.c \ + vcl_fixed_token.c From phk at projects.linpro.no Mon Mar 27 09:02:10 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 11:02:10 +0200 (CEST) Subject: r73 - trunk/varnish-cache Message-ID: <20060327090210.957771ED5DD@projects.linpro.no> Author: phk Date: 2006-03-27 11:02:10 +0200 (Mon, 27 Mar 2006) New Revision: 73 Modified: trunk/varnish-cache/configure.ac Log: add libvcl Modified: trunk/varnish-cache/configure.ac =================================================================== --- trunk/varnish-cache/configure.ac 2006-03-27 09:01:56 UTC (rev 72) +++ trunk/varnish-cache/configure.ac 2006-03-27 09:02:10 UTC (rev 73) @@ -68,6 +68,7 @@ lib/libsbuf/Makefile lib/libvarnish/Makefile lib/libvarnishapi/Makefile + lib/libvcl/Makefile bin/Makefile bin/varnishd/Makefile bin/varnishlog/Makefile From phk at projects.linpro.no Mon Mar 27 11:21:18 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 13:21:18 +0200 (CEST) Subject: r74 - trunk/varnish-cache/include Message-ID: <20060327112118.78FBC1ED5A2@projects.linpro.no> Author: phk Date: 2006-03-27 13:21:18 +0200 (Mon, 27 Mar 2006) New Revision: 74 Added: trunk/varnish-cache/include/vcl_lang.h Log: Stuff VCL programs needs to know about. Added: trunk/varnish-cache/include/vcl_lang.h =================================================================== --- trunk/varnish-cache/include/vcl_lang.h 2006-03-27 09:02:10 UTC (rev 73) +++ trunk/varnish-cache/include/vcl_lang.h 2006-03-27 11:21:18 UTC (rev 74) @@ -0,0 +1,74 @@ +/* + * Stuff necessary to compile a VCL programs C code + * + * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl + * XXX: *MUST* be rerun. + */ + + +struct vcl_ref { + unsigned line; + unsigned pos; + unsigned count; + const char *token; +}; + +struct vcl_acl { + unsigned ip; + unsigned mask; +}; + +struct client { + unsigned ip; +}; + +struct req { + char *req; + char *useragent; + struct { + char *path; + char *host; + } url; + double ttlfactor; + struct backend *backend; +}; + +struct backend { + unsigned ip; + double responsetime; + double timeout; + double bandwidth; + int down; +}; + +struct obj { + int exists; + double ttl; + unsigned result; + unsigned size; + unsigned usage; +}; + +#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend +#define VCL_PASS_ARGS client, obj, req, backend + +void VCL_count(unsigned); +void VCL_no_cache(); +void VCL_no_new_cache(); +int ip_match(unsigned, struct vcl_acl *); +int string_match(const char *, const char *); +int VCL_rewrite(const char *, const char *); +int VCL_error(unsigned, const char *); +int VCL_fetch(void); +int VCL_switch_config(const char *); + +typedef void vcl_init_f(void); + +struct VCL_conf { + unsigned magic; +#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */ + vcl_init_f *init_func; + struct backend *default_backend; + struct vcl_ref *ref; + unsigned nref; +}; From phk at projects.linpro.no Mon Mar 27 11:21:59 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 13:21:59 +0200 (CEST) Subject: r75 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327112159.0AEA21ED5E6@projects.linpro.no> Author: phk Date: 2006-03-27 13:21:58 +0200 (Mon, 27 Mar 2006) New Revision: 75 Removed: trunk/varnish-cache/lib/libvcl/vcl_lang.h Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcl_priv.h Log: Actually generate a shared object Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 11:21:18 UTC (rev 74) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 11:21:58 UTC (rev 75) @@ -42,6 +42,8 @@ #include #include "vcl_priv.h" +#include "libvcl.h" + #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define INDENT 2 @@ -61,7 +63,7 @@ struct token *t; int indent; unsigned cnt; - FILE *fc, *fh; + struct sbuf *fc, *fh; TAILQ_HEAD(, ref) refs; struct sbuf *sb; int err; @@ -226,7 +228,7 @@ { if (tl->t->tok == tok) return; - sbuf_printf(tl->sb, "Expected %s got ", tnames[tok]); + sbuf_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]); ErrToken(tl, tl->t); sbuf_printf(tl->sb, "\n(program line %u), at\n", line); ErrWhere(tl, tl->t); @@ -236,8 +238,8 @@ #define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0) #define I(tl) do { \ - fprintf(tl->fc, "/* %-11s */ ", __func__); \ - fprintf(tl->fc, "%*.*s", tl->indent, tl->indent, ""); \ + sbuf_printf(tl->fc, "/* %-11s */ ", __func__); \ + sbuf_printf(tl->fc, "%*.*s", tl->indent, tl->indent, ""); \ } while (0) #define L(tl, foo) do { \ @@ -248,7 +250,7 @@ #define C(tl, sep) do { \ I(tl); \ - fprintf(tl->fc, "VCL_count(%u)%s\n", ++tl->cnt, sep); \ + sbuf_printf(tl->fc, "VCL_count(%u)%s\n", ++tl->cnt, sep); \ tl->t->cnt = tl->cnt; \ } while (0) @@ -506,7 +508,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = TimeUnit(tl); - fprintf(tl->fc, "(%g * %g)", v, sc); + sbuf_printf(tl->fc, "(%g * %g)", v, sc); } static void @@ -517,7 +519,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = SizeUnit(tl); - fprintf(tl->fc, "(%g * %g)", v, sc); + sbuf_printf(tl->fc, "(%g * %g)", v, sc); } static void @@ -528,7 +530,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = RateUnit(tl); - fprintf(tl->fc, "(%g * %g)", v, sc); + sbuf_printf(tl->fc, "(%g * %g)", v, sc); } /*--------------------------------------------------------------------*/ @@ -544,7 +546,7 @@ ExpectErr(tl, ID); I(tl); AddRef(tl, tl->t, R_ACL); - fprintf(tl->fc, "ip_match(%s, acl_%*.*s)\n", + sbuf_printf(tl->fc, "ip_match(%s, acl_%*.*s)\n", vp->cname, tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); @@ -553,13 +555,13 @@ case T_EQ: case T_NEQ: I(tl); - fprintf(tl->fc, "%s %*.*s ", + sbuf_printf(tl->fc, "%s %*.*s ", vp->cname, tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); u = IpVal(tl); - fprintf(tl->fc, "%uU /* %u.%u.%u.%u */\n", u, + sbuf_printf(tl->fc, "%uU /* %u.%u.%u.%u */\n", u, (u >> 24) & 0xff, (u >> 16) & 0xff, (u >> 8) & 0xff, (u) & 0xff); break; @@ -579,10 +581,10 @@ switch (tl->t->tok) { case '~': - I(tl); fprintf(tl->fc, "string_match(%s, ", vp->cname); + I(tl); sbuf_printf(tl->fc, "string_match(%s, ", vp->cname); NextToken(tl); ExpectErr(tl, CSTR); - fprintf(tl->fc, "%*.*s)\n", + sbuf_printf(tl->fc, "%*.*s)\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -602,7 +604,7 @@ { I(tl); - fprintf(tl->fc, "%s ", vp->cname); + sbuf_printf(tl->fc, "%s ", vp->cname); switch (tl->t->tok) { case T_EQ: case T_NEQ: @@ -610,7 +612,7 @@ case T_GEQ: case '>': case '<': - fprintf(tl->fc, "%*.*s ", + sbuf_printf(tl->fc, "%*.*s ", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -620,7 +622,7 @@ break; case INT: ExpectErr(tl, CNUM); - fprintf(tl->fc, "%*.*s ", + sbuf_printf(tl->fc, "%*.*s ", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -635,7 +637,7 @@ ErrWhere(tl, tl->t); return; } - fprintf(tl->fc, "\n"); + sbuf_printf(tl->fc, "\n"); break; default: sbuf_printf(tl->sb, "Illegal condition "); @@ -653,7 +655,7 @@ { I(tl); - fprintf(tl->fc, "%s\n", vp->cname); + sbuf_printf(tl->fc, "%s\n", vp->cname); } static void @@ -664,10 +666,10 @@ C(tl, ","); I(tl); if (tl->t->tok == '!') { - fprintf(tl->fc, "!"); + sbuf_printf(tl->fc, "!"); NextToken(tl); } - fprintf(tl->fc, "(\n"); + sbuf_printf(tl->fc, "(\n"); if (tl->t->tok == '(') { NextToken(tl); Cond_0(tl); @@ -704,35 +706,35 @@ return; } I(tl); - fprintf(tl->fc, ")\n"); + sbuf_printf(tl->fc, ")\n"); } static void Cond_1(struct tokenlist *tl) { - I(tl); fprintf(tl->fc, "(\n"); + I(tl); sbuf_printf(tl->fc, "(\n"); L(tl, Cond_2(tl)); while (tl->t->tok == T_CAND) { NextToken(tl); - I(tl); fprintf(tl->fc, ") && (\n"); + I(tl); sbuf_printf(tl->fc, ") && (\n"); L(tl, Cond_2(tl)); } - I(tl); fprintf(tl->fc, ")\n"); + I(tl); sbuf_printf(tl->fc, ")\n"); } static void Cond_0(struct tokenlist *tl) { - I(tl); fprintf(tl->fc, "(\n"); + I(tl); sbuf_printf(tl->fc, "(\n"); L(tl, Cond_1(tl)); while (tl->t->tok == T_COR) { NextToken(tl); - I(tl); fprintf(tl->fc, ") || (\n"); + I(tl); sbuf_printf(tl->fc, ") || (\n"); L(tl, Cond_1(tl)); } - I(tl); fprintf(tl->fc, ")\n"); + I(tl); sbuf_printf(tl->fc, ")\n"); } static void @@ -741,10 +743,10 @@ ExpectErr(tl, '('); NextToken(tl); - I(tl); fprintf(tl->fc, "(\n"); + I(tl); sbuf_printf(tl->fc, "(\n"); L(tl, Cond_0(tl)); ERRCHK(tl); - I(tl); fprintf(tl->fc, ")\n"); + I(tl); sbuf_printf(tl->fc, ")\n"); ExpectErr(tl, ')'); NextToken(tl); } @@ -756,7 +758,7 @@ { ExpectErr(tl, T_IF); - I(tl); fprintf(tl->fc, "if \n"); + I(tl); sbuf_printf(tl->fc, "if \n"); NextToken(tl); L(tl, Conditional(tl)); ERRCHK(tl); @@ -767,7 +769,7 @@ case T_ELSE: NextToken(tl); if (tl->t->tok != T_IF) { - I(tl); fprintf(tl->fc, "else \n"); + I(tl); sbuf_printf(tl->fc, "else \n"); L(tl, Compound(tl)); ERRCHK(tl); return; @@ -775,7 +777,7 @@ /* FALLTHROUGH */ case T_ELSEIF: case T_ELSIF: - I(tl); fprintf(tl->fc, "else if \n"); + I(tl); sbuf_printf(tl->fc, "else if \n"); NextToken(tl); L(tl, Conditional(tl)); ERRCHK(tl); @@ -802,36 +804,36 @@ switch (at->tok) { case T_NO_NEW_CACHE: I(tl); - fprintf(tl->fc, "VCL_no_new_cache();\n"); + sbuf_printf(tl->fc, "VCL_no_new_cache();\n"); return; case T_NO_CACHE: I(tl); - fprintf(tl->fc, "VCL_no_cache();\n"); + sbuf_printf(tl->fc, "VCL_no_cache();\n"); return; case T_FINISH: I(tl); - fprintf(tl->fc, "return;\n"); + sbuf_printf(tl->fc, "return;\n"); return; case T_FETCH: I(tl); - fprintf(tl->fc, "VCL_fetch();\n"); + sbuf_printf(tl->fc, "VCL_fetch();\n"); return; case T_ERROR: a = UintVal(tl); I(tl); - fprintf(tl->fc, "VCL_error(%u, ", a); + sbuf_printf(tl->fc, "VCL_error(%u, ", a); if (tl->t->tok == CSTR) { - fprintf(tl->fc, "%*.*s);\n", + sbuf_printf(tl->fc, "%*.*s);\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); } else - fprintf(tl->fc, "(const char *)0);\n"); + sbuf_printf(tl->fc, "(const char *)0);\n"); return; case T_SWITCH_CONFIG: ExpectErr(tl, ID); I(tl); - fprintf(tl->fc, "VCL_switch_config(\"%*.*s\");\n", + sbuf_printf(tl->fc, "VCL_switch_config(\"%*.*s\");\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -840,7 +842,7 @@ ExpectErr(tl, ID); AddRef(tl, tl->t, R_FUNC); I(tl); - fprintf(tl->fc, "VCL_function_%*.*s(VCL_PASS_ARGS);\n", + sbuf_printf(tl->fc, "VCL_function_%*.*s(VCL_PASS_ARGS);\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); /* XXX: check if function finished request */ @@ -849,12 +851,12 @@ case T_REWRITE: ExpectErr(tl, CSTR); I(tl); - fprintf(tl->fc, "VCL_rewrite(%*.*s", + sbuf_printf(tl->fc, "VCL_rewrite(%*.*s", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); ExpectErr(tl, CSTR); - fprintf(tl->fc, ", %*.*s);\n", + sbuf_printf(tl->fc, ", %*.*s);\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -865,7 +867,7 @@ ERRCHK(tl); assert(vp != NULL); I(tl); - fprintf(tl->fc, "%s ", vp->cname); + sbuf_printf(tl->fc, "%s ", vp->cname); NextToken(tl); switch (vp->fmt) { case INT: @@ -873,13 +875,13 @@ case RATE: case TIME: case FLOAT: - fprintf(tl->fc, "%*.*s ", + sbuf_printf(tl->fc, "%*.*s ", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); a = tl->t->tok; NextToken(tl); if (a == T_MUL || a == T_DIV) - fprintf(tl->fc, "%g", DoubleVal(tl)); + sbuf_printf(tl->fc, "%g", DoubleVal(tl)); else if (vp->fmt == TIME) TimeVal(tl); else if (vp->fmt == SIZE) @@ -887,14 +889,14 @@ else if (vp->fmt == RATE) RateVal(tl); else - fprintf(tl->fc, "%g", DoubleVal(tl)); - fprintf(tl->fc, ";\n"); + sbuf_printf(tl->fc, "%g", DoubleVal(tl)); + sbuf_printf(tl->fc, ";\n"); break; case IP: if (tl->t->tok == '=') { NextToken(tl); u = IpVal(tl); - fprintf(tl->fc, "= %uU; /* %u.%u.%u.%u */\n", + sbuf_printf(tl->fc, "= %uU; /* %u.%u.%u.%u */\n", u, (u >> 24) & 0xff, (u >> 16) & 0xff, @@ -911,7 +913,7 @@ case BACKEND: if (tl->t->tok == '=') { NextToken(tl); - fprintf(tl->fc, "= &VCL_backend_%*.*s;\n", + sbuf_printf(tl->fc, "= &VCL_backend_%*.*s;\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -948,11 +950,11 @@ ExpectErr(tl, ID); AddDef(tl, tl->t, R_ACL); - fprintf(tl->fh, "static struct vcl_acl acl_%*.*s[];\n", + sbuf_printf(tl->fh, "static struct vcl_acl acl_%*.*s[];\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); I(tl); - fprintf(tl->fc, "static struct vcl_acl acl_%*.*s[] = {\n", + sbuf_printf(tl->fc, "static struct vcl_acl acl_%*.*s[] = {\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); @@ -973,19 +975,19 @@ ExpectErr(tl, ';'); NextToken(tl); I(tl); - fprintf(tl->fc, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n", + sbuf_printf(tl->fc, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n", u, m, (u >> 24) & 0xff, (u >> 16) & 0xff, (u >> 8) & 0xff, (u) & 0xff, m); } ExpectErr(tl, '}'); I(tl); - fprintf(tl->fc, "{ %11uU, %3uU }\n", 0, 0); + sbuf_printf(tl->fc, "{ %11uU, %3uU }\n", 0, 0); tl->indent -= INDENT; I(tl); - fprintf(tl->fc, "};\n\n"); + sbuf_printf(tl->fc, "};\n\n"); NextToken(tl); } @@ -996,7 +998,7 @@ { ExpectErr(tl, '{'); - I(tl); fprintf(tl->fc, "{\n"); + I(tl); sbuf_printf(tl->fc, "{\n"); tl->indent += INDENT; C(tl, ";"); NextToken(tl); @@ -1012,7 +1014,7 @@ case '}': NextToken(tl); tl->indent -= INDENT; - I(tl); fprintf(tl->fc, "}\n"); + I(tl); sbuf_printf(tl->fc, "}\n"); return; case EOI: sbuf_printf(tl->sb, @@ -1039,20 +1041,21 @@ ExpectErr(tl, ID); AddDef(tl, tl->t, R_BACKEND); I(tl); - fprintf(tl->fh, "static struct backend VCL_backend_%*.*s;\n", + sbuf_printf(tl->fh, "static struct backend VCL_backend_%*.*s;\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); - fprintf(tl->fc, "static struct backend VCL_backend_%*.*s;\n", + sbuf_printf(tl->fc, "static struct backend VCL_backend_%*.*s;\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); - fprintf(tl->fc, "static void\n"); + sbuf_printf(tl->fc, "static void\n"); I(tl); - fprintf(tl->fc, "VCL_init_backend_%*.*s (struct backend *backend)\n", + sbuf_printf(tl->fc, + "VCL_init_backend_%*.*s (struct backend *backend)\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); L(tl, Compound(tl)); - fprintf(tl->fc, "\n"); + sbuf_printf(tl->fc, "\n"); } /*--------------------------------------------------------------------*/ @@ -1064,18 +1067,18 @@ NextToken(tl); ExpectErr(tl, ID); AddDef(tl, tl->t, R_FUNC); - fprintf(tl->fh, "static void VCL_function_%*.*s (VCL_FARGS);\n", + sbuf_printf(tl->fh, "static void VCL_function_%*.*s (VCL_FARGS);\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); I(tl); - fprintf(tl->fc, "static void\n"); + sbuf_printf(tl->fc, "static void\n"); I(tl); - fprintf(tl->fc, "VCL_function_%*.*s (VCL_FARGS)\n", + sbuf_printf(tl->fc, "VCL_function_%*.*s (VCL_FARGS)\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); NextToken(tl); L(tl, Compound(tl)); - fprintf(tl->fc, "\n"); + sbuf_printf(tl->fc, "\n"); } /*-------------------------------------------------------------------- @@ -1130,6 +1133,8 @@ t->e = e; TAILQ_INSERT_TAIL(&tl->tokens, t, list); tl->t = t; + if (0) + fprintf(stderr, "+ %s\n", vcl_tnames[tok]); } /*-------------------------------------------------------------------- @@ -1170,7 +1175,7 @@ } /* Match for the fixed tokens (see token.tcl) */ - u = fixed_token(p, &q); + u = vcl_fixed_token(p, &q); if (u != 0) { AddToken(tl, u, p, q); p = q; @@ -1278,8 +1283,12 @@ unsigned lin, pos; const char *p; - fprintf(tl->fh, "static struct vcl_ref VCL_ref[%u];\n", tl->cnt + 1); - fprintf(tl->fc, "static struct vcl_ref VCL_ref[%u] = {\n", tl->cnt + 1); + sbuf_printf(tl->fh, + "#define VCL_NREFS %u\n", tl->cnt + 1); + sbuf_printf(tl->fh, + "static struct vcl_ref VCL_ref[VCL_NREFS];\n"); + sbuf_printf(tl->fc, + "static struct vcl_ref VCL_ref[VCL_NREFS] = {\n"); lin = 1; pos = 0; p = tl->b; @@ -1297,51 +1306,137 @@ pos++; } - fprintf(tl->fc, + sbuf_printf(tl->fc, "%*.*s[%3u] = { %4u, %3u, 0, \"%*.*s\" },\n", INDENT, INDENT, "", t->cnt, lin, pos + 1, t->e - t->b, t->e - t->b, t->b); } - fprintf(tl->fc, "};\n"); + sbuf_printf(tl->fc, "};\n"); } /*--------------------------------------------------------------------*/ static void -Compile(struct sbuf *sb, const char *b, const char *e) +EmitInitFunc(struct tokenlist *tl) { + struct ref *r; + + sbuf_printf(tl->fc, + "\nstatic void\n" + "VCL_Init(void)\n" + "{\n\n"); + + TAILQ_FOREACH(r, &tl->refs, list) { + switch(r->type) { + case R_FUNC: + break; + case R_ACL: + break; + case R_BACKEND: + sbuf_printf(tl->fc, + "\tVCL_init_backend_%*.*s(&VCL_backend_%*.*s);\n", + r->name->e - r->name->b, + r->name->e - r->name->b, r->name->b, + r->name->e - r->name->b, + r->name->e - r->name->b, r->name->b); + break; + } + } + sbuf_printf(tl->fc, "}\n"); +} + +/*--------------------------------------------------------------------*/ + +static void +EmitStruct(struct tokenlist *tl) +{ + + sbuf_printf(tl->fc, "\nstruct VCL_conf VCL_conf = {\n"); + sbuf_printf(tl->fc, + "\t.magic = VCL_CONF_MAGIC,\n"); + sbuf_printf(tl->fc, + "\t.init_func = VCL_Init,\n"); + sbuf_printf(tl->fc, + "\t.default_backend = &VCL_backend_default,\n"); + sbuf_printf(tl->fc, + "\t.ref = VCL_ref,\n"); + sbuf_printf(tl->fc, + "\t.nref = VCL_NREFS,\n"); + sbuf_printf(tl->fc, "};\n"); +} + +/*--------------------------------------------------------------------*/ + +void +VCL_Compile(struct sbuf *sb, const char *b, const char *e) +{ struct tokenlist tokens; + FILE *fo; memset(&tokens, 0, sizeof tokens); TAILQ_INIT(&tokens.tokens); TAILQ_INIT(&tokens.refs); tokens.sb = sb; - tokens.fc = fopen("_.c", "w"); + tokens.fc = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); assert(tokens.fc != NULL); - tokens.fh = fopen("_.h", "w"); + tokens.fh = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); assert(tokens.fh != NULL); - fprintf(tokens.fc, "#include \"vcl_lang.h\"\n"); - fprintf(tokens.fc, "#include \"_.h\"\n"); tokens.b = b; + if (e == NULL) + e = strchr(b, '\0'); + assert(e != NULL); tokens.e = e; Lexer(&tokens, b, e); ERRCHK(&tokens); tokens.t = TAILQ_FIRST(&tokens.tokens); Parse(&tokens); ERRCHK(&tokens); +if (0) CheckRefs(&tokens); ERRCHK(&tokens); LocTable(&tokens); + + EmitInitFunc(&tokens); + + EmitStruct(&tokens); + + fo = popen( + "tee /tmp/_.c |" + "cc -fpic -shared -Wl,-x -o /tmp/_.so.1 -x c - ", "w"); + + vcl_output_lang_h(fo); + + fprintf(fo, "/* FH */\n"); + sbuf_finish(tokens.fh); + fputs(sbuf_data(tokens.fh), fo); + + fprintf(fo, "/* FC */\n"); + sbuf_finish(tokens.fc); + fputs(sbuf_data(tokens.fc), fo); + pclose(fo); } /*--------------------------------------------------------------------*/ +void +VCL_InitCompile(void) +{ + struct var *v; + + vcl_init_tnames(); + for (v = vars; v->name != NULL; v++) + v->len = strlen(v->name); +} + +#if 0 +/*--------------------------------------------------------------------*/ + #include #define MYSPACE (128 * 1024) @@ -1381,3 +1476,4 @@ printf("<%s>\n", sbuf_data(sb)); return (0); } +#endif Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-27 11:21:18 UTC (rev 74) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-27 11:21:58 UTC (rev 75) @@ -3,10 +3,12 @@ * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand */ +#include +#include #include "vcl_priv.h" unsigned -fixed_token(const char *p, const char **q) +vcl_fixed_token(const char *p, const char **q) { switch (p[0]) { @@ -305,65 +307,144 @@ } } -const char *tnames[256]; +const char *vcl_tnames[256]; void -init_tnames(void) +vcl_init_tnames(void) { - tnames['!'] = "'!'"; - tnames['%'] = "'%'"; - tnames['&'] = "'&'"; - tnames['('] = "'('"; - tnames[')'] = "')'"; - tnames['*'] = "'*'"; - tnames['+'] = "'+'"; - tnames[','] = "','"; - tnames['-'] = "'-'"; - tnames['.'] = "'.'"; - tnames['/'] = "'/'"; - tnames['<'] = "'<'"; - tnames['='] = "'='"; - tnames['>'] = "'>'"; - tnames['{'] = "'{'"; - tnames['}'] = "'}'"; - tnames['|'] = "'|'"; - tnames['~'] = "'~'"; - tnames[';'] = "';'"; - tnames[CNUM] = "CNUM"; - tnames[CSTR] = "CSTR"; - tnames[EOI] = "EOI"; - tnames[ID] = "ID"; - tnames[T_ACL] = "acl"; - tnames[T_BACKEND] = "backend"; - tnames[T_CALL] = "call"; - tnames[T_CAND] = "&&"; - tnames[T_COR] = "||"; - tnames[T_DEC] = "--"; - tnames[T_DECR] = "/="; - tnames[T_DIV] = "/="; - tnames[T_ELSE] = "else"; - tnames[T_ELSEIF] = "elseif"; - tnames[T_ELSIF] = "elsif"; - tnames[T_EQ] = "=="; - tnames[T_ERROR] = "error"; - tnames[T_FETCH] = "fetch"; - tnames[T_FINISH] = "finish"; - tnames[T_FUNC] = "func"; - tnames[T_GEQ] = ">="; - tnames[T_IF] = "if"; - tnames[T_INC] = "++"; - tnames[T_INCR] = "+="; - tnames[T_LEQ] = "<="; - tnames[T_MUL] = "*="; - tnames[T_NEQ] = "!="; - tnames[T_NO_CACHE] = "no_cache"; - tnames[T_NO_NEW_CACHE] = "no_new_cache"; - tnames[T_PROC] = "proc"; - tnames[T_REWRITE] = "rewrite"; - tnames[T_SET] = "set"; - tnames[T_SHL] = "<<"; - tnames[T_SHR] = ">>"; - tnames[T_SUB] = "sub"; - tnames[T_SWITCH_CONFIG] = "switch_config"; - tnames[VAR] = "VAR"; + vcl_tnames['!'] = "'!'"; + vcl_tnames['%'] = "'%'"; + vcl_tnames['&'] = "'&'"; + vcl_tnames['('] = "'('"; + vcl_tnames[')'] = "')'"; + vcl_tnames['*'] = "'*'"; + vcl_tnames['+'] = "'+'"; + vcl_tnames[','] = "','"; + vcl_tnames['-'] = "'-'"; + vcl_tnames['.'] = "'.'"; + vcl_tnames['/'] = "'/'"; + vcl_tnames['<'] = "'<'"; + vcl_tnames['='] = "'='"; + vcl_tnames['>'] = "'>'"; + vcl_tnames['{'] = "'{'"; + vcl_tnames['}'] = "'}'"; + vcl_tnames['|'] = "'|'"; + vcl_tnames['~'] = "'~'"; + vcl_tnames[';'] = "';'"; + vcl_tnames[CNUM] = "CNUM"; + vcl_tnames[CSTR] = "CSTR"; + vcl_tnames[EOI] = "EOI"; + vcl_tnames[ID] = "ID"; + vcl_tnames[T_ACL] = "acl"; + vcl_tnames[T_BACKEND] = "backend"; + vcl_tnames[T_CALL] = "call"; + vcl_tnames[T_CAND] = "&&"; + vcl_tnames[T_COR] = "||"; + vcl_tnames[T_DEC] = "--"; + vcl_tnames[T_DECR] = "/="; + vcl_tnames[T_DIV] = "/="; + vcl_tnames[T_ELSE] = "else"; + vcl_tnames[T_ELSEIF] = "elseif"; + vcl_tnames[T_ELSIF] = "elsif"; + vcl_tnames[T_EQ] = "=="; + vcl_tnames[T_ERROR] = "error"; + vcl_tnames[T_FETCH] = "fetch"; + vcl_tnames[T_FINISH] = "finish"; + vcl_tnames[T_FUNC] = "func"; + vcl_tnames[T_GEQ] = ">="; + vcl_tnames[T_IF] = "if"; + vcl_tnames[T_INC] = "++"; + vcl_tnames[T_INCR] = "+="; + vcl_tnames[T_LEQ] = "<="; + vcl_tnames[T_MUL] = "*="; + vcl_tnames[T_NEQ] = "!="; + vcl_tnames[T_NO_CACHE] = "no_cache"; + vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache"; + vcl_tnames[T_PROC] = "proc"; + vcl_tnames[T_REWRITE] = "rewrite"; + vcl_tnames[T_SET] = "set"; + vcl_tnames[T_SHL] = "<<"; + vcl_tnames[T_SHR] = ">>"; + vcl_tnames[T_SUB] = "sub"; + vcl_tnames[T_SWITCH_CONFIG] = "switch_config"; + vcl_tnames[VAR] = "VAR"; } + +void +vcl_output_lang_h(FILE *f) +{ + fputs("/*\n", f); + fputs(" * Stuff necessary to compile a VCL programs C code\n", f); + fputs(" *\n", f); + fputs(" * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl\n", f); + fputs(" * XXX: *MUST* be rerun.\n", f); + fputs(" */\n", f); + fputs("\n", f); + fputs("\n", f); + fputs("struct vcl_ref {\n", f); + fputs(" unsigned line;\n", f); + fputs(" unsigned pos;\n", f); + fputs(" unsigned count;\n", f); + fputs(" const char *token;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("struct vcl_acl {\n", f); + fputs(" unsigned ip;\n", f); + fputs(" unsigned mask;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("struct client {\n", f); + fputs(" unsigned ip;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("struct req {\n", f); + fputs(" char *req;\n", f); + fputs(" char *useragent;\n", f); + fputs(" struct {\n", f); + fputs(" char *path;\n", f); + fputs(" char *host;\n", f); + fputs(" } url;\n", f); + fputs(" double ttlfactor;\n", f); + fputs(" struct backend *backend;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("struct backend {\n", f); + fputs(" unsigned ip;\n", f); + fputs(" double responsetime;\n", f); + fputs(" double timeout;\n", f); + fputs(" double bandwidth;\n", f); + fputs(" int down;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("struct obj {\n", f); + fputs(" int exists;\n", f); + fputs(" double ttl;\n", f); + fputs(" unsigned result;\n", f); + fputs(" unsigned size;\n", f); + fputs(" unsigned usage;\n", f); + fputs("};\n", f); + fputs("\n", f); + fputs("#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend\n", f); + fputs("#define VCL_PASS_ARGS client, obj, req, backend\n", f); + fputs("\n", f); + fputs("void VCL_count(unsigned);\n", f); + fputs("void VCL_no_cache();\n", f); + fputs("void VCL_no_new_cache();\n", f); + fputs("int ip_match(unsigned, struct vcl_acl *);\n", f); + fputs("int string_match(const char *, const char *);\n", f); + fputs("int VCL_rewrite(const char *, const char *);\n", f); + fputs("int VCL_error(unsigned, const char *);\n", f); + fputs("int VCL_fetch(void);\n", f); + fputs("int VCL_switch_config(const char *);\n", f); + fputs("\n", f); + fputs("typedef void vcl_init_f(void);\n", f); + fputs("\n", f); + fputs("struct VCL_conf {\n", f); + fputs(" unsigned magic;\n", f); + fputs("#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n", f); + fputs(" vcl_init_f *init_func;\n", f); + fputs(" struct backend *default_backend;\n", f); + fputs(" struct vcl_ref *ref;\n", f); + fputs(" unsigned nref;\n", f); + fputs("};\n", f); +} Modified: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-27 11:21:18 UTC (rev 74) +++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-27 11:21:58 UTC (rev 75) @@ -59,6 +59,8 @@ */ } +puts $fo "#include " +puts $fo "#include " puts $fo "#include \"vcl_priv.h\"" set tn 128 @@ -103,7 +105,7 @@ puts $fo { unsigned -fixed_token(const char *p, const char **q)} +vcl_fixed_token(const char *p, const char **q)} puts $fo "{" puts $fo "" puts $fo " switch (p\[0\]) {" @@ -158,17 +160,29 @@ puts $fo "}" puts $fo "" -puts $fo "const char *tnames\[256\];\n" +puts $fo "const char *vcl_tnames\[256\];\n" puts $fo "void" -puts $fo "init_tnames(void)" +puts $fo "vcl_init_tnames(void)" puts $fo "{" foreach i $token2 { - puts $fo "\ttnames\[[lindex $i 0]\] = \"[lindex $i 0]\";" + puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";" } foreach i $tokens { - puts $fo "\ttnames\[[lindex $i 0]\] = \"[lindex $i 1]\";" + puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";" } puts $fo "}" +set fi [open "../../include/vcl_lang.h"] + +puts $fo "" +puts $fo "void" +puts $fo "vcl_output_lang_h(FILE *f)" +puts $fo "{" +while {[gets $fi a] >= 0} { + puts $fo "\tfputs(\"$a\\n\", f);" +} +puts $fo "}" +close $fi + close $foh close $fo Deleted: trunk/varnish-cache/lib/libvcl/vcl_lang.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_lang.h 2006-03-27 11:21:18 UTC (rev 74) +++ trunk/varnish-cache/lib/libvcl/vcl_lang.h 2006-03-27 11:21:58 UTC (rev 75) @@ -1,62 +0,0 @@ -/* - * Stuff necessary to compile a VCL programs C code - */ - - -struct vcl_ref { - unsigned line; - unsigned pos; - unsigned count; - const char *token; -}; - -struct vcl_acl { - unsigned ip; - unsigned mask; -}; - -struct client { - unsigned ip; -}; - -struct req { - char *req; - char *useragent; - struct { - char *path; - char *host; - } url; - double ttlfactor; - struct backend *backend; -}; - -struct backend { - unsigned ip; - double responsetime; - double timeout; - double bandwidth; - int down; -}; - -struct obj { - int exists; - double ttl; - unsigned result; - unsigned size; - unsigned usage; -}; - -#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend -#define VCL_PASS_ARGS client, obj, req, backend - -void VCL_count(unsigned); -void VCL_no_cache(); -void VCL_no_new_cache(); -int ip_match(unsigned, struct vcl_acl *); -int string_match(const char *, const char *); -int VCL_rewrite(const char *, const char *); -int VCL_error(unsigned, const char *); -int VCL_fetch(void); -int VCL_switch_config(const char *); - - Modified: trunk/varnish-cache/lib/libvcl/vcl_priv.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-03-27 11:21:18 UTC (rev 74) +++ trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-03-27 11:21:58 UTC (rev 75) @@ -3,10 +3,11 @@ */ #include "vcl_token_defs.h" -#include #define isident1(c) (isalpha(c)) #define isident(c) (isalpha(c) || isdigit(c) || (c) == '_') #define isvar(c) (isident(c) || (c) == '.') -unsigned fixed_token(const char *p, const char **q); -extern const char *tnames[256]; +unsigned vcl_fixed_token(const char *p, const char **q); +extern const char *vcl_tnames[256]; +void vcl_init_tnames(void); +void vcl_output_lang_h(FILE *f); From phk at projects.linpro.no Mon Mar 27 11:22:29 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 13:22:29 +0200 (CEST) Subject: r76 - trunk/varnish-cache/bin/varnishd Message-ID: <20060327112229.79F471ED5A2@projects.linpro.no> Author: phk Date: 2006-03-27 13:22:29 +0200 (Mon, 27 Mar 2006) New Revision: 76 Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: Experimentally pull in VCL program Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-27 11:21:58 UTC (rev 75) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-27 11:22:29 UTC (rev 76) @@ -14,8 +14,11 @@ tcp.c \ varnishd.c +varnishd_LDFLAGS = -export-dynamic + varnishd_LDADD = \ $(top_builddir)/lib/libvarnish/libvarnish.la \ $(top_builddir)/lib/libsbuf/libsbuf.la \ + $(top_builddir)/lib/libvcl/libvcl.la \ $(top_builddir)/contrib/libevent/libevent.la \ -lpthread Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-27 11:21:58 UTC (rev 75) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-27 11:22:29 UTC (rev 76) @@ -37,7 +37,6 @@ const char *p; int i; - printf("%s(%d, %d, ...)\n", __func__, fd, event); assert(VCA_RXBUFSIZE - sp->rcv_len > 0); i = read(fd, sp->rcv + sp->rcv_len, VCA_RXBUFSIZE - sp->rcv_len); if (i <= 0) { @@ -67,6 +66,9 @@ sp->hdr_e = p; event_del(sp->rd_e); HttpdAnalyze(sp); + + /* XXX: for now, pass everything */ + sp->handling = HND_Pass; } static void Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 11:21:58 UTC (rev 75) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 11:22:29 UTC (rev 76) @@ -23,6 +23,7 @@ #include #include #include +#include #include "mgt.h" #include "heritage.h" @@ -204,7 +205,15 @@ /* for development purposes */ #include +#include +#include + +void +VCL_count(unsigned u) +{ +} + int main(int argc, char *argv[]) { @@ -213,7 +222,31 @@ unsigned dflag = 1; /* XXX: debug=on for now */ register_printf_render_std((const unsigned char *)"HVQ"); + + { + struct sbuf *sb; + VCL_InitCompile(); + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + VCL_Compile(sb, + "backend default { set backend.ip = 10.0.0.1; } ", + NULL); + sbuf_finish(sb); + fprintf(stderr, "Result: %s\n", sbuf_data(sb)); + + { + void *dlhandle; + + dlhandle = dlopen("/tmp/_.so.1", + RTLD_NOW | RTLD_LOCAL ); + if (dlhandle == NULL) + err(1, "dlopen %s", dlerror()); + + } + exit (0); + } + while ((o = getopt(argc, argv, "dp:")) != -1) switch (o) { case 'd': From phk at projects.linpro.no Mon Mar 27 11:51:31 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 13:51:31 +0200 (CEST) Subject: r77 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327115131.E235F1ED5EA@projects.linpro.no> Author: phk Date: 2006-03-27 13:51:31 +0200 (Mon, 27 Mar 2006) New Revision: 77 Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c Log: edge closer towards being a nice member of society Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 11:22:29 UTC (rev 76) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 11:51:31 UTC (rev 77) @@ -1370,11 +1370,15 @@ /*--------------------------------------------------------------------*/ -void +char * VCL_Compile(struct sbuf *sb, const char *b, const char *e) { - struct tokenlist tokens; + struct tokenlist tokens; + struct ref *r; + struct token *t; FILE *fo; + char *of = NULL; + char buf[BUFSIZ]; memset(&tokens, 0, sizeof tokens); TAILQ_INIT(&tokens.tokens); @@ -1393,33 +1397,60 @@ assert(e != NULL); tokens.e = e; Lexer(&tokens, b, e); - ERRCHK(&tokens); + if (tokens.err) + goto done; tokens.t = TAILQ_FIRST(&tokens.tokens); Parse(&tokens); - ERRCHK(&tokens); + if (tokens.err) + goto done; if (0) CheckRefs(&tokens); - ERRCHK(&tokens); + if (tokens.err) + goto done; LocTable(&tokens); EmitInitFunc(&tokens); EmitStruct(&tokens); - fo = popen( + of = strdup("/tmp/vcl.XXXXXXXX"); + assert(of != NULL); + mktemp(of); + + sprintf(buf, "tee /tmp/_.c |" - "cc -fpic -shared -Wl,-x -o /tmp/_.so.1 -x c - ", "w"); + "cc -fpic -shared -Wl,-x -o %s -x c - ", of); + fo = popen(buf, "w"); + assert(fo != NULL); + vcl_output_lang_h(fo); - fprintf(fo, "/* FH */\n"); sbuf_finish(tokens.fh); fputs(sbuf_data(tokens.fh), fo); + sbuf_delete(tokens.fh); - fprintf(fo, "/* FC */\n"); sbuf_finish(tokens.fc); fputs(sbuf_data(tokens.fc), fo); + sbuf_delete(tokens.fc); + pclose(fo); +done: + + /* Free References */ + while (!TAILQ_EMPTY(&tokens.refs)) { + r = TAILQ_FIRST(&tokens.refs); + TAILQ_REMOVE(&tokens.refs, r, list); + free(r); + } + + /* Free Tokens */ + while (!TAILQ_EMPTY(&tokens.tokens)) { + t = TAILQ_FIRST(&tokens.tokens); + TAILQ_REMOVE(&tokens.tokens, t, list); + free(t); + } + return (of); } /*--------------------------------------------------------------------*/ From phk at projects.linpro.no Mon Mar 27 12:27:16 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 14:27:16 +0200 (CEST) Subject: r78 - trunk/varnish-cache/bin/varnishd Message-ID: <20060327122716.571CD1ED5EE@projects.linpro.no> Author: phk Date: 2006-03-27 14:27:16 +0200 (Mon, 27 Mar 2006) New Revision: 78 Added: trunk/varnish-cache/bin/varnishd/cache_vcl.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/varnishd.c Log: Build default VCL from "-b backend_IP" option and pass it to client via heritage. Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-27 12:27:16 UTC (rev 78) @@ -9,6 +9,7 @@ cache_httpd.c \ cache_main.c \ cache_shmlog.c \ + cache_vcl.c \ cli_event.c \ mgt_child.c \ tcp.c \ Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-27 12:27:16 UTC (rev 78) @@ -49,4 +49,5 @@ void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...); #endif - +/* cache_vcl.c */ +int CVCL_Load(const char *fn, const char *name); Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-27 12:27:16 UTC (rev 78) @@ -22,6 +22,7 @@ #include "cli_event.h" static struct event ev_keepalive; +static pthread_t vca_thread; /*--------------------------------------------------------------------*/ @@ -81,7 +82,7 @@ { NULL } }; -static pthread_t vca_thread; +/*--------------------------------------------------------------------*/ void child_main(void) @@ -101,6 +102,7 @@ eb = event_init(); assert(eb != NULL); + CVCL_Load(heritage.vcl_file, "boot"); cli = cli_setup(heritage.fds[2], heritage.fds[1], 0, cli_proto); evtimer_set(&ev_keepalive, timer_keepalive, NULL); Added: trunk/varnish-cache/bin/varnishd/cache_vcl.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-27 12:27:16 UTC (rev 78) @@ -0,0 +1,33 @@ +/* + * $Id$ + */ + +#include +#include + +#include "vcl_lang.h" +#include "cache.h" + +int +CVCL_Load(const char *fn, const char *name) +{ + void *dlh; + struct VCL_conf *vc; + + dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL); + if (dlh == NULL) { + fprintf(stderr, "dlopen(%s): %s\n", fn, dlerror()); + return (1); + } + vc = dlsym(dlh, "VCL_conf"); + if (vc == NULL) { + fprintf(stderr, "No VCL_conf symbol\n"); + return (1); + } + if (vc->magic != VCL_CONF_MAGIC) { + fprintf(stderr, "Wrong VCL_CONF_MAGIC\n"); + return (1); + } + fprintf(stderr, "Loaded \"%s\" as \"%s\"\n", fn , name); + return (0); +} Modified: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2006-03-27 12:27:16 UTC (rev 78) @@ -24,6 +24,9 @@ /* Share memory log fd and size (incl header) */ int vsl_fd; unsigned vsl_size; + + /* Initial VCL file */ + char *vcl_file; }; extern struct heritage heritage; Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 11:51:31 UTC (rev 77) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 12:27:16 UTC (rev 78) @@ -25,6 +25,8 @@ #include #include +#include "vcl_lang.h" + #include "mgt.h" #include "heritage.h" #include "cli_event.h" @@ -153,15 +155,15 @@ usage(void) { fprintf(stderr, "usage: varnishd [options]\n"); + fprintf(stderr, " %-20s # %s\n", "-b", "backend_IP_number"); fprintf(stderr, " %-20s # %s\n", "-d", "debug"); + fprintf(stderr, " %-20s # %s\n", "-f", "VCL_file"); fprintf(stderr, " %-20s # %s\n", "-p number", "TCP listen port"); #if 0 -c clusterid at cluster_controller - -f config_file -m memory_limit -s kind[,storage-options] -l logfile,logsize - -b backend ip... -u uid -a CLI_port #endif @@ -203,12 +205,67 @@ /*--------------------------------------------------------------------*/ +static char * +vcl_default(const char *bflag) +{ + char *buf, *vf; + struct sbuf *sb; + + buf = NULL; + asprintf(&buf, + "backend default { set backend.ip = %s; }", + bflag); + assert(buf != NULL); + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_Compile(sb, buf, NULL); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + fprintf(stderr, "%s", sbuf_data(sb)); + free(buf); + sbuf_delete(sb); + return (NULL); + } + sbuf_delete(sb); + free(buf); + return (vf); +} + +/*--------------------------------------------------------------------*/ + +static char * +vcl_file(const char *bflag) +{ + char *buf, *vf; + struct sbuf *sb; + + return (NULL); + buf = NULL; + asprintf(&buf, + "backend default { set backend.ip = %s; }", + bflag); + assert(buf != NULL); + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_Compile(sb, buf, NULL); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + fprintf(stderr, "%s", sbuf_data(sb)); + free(buf); + sbuf_delete(sb); + return (NULL); + } + sbuf_delete(sb); + free(buf); + return (vf); +} + +/*--------------------------------------------------------------------*/ + /* for development purposes */ #include #include -#include - void VCL_count(unsigned u) { @@ -220,38 +277,24 @@ int o; const char *portnumber = "8080"; unsigned dflag = 1; /* XXX: debug=on for now */ + const char *bflag = NULL; + const char *fflag = NULL; register_printf_render_std((const unsigned char *)"HVQ"); - { - struct sbuf *sb; - VCL_InitCompile(); - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - assert(sb != NULL); - VCL_Compile(sb, - "backend default { set backend.ip = 10.0.0.1; } ", - NULL); - sbuf_finish(sb); - fprintf(stderr, "Result: %s\n", sbuf_data(sb)); - { - void *dlhandle; - - dlhandle = dlopen("/tmp/_.so.1", - RTLD_NOW | RTLD_LOCAL ); - if (dlhandle == NULL) - err(1, "dlopen %s", dlerror()); - - } - exit (0); - } - - while ((o = getopt(argc, argv, "dp:")) != -1) + while ((o = getopt(argc, argv, "b:df:p:")) != -1) switch (o) { + case 'b': + bflag = optarg; + break; case 'd': dflag++; break; + case 'f': + fflag = optarg; + break; case 'p': portnumber = optarg; break; @@ -262,9 +305,27 @@ argc -= optind; argv += optind; - if (argc != 0) + if (argc != 0) { + fprintf(stderr, "Too many arguments\n"); usage(); + } + if (bflag != NULL && fflag != NULL) { + fprintf(stderr, "Only one of -b or -f can be specified\n"); + usage(); + } + if (bflag == NULL && fflag == NULL) { + fprintf(stderr, "One of -b or -f must be specified\n"); + usage(); + } + + if (bflag != NULL) + heritage.vcl_file = vcl_default(bflag); + else + heritage.vcl_file = vcl_file(fflag); + if (heritage.vcl_file == NULL) + exit (1); + /* * XXX: Lacking the suspend/resume facility (due to the socket API * missing an unlisten(2) facility) we may want to push this into From phk at projects.linpro.no Mon Mar 27 13:57:34 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 15:57:34 +0200 (CEST) Subject: r79 - trunk/varnish-cache/include Message-ID: <20060327135734.8D39E1ED5F1@projects.linpro.no> Author: phk Date: 2006-03-27 15:57:34 +0200 (Mon, 27 Mar 2006) New Revision: 79 Modified: trunk/varnish-cache/include/cli_priv.h Log: Add a macro which we can #ifdef Modified: trunk/varnish-cache/include/cli_priv.h =================================================================== --- trunk/varnish-cache/include/cli_priv.h 2006-03-27 12:27:16 UTC (rev 78) +++ trunk/varnish-cache/include/cli_priv.h 2006-03-27 13:57:34 UTC (rev 79) @@ -7,6 +7,8 @@ * */ +#define CLI_PRIV_H + struct cli; /* NB: struct cli is opaque at this level. */ typedef void cli_func_t(struct cli*, char **av, void *priv); From phk at projects.linpro.no Mon Mar 27 13:59:09 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 15:59:09 +0200 (CEST) Subject: r80 - trunk/varnish-cache/bin/varnishd Message-ID: <20060327135909.5EC1C1ED5F4@projects.linpro.no> Author: phk Date: 2006-03-27 15:59:09 +0200 (Mon, 27 Mar 2006) New Revision: 80 Modified: trunk/varnish-cache/bin/varnishd/mgt_child.c Log: Just return if there is nothing to wait for. We get SIGCHLD'ed on the popen child process. Modified: trunk/varnish-cache/bin/varnishd/mgt_child.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-27 13:57:34 UTC (rev 79) +++ trunk/varnish-cache/bin/varnishd/mgt_child.c 2006-03-27 13:59:09 UTC (rev 80) @@ -188,7 +188,7 @@ time(&t); mgt_child_request(child_pingpong_ccb, NULL, NULL, "ping %ld", t); if (1) { - tv.tv_sec = 3; + tv.tv_sec = 30; tv.tv_usec = 0; evtimer_del(&ev_child_pingpong); evtimer_add(&ev_child_pingpong, &tv); @@ -284,6 +284,8 @@ printf("sig_chld(%d, %d, %p)\n", a, b, c); p = wait4(-1, &status, WNOHANG, NULL); + if (p == 0) + return; printf("pid = %d status = 0x%x\n", p, status); assert(p == child_pid); From phk at projects.linpro.no Mon Mar 27 14:10:43 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 16:10:43 +0200 (CEST) Subject: r81 - trunk/varnish-cache/lib/libvcl Message-ID: <20060327141043.567371ED5F1@projects.linpro.no> Author: phk Date: 2006-03-27 16:10:43 +0200 (Mon, 27 Mar 2006) New Revision: 81 Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c Log: Add VCL_CompileFile() function. Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 13:59:09 UTC (rev 80) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 14:10:43 UTC (rev 81) @@ -36,9 +36,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include #include "vcl_priv.h" @@ -1455,56 +1459,38 @@ /*--------------------------------------------------------------------*/ -void -VCL_InitCompile(void) +char * +VCL_CompileFile(struct sbuf *sb, const char *fn) { - struct var *v; + char *f, *r; + int fd, i; + struct stat st; - vcl_init_tnames(); - for (v = vars; v->name != NULL; v++) - v->len = strlen(v->name); + fd = open(fn, O_RDONLY); + if (fd < 0) { + sbuf_printf(sb, "Cannot open file '%s': %s", + fn, strerror(errno)); + return (NULL); + } + assert(0 == fstat(fd, &st)); + f = malloc(st.st_size + 1); + assert(f != NULL); + i = read(fd, f, st.st_size); + assert(i == st.st_size); + f[i] = '\0'; + r = VCL_Compile(sb, f, NULL); + free(f); + return (r); } -#if 0 /*--------------------------------------------------------------------*/ -#include - -#define MYSPACE (128 * 1024) - -int -main(int argc, char **argv) +void +VCL_InitCompile(void) { - char *p; - size_t z; - FILE *fi; - struct sbuf *sb; - - setbuf(stdout, NULL); - { struct var *v; - for (v = vars; v->name != NULL; v++) { + vcl_init_tnames(); + for (v = vars; v->name != NULL; v++) v->len = strlen(v->name); - } - } - if (argc != 2) - err(1, "Usage: %s file", argv[0]); - fi = fopen(argv[1], "r"); - if (fi == NULL) - err(1, "Cannot open %s", argv[1]); - p = malloc(MYSPACE); - assert(p != NULL); - - z = fread(p, 1, MYSPACE - 1, fi); - if (z == 0) - err(1, "Nothing read from %s", argv[1]); - p[z] = '\0'; - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - Compile(sb, p, p + z); - sbuf_finish(sb); - if (sbuf_len(sb)) - printf("<%s>\n", sbuf_data(sb)); - return (0); } -#endif From phk at projects.linpro.no Mon Mar 27 14:11:22 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 16:11:22 +0200 (CEST) Subject: r82 - trunk/varnish-cache/include Message-ID: <20060327141122.32BCE1ED5F8@projects.linpro.no> Author: phk Date: 2006-03-27 16:11:22 +0200 (Mon, 27 Mar 2006) New Revision: 82 Added: trunk/varnish-cache/include/libvcl.h Log: Forgot to add this one. Prototypes for the VCL compiler. Added: trunk/varnish-cache/include/libvcl.h =================================================================== --- trunk/varnish-cache/include/libvcl.h 2006-03-27 14:10:43 UTC (rev 81) +++ trunk/varnish-cache/include/libvcl.h 2006-03-27 14:11:22 UTC (rev 82) @@ -0,0 +1,9 @@ +/* + * $Id$ + */ + +char *VCL_Compile(struct sbuf *sb, const char *b, const char *e); +char *VCL_CompileFile(struct sbuf *sb, const char *fn); +void VCL_InitCompile(void); + + From phk at projects.linpro.no Mon Mar 27 14:12:07 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Mon, 27 Mar 2006 16:12:07 +0200 (CEST) Subject: r83 - trunk/varnish-cache/bin/varnishd Message-ID: <20060327141207.8354B1ED5FA@projects.linpro.no> Author: phk Date: 2006-03-27 16:12:07 +0200 (Mon, 27 Mar 2006) New Revision: 83 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cache_vcl.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: Add config.load, config.inline and config.use commands. Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-27 14:11:22 UTC (rev 82) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-27 14:12:07 UTC (rev 83) @@ -51,3 +51,9 @@ /* cache_vcl.c */ int CVCL_Load(const char *fn, const char *name); +#ifdef CLI_PRIV_H +cli_func_t cli_func_config_list; +cli_func_t cli_func_config_load; +cli_func_t cli_func_config_unload; +cli_func_t cli_func_config_use; +#endif Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-27 14:11:22 UTC (rev 82) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-27 14:12:07 UTC (rev 83) @@ -78,6 +78,10 @@ static struct cli_proto cli_proto[] = { { CLI_URL_QUERY, cli_func_url_query }, + { CLI_CONFIG_LOAD, cli_func_config_load }, + { CLI_CONFIG_LIST, cli_func_config_list }, + { CLI_CONFIG_UNLOAD, cli_func_config_unload }, + { CLI_CONFIG_USE, cli_func_config_use }, { CLI_PING, cli_func_ping }, { NULL } }; Modified: trunk/varnish-cache/bin/varnishd/cache_vcl.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-27 14:11:22 UTC (rev 82) +++ trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-27 14:12:07 UTC (rev 83) @@ -3,31 +3,142 @@ */ #include +#include +#include +#include #include +#include +#include "cli.h" +#include "cli_priv.h" #include "vcl_lang.h" #include "cache.h" +struct vcls { + TAILQ_ENTRY(vcls) list; + const char *name; + void *dlh; + struct VCL_conf *conf; +}; + +static TAILQ_HEAD(, vcls) vcl_head = + TAILQ_HEAD_INITIALIZER(vcl_head); + +static struct vcls *active_vcl; + int CVCL_Load(const char *fn, const char *name) { - void *dlh; - struct VCL_conf *vc; + struct vcls *vcl; - dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL); - if (dlh == NULL) { + vcl = calloc(sizeof *vcl, 1); + assert(vcl != NULL); + + vcl->dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL); + if (vcl->dlh == NULL) { fprintf(stderr, "dlopen(%s): %s\n", fn, dlerror()); + free(vcl); return (1); } - vc = dlsym(dlh, "VCL_conf"); - if (vc == NULL) { + vcl->conf = dlsym(vcl->dlh, "VCL_conf"); + if (vcl->conf == NULL) { fprintf(stderr, "No VCL_conf symbol\n"); + dlclose(vcl->dlh); + free(vcl); return (1); } - if (vc->magic != VCL_CONF_MAGIC) { + if (vcl->conf->magic != VCL_CONF_MAGIC) { fprintf(stderr, "Wrong VCL_CONF_MAGIC\n"); + dlclose(vcl->dlh); + free(vcl); return (1); } + vcl->name = strdup(name); + assert(vcl->name != NULL); + TAILQ_INSERT_TAIL(&vcl_head, vcl, list); + if (active_vcl == NULL) + active_vcl = vcl; fprintf(stderr, "Loaded \"%s\" as \"%s\"\n", fn , name); return (0); } + +void +cli_func_config_list(struct cli *cli, char **av, void *priv) +{ + struct vcls *vcl; + + TAILQ_FOREACH(vcl, &vcl_head, list) { + cli_out(cli, "%s%s\n", + vcl == active_vcl ? "* " : " ", + vcl->name); + } +} + + +void +cli_func_config_load(struct cli *cli, char **av, void *priv) +{ + struct vcls *vcl; + + TAILQ_FOREACH(vcl, &vcl_head, list) { + if (!strcmp(vcl->name, av[2])) { + cli_out(cli, "Config '%s' already loaded", av[2]); + cli_result(cli, CLIS_PARAM); + return; + } + } + vcl = calloc(sizeof *vcl, 1); + assert(vcl != NULL); + + vcl->dlh = dlopen(av[3], RTLD_NOW | RTLD_LOCAL); + if (vcl->dlh == NULL) { + cli_out(cli, "dlopen(%s): %s\n", av[3], dlerror()); + cli_result(cli, CLIS_PARAM); + free(vcl); + return; + } + vcl->conf = dlsym(vcl->dlh, "VCL_conf"); + if (vcl->conf == NULL) { + cli_out(cli, "No VCL_conf symbol\n"); + cli_result(cli, CLIS_PARAM); + dlclose(vcl->dlh); + free(vcl); + return; + } + if (vcl->conf->magic != VCL_CONF_MAGIC) { + cli_out(cli, "Wrong VCL_CONF_MAGIC\n"); + cli_result(cli, CLIS_PARAM); + dlclose(vcl->dlh); + free(vcl); + return; + } + vcl->name = strdup(av[2]); + assert(vcl->name != NULL); + TAILQ_INSERT_TAIL(&vcl_head, vcl, list); + if (active_vcl == NULL) + active_vcl = vcl; + cli_out(cli, "Loaded \"%s\" from \"%s\"\n", vcl->name , av[3]); +} + +void +cli_func_config_unload(struct cli *cli, char **av, void *priv) +{ + cli_result(cli, CLIS_UNIMPL); +} + +void +cli_func_config_use(struct cli *cli, char **av, void *priv) +{ + struct vcls *vcl; + + TAILQ_FOREACH(vcl, &vcl_head, list) { + if (!strcmp(vcl->name, av[2])) + break; + } + if (vcl == NULL) { + cli_out(cli, "No config named '%s' loaded", av[2]); + cli_result(cli, CLIS_PARAM); + return; + } + active_vcl = vcl; +} Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 14:11:22 UTC (rev 82) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 14:12:07 UTC (rev 83) @@ -60,7 +60,97 @@ /*--------------------------------------------------------------------*/ +static char * +vcl_default(const char *bflag) +{ + char *buf, *vf; + struct sbuf *sb; + + buf = NULL; + asprintf(&buf, + "backend default { set backend.ip = %s; }", + bflag); + assert(buf != NULL); + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_Compile(sb, buf, NULL); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + fprintf(stderr, "%s", sbuf_data(sb)); + free(buf); + sbuf_delete(sb); + return (NULL); + } + sbuf_delete(sb); + free(buf); + return (vf); +} + static void +cli_func_config_inline(struct cli *cli, char **av, void *priv __unused) +{ + char *vf; + struct sbuf *sb; + + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_Compile(sb, av[3], NULL); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + cli_out(cli, "%s", sbuf_data(sb)); + sbuf_delete(sb); + return; + } + sbuf_delete(sb); + cli_suspend(cli); + mgt_child_request(cli_passthrough_cb, cli, NULL, + "config.load %s %s", av[2], vf); +} + +static void +cli_func_config_load(struct cli *cli, char **av, void *priv __unused) +{ + char *vf; + struct sbuf *sb; + + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_CompileFile(sb, av[3]); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + cli_out(cli, "%s", sbuf_data(sb)); + sbuf_delete(sb); + return; + } + sbuf_delete(sb); + cli_suspend(cli); + mgt_child_request(cli_passthrough_cb, cli, NULL, + "config.load %s %s", av[2], vf); +} + +static char * +vcl_file(const char *fflag) +{ + char *vf; + struct sbuf *sb; + + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + assert(sb != NULL); + vf = VCL_CompileFile(sb, fflag); + sbuf_finish(sb); + if (sbuf_len(sb) > 0) { + fprintf(stderr, "%s", sbuf_data(sb)); + sbuf_delete(sb); + return (NULL); + } + sbuf_delete(sb); + return (vf); +} + + +/*--------------------------------------------------------------------*/ + +static void cli_func_server_start(struct cli *cli, char **av __unused, void *priv __unused) { @@ -105,11 +195,11 @@ { CLI_URL_QUERY, cli_func_passthrough, NULL }, { CLI_URL_PURGE, cli_func_passthrough, NULL }, { CLI_URL_STATUS, cli_func_passthrough, NULL }, - { CLI_CONFIG_LOAD }, - { CLI_CONFIG_INLINE }, - { CLI_CONFIG_UNLOAD }, - { CLI_CONFIG_LIST }, - { CLI_CONFIG_USE }, + { CLI_CONFIG_LOAD, cli_func_config_load, NULL }, + { CLI_CONFIG_INLINE, cli_func_config_inline, NULL }, + { CLI_CONFIG_UNLOAD, cli_func_passthrough, NULL }, + { CLI_CONFIG_LIST, cli_func_passthrough, NULL }, + { CLI_CONFIG_USE, cli_func_passthrough, NULL }, { CLI_SERVER_FREEZE, cli_func_passthrough, NULL }, { CLI_SERVER_THAW, cli_func_passthrough, NULL }, { CLI_SERVER_SUSPEND, cli_func_passthrough, NULL }, @@ -202,66 +292,8 @@ AZ(ftruncate(heritage.vsl_fd, sizeof slh + size)); heritage.vsl_size = slh.size + slh.start; } - /*--------------------------------------------------------------------*/ -static char * -vcl_default(const char *bflag) -{ - char *buf, *vf; - struct sbuf *sb; - - buf = NULL; - asprintf(&buf, - "backend default { set backend.ip = %s; }", - bflag); - assert(buf != NULL); - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - assert(sb != NULL); - vf = VCL_Compile(sb, buf, NULL); - sbuf_finish(sb); - if (sbuf_len(sb) > 0) { - fprintf(stderr, "%s", sbuf_data(sb)); - free(buf); - sbuf_delete(sb); - return (NULL); - } - sbuf_delete(sb); - free(buf); - return (vf); -} - -/*--------------------------------------------------------------------*/ - -static char * -vcl_file(const char *bflag) -{ - char *buf, *vf; - struct sbuf *sb; - - return (NULL); - buf = NULL; - asprintf(&buf, - "backend default { set backend.ip = %s; }", - bflag); - assert(buf != NULL); - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - assert(sb != NULL); - vf = VCL_Compile(sb, buf, NULL); - sbuf_finish(sb); - if (sbuf_len(sb) > 0) { - fprintf(stderr, "%s", sbuf_data(sb)); - free(buf); - sbuf_delete(sb); - return (NULL); - } - sbuf_delete(sb); - free(buf); - return (vf); -} - -/*--------------------------------------------------------------------*/ - /* for development purposes */ #include #include From phk at projects.linpro.no Thu Mar 30 07:05:10 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 30 Mar 2006 09:05:10 +0200 (CEST) Subject: r84 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20060330070510.ECE411ED5E6@projects.linpro.no> Author: phk Date: 2006-03-30 09:05:10 +0200 (Thu, 30 Mar 2006) New Revision: 84 Added: trunk/varnish-cache/bin/varnishd/cache_pool.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/cache_httpd.c trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cache_vcl.c trunk/varnish-cache/bin/varnishd/varnishd.c trunk/varnish-cache/include/vcl_lang.h trunk/varnish-cache/lib/libvcl/vcl_compile.c trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcl_token_defs.h Log: Integrate the VCL code closer in the cache process: The passed argument will be the session structure. Add the pool of worker threads (cache_pool). With a unitary nature of the VCL code, the HTTP parsing can be postponed to the worker thread. This actually helps us with CPU cache locality as it will reduce the amount of memory allocated on one CPU but freed on another. Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-30 07:05:10 UTC (rev 84) @@ -8,6 +8,7 @@ cache_acceptor.c \ cache_httpd.c \ cache_main.c \ + cache_pool.c \ cache_shmlog.c \ cache_vcl.c \ cli_event.c \ Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-30 07:05:10 UTC (rev 84) @@ -2,46 +2,16 @@ * $Id$ */ -#define VCA_RXBUFSIZE 1024 -#define VCA_ADDRBUFSIZE 32 - -struct sess { - int fd; - - /* formatted ascii client address */ - char addr[VCA_ADDRBUFSIZE]; - - /* Receive buffer for HTTP header */ - char rcv[VCA_RXBUFSIZE + 1]; - unsigned rcv_len; - - /* HTTP request info, points into rcv */ - const char *req_b; - const char *req_e; - const char *url_b; - const char *url_e; - const char *proto_b; - const char *proto_e; - const char *hdr_b; - const char *hdr_e; - - enum { - HND_Unclass, - HND_Handle, - HND_Pass - } handling; - - /* Various internal stuff */ - struct event *rd_e; - struct sessmem *mem; -}; - /* cache_acceptor.c */ void *vca_main(void *arg); /* cache_httpd.c */ void HttpdAnalyze(struct sess *sp); +/* cache_pool.c */ +void CacheInitPool(void); +void DealWithSession(struct sess *sp); + /* cache_shmlog.c */ void VSL_Init(void); #ifdef SHMLOGHEAD_MAGIC Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-30 07:05:10 UTC (rev 84) @@ -17,6 +17,7 @@ #include #include "libvarnish.h" +#include "vcl_lang.h" #include "heritage.h" #include "shmlog.h" #include "cache.h" @@ -65,10 +66,7 @@ } sp->hdr_e = p; event_del(sp->rd_e); - HttpdAnalyze(sp); - - /* XXX: for now, pass everything */ - sp->handling = HND_Pass; + DealWithSession(sp); } static void Modified: trunk/varnish-cache/bin/varnishd/cache_httpd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-30 07:05:10 UTC (rev 84) @@ -9,6 +9,7 @@ #include "libvarnish.h" #include "shmlog.h" +#include "vcl_lang.h" #include "cache.h" void @@ -20,23 +21,9 @@ /* First, isolate and possibly identify request type */ p = sp->req_b = sp->rcv; - if (p[0] == 'G' && p[1] == 'E' && p[2] == 'T' && p[3] == ' ') { - p = sp->req_e = p + 4; - sp->handling = HND_Handle; - } else if (p[0] == 'H' && p[1] == 'E' && p[2] == 'A' && p[3] == 'D' - && p[4] == ' ') { - p = sp->req_e = p + 5; - sp->handling = HND_Handle; - } else { - /* - * We don't bother to identify the rest, we won't handle - * them in any case - */ - for (q = p; isalpha(*q); q++) - ; - p = sp->req_e = q; - sp->handling = HND_Pass; - } + for (q = p; isalpha(*q); q++) + ; + p = sp->req_e = q; VSLR(SLT_Request, sp->fd, sp->req_b, sp->req_e); /* Next find the URI */ Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-30 07:05:10 UTC (rev 84) @@ -18,6 +18,7 @@ #include "libvarnish.h" #include "heritage.h" #include "shmlog.h" +#include "vcl_lang.h" #include "cache.h" #include "cli_event.h" @@ -100,6 +101,7 @@ printf("Child starts\n"); VSL_Init(); + CacheInitPool(); AZ(pthread_create(&vca_thread, NULL, vca_main, NULL)); Added: trunk/varnish-cache/bin/varnishd/cache_pool.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-30 07:05:10 UTC (rev 84) @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#include +#include +#include + +#include "libvarnish.h" +#include "vcl_lang.h" +#include "cache.h" + +static TAILQ_HEAD(, sess) shd = TAILQ_HEAD_INITIALIZER(shd); + +static pthread_mutex_t shdmtx; +static pthread_cond_t shdcnd; + +static void * +CacheWorker(void *priv __unused) +{ + struct sess *sp; + + while (1) { + AZ(pthread_mutex_lock(&shdmtx)); + while (1) { + sp = TAILQ_FIRST(&shd); + if (sp != NULL) + break; + AZ(pthread_cond_wait(&shdcnd, &shdmtx)); + } + TAILQ_REMOVE(&shd, sp, list); + AZ(pthread_mutex_unlock(&shdmtx)); + + HttpdAnalyze(sp); + + /* + * XXX send session to acceptor for reuse/disposal + */ + } +} + +void +DealWithSession(struct sess *sp) +{ + AZ(pthread_mutex_lock(&shdmtx)); + TAILQ_INSERT_TAIL(&shd, sp, list); + AZ(pthread_mutex_unlock(&shdmtx)); + AZ(pthread_cond_signal(&shdcnd)); +} + +void +CacheInitPool(void) +{ + pthread_t tp; + + AZ(pthread_mutex_init(&shdmtx, NULL)); + AZ(pthread_cond_init(&shdcnd, NULL)); + + AZ(pthread_create(&tp, NULL, CacheWorker, NULL)); + AZ(pthread_detach(tp)); +} Modified: trunk/varnish-cache/bin/varnishd/cache_vcl.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-30 07:05:10 UTC (rev 84) @@ -142,3 +142,13 @@ } active_vcl = vcl; } + +/*--------------------------------------------------------------------*/ + +void +VCL_pass(VCL_FARGS) +{ + + sess->handling = HND_Pass; + sess->done++; +} Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-30 07:05:10 UTC (rev 84) @@ -68,8 +68,23 @@ buf = NULL; asprintf(&buf, - "backend default { set backend.ip = %s; }", - bflag); + "backend default { set backend.ip = %s; }\n" + "sub main {\n" + " pass;\n" +#if 0 + " if (req.request != \"GET\" && req.request != \"HEAD\") {\n" + " pass;\n" + " }\n" + " lookup;\n" + " if (!obj.valid) {\n" + " fetch;\n" + " if (obj.cacheable) {\n" + " insert;\n" + " }\n" + " }\n" +#endif + "}\n" + "", bflag); assert(buf != NULL); sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); assert(sb != NULL); Modified: trunk/varnish-cache/include/vcl_lang.h =================================================================== --- trunk/varnish-cache/include/vcl_lang.h 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/include/vcl_lang.h 2006-03-30 07:05:10 UTC (rev 84) @@ -5,6 +5,7 @@ * XXX: *MUST* be rerun. */ +#include struct vcl_ref { unsigned line; @@ -18,19 +19,42 @@ unsigned mask; }; -struct client { - unsigned ip; -}; +#define VCA_RXBUFSIZE 1024 +#define VCA_ADDRBUFSIZE 32 -struct req { - char *req; - char *useragent; - struct { - char *path; - char *host; - } url; - double ttlfactor; - struct backend *backend; +struct sess { + int fd; + + /* formatted ascii client address */ + char addr[VCA_ADDRBUFSIZE]; + + /* Receive buffer for HTTP header */ + char rcv[VCA_RXBUFSIZE + 1]; + unsigned rcv_len; + + /* HTTP request info, points into rcv */ + const char *req_b; + const char *req_e; + const char *url_b; + const char *url_e; + const char *proto_b; + const char *proto_e; + const char *hdr_b; + const char *hdr_e; + + enum { + HND_Unclass, + HND_Handle, + HND_Pass + } handling; + + char done; + + TAILQ_ENTRY(sess) list; + + /* Various internal stuff */ + struct event *rd_e; + struct sessmem *mem; }; struct backend { @@ -41,17 +65,9 @@ int down; }; -struct obj { - int exists; - double ttl; - unsigned result; - unsigned size; - unsigned usage; -}; +#define VCL_FARGS struct sess *sess +#define VCL_PASS_ARGS sess -#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend -#define VCL_PASS_ARGS client, obj, req, backend - void VCL_count(unsigned); void VCL_no_cache(); void VCL_no_new_cache(); @@ -59,15 +75,18 @@ int string_match(const char *, const char *); int VCL_rewrite(const char *, const char *); int VCL_error(unsigned, const char *); +void VCL_pass(VCL_FARGS); int VCL_fetch(void); int VCL_switch_config(const char *); typedef void vcl_init_f(void); +typedef void vcl_func_f(VCL_FARGS); struct VCL_conf { unsigned magic; #define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */ vcl_init_f *init_func; + vcl_func_f *main_func; struct backend *default_backend; struct vcl_ref *ref; unsigned nref; Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-30 07:05:10 UTC (rev 84) @@ -818,6 +818,11 @@ I(tl); sbuf_printf(tl->fc, "return;\n"); return; + case T_PASS: + I(tl); + sbuf_printf(tl->fc, "VCL_pass(VCL_PASS_ARGS);\n"); + sbuf_printf(tl->fc, "return;\n"); + return; case T_FETCH: I(tl); sbuf_printf(tl->fc, "VCL_fetch();\n"); @@ -849,7 +854,8 @@ sbuf_printf(tl->fc, "VCL_function_%*.*s(VCL_PASS_ARGS);\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); - /* XXX: check if function finished request */ + I(tl); sbuf_printf(tl->fc, "if (sess->done)\n"); + I(tl); sbuf_printf(tl->fc, "\treturn;\n"); NextToken(tl); return; case T_REWRITE: @@ -1364,6 +1370,8 @@ sbuf_printf(tl->fc, "\t.init_func = VCL_Init,\n"); sbuf_printf(tl->fc, + "\t.main_func = VCL_function_main,\n"); + sbuf_printf(tl->fc, "\t.default_backend = &VCL_backend_default,\n"); sbuf_printf(tl->fc, "\t.ref = VCL_ref,\n"); Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-30 07:05:10 UTC (rev 84) @@ -245,6 +245,11 @@ *q = p + 4; return (T_PROC); } + if (p[0] == 'p' && p[1] == 'a' && p[2] == 's' && + p[3] == 's' && !isvar(p[4])) { + *q = p + 4; + return (T_PASS); + } return (0); case 'r': if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' && @@ -360,6 +365,7 @@ vcl_tnames[T_NEQ] = "!="; vcl_tnames[T_NO_CACHE] = "no_cache"; vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache"; + vcl_tnames[T_PASS] = "pass"; vcl_tnames[T_PROC] = "proc"; vcl_tnames[T_REWRITE] = "rewrite"; vcl_tnames[T_SET] = "set"; @@ -380,6 +386,7 @@ fputs(" * XXX: *MUST* be rerun.\n", f); fputs(" */\n", f); fputs("\n", f); + fputs("#include \n", f); fputs("\n", f); fputs("struct vcl_ref {\n", f); fputs(" unsigned line;\n", f); @@ -393,19 +400,40 @@ fputs(" unsigned mask;\n", f); fputs("};\n", f); fputs("\n", f); - fputs("struct client {\n", f); - fputs(" unsigned ip;\n", f); - fputs("};\n", f); + fputs("#define VCA_RXBUFSIZE 1024\n", f); + fputs("#define VCA_ADDRBUFSIZE 32\n", f); fputs("\n", f); - fputs("struct req {\n", f); - fputs(" char *req;\n", f); - fputs(" char *useragent;\n", f); - fputs(" struct {\n", f); - fputs(" char *path;\n", f); - fputs(" char *host;\n", f); - fputs(" } url;\n", f); - fputs(" double ttlfactor;\n", f); - fputs(" struct backend *backend;\n", f); + fputs("struct sess {\n", f); + fputs(" int fd;\n", f); + fputs("\n", f); + fputs(" /* formatted ascii client address */\n", f); + fputs(" char addr[VCA_ADDRBUFSIZE];\n", f); + fputs("\n", f); + fputs(" /* Receive buffer for HTTP header */\n", f); + fputs(" char rcv[VCA_RXBUFSIZE + 1];\n", f); + fputs(" unsigned rcv_len;\n", f); + fputs("\n", f); + fputs(" /* HTTP request info, points into rcv */\n", f); + fputs(" const char *req_b;\n", f); + fputs(" const char *req_e;\n", f); + fputs(" const char *url_b;\n", f); + fputs(" const char *url_e;\n", f); + fputs(" const char *proto_b;\n", f); + fputs(" const char *proto_e;\n", f); + fputs(" const char *hdr_b;\n", f); + fputs(" const char *hdr_e;\n", f); + fputs("\n", f); + fputs(" enum {\n", f); + fputs(" HND_Unclass,\n", f); + fputs(" HND_Handle,\n", f); + fputs(" HND_Pass\n", f); + fputs(" } handling;\n", f); + fputs("\n", f); + fputs(" char done;\n", f); + fputs("\n", f); + fputs(" /* Various internal stuff */\n", f); + fputs(" struct event *rd_e;\n", f); + fputs(" struct sessmem *mem;\n", f); fputs("};\n", f); fputs("\n", f); fputs("struct backend {\n", f); @@ -416,17 +444,9 @@ fputs(" int down;\n", f); fputs("};\n", f); fputs("\n", f); - fputs("struct obj {\n", f); - fputs(" int exists;\n", f); - fputs(" double ttl;\n", f); - fputs(" unsigned result;\n", f); - fputs(" unsigned size;\n", f); - fputs(" unsigned usage;\n", f); - fputs("};\n", f); + fputs("#define VCL_FARGS struct sess *sess\n", f); + fputs("#define VCL_PASS_ARGS sess\n", f); fputs("\n", f); - fputs("#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend\n", f); - fputs("#define VCL_PASS_ARGS client, obj, req, backend\n", f); - fputs("\n", f); fputs("void VCL_count(unsigned);\n", f); fputs("void VCL_no_cache();\n", f); fputs("void VCL_no_new_cache();\n", f); @@ -434,15 +454,18 @@ fputs("int string_match(const char *, const char *);\n", f); fputs("int VCL_rewrite(const char *, const char *);\n", f); fputs("int VCL_error(unsigned, const char *);\n", f); + fputs("void VCL_pass(VCL_FARGS);\n", f); fputs("int VCL_fetch(void);\n", f); fputs("int VCL_switch_config(const char *);\n", f); fputs("\n", f); fputs("typedef void vcl_init_f(void);\n", f); + fputs("typedef void vcl_func_f(VCL_FARGS);\n", f); fputs("\n", f); fputs("struct VCL_conf {\n", f); fputs(" unsigned magic;\n", f); fputs("#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n", f); fputs(" vcl_init_f *init_func;\n", f); + fputs(" vcl_func_f *main_func;\n", f); fputs(" struct backend *default_backend;\n", f); fputs(" struct vcl_ref *ref;\n", f); fputs(" unsigned nref;\n", f); Modified: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-30 07:05:10 UTC (rev 84) @@ -13,6 +13,7 @@ backend error + pass fetch call no_cache Modified: trunk/varnish-cache/lib/libvcl/vcl_token_defs.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-03-27 14:12:07 UTC (rev 83) +++ trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-03-30 07:05:10 UTC (rev 84) @@ -14,30 +14,31 @@ #define T_ACL 135 #define T_BACKEND 136 #define T_ERROR 137 -#define T_FETCH 138 -#define T_CALL 139 -#define T_NO_CACHE 140 -#define T_NO_NEW_CACHE 141 -#define T_SET 142 -#define T_REWRITE 143 -#define T_FINISH 144 -#define T_SWITCH_CONFIG 145 -#define T_INC 146 -#define T_DEC 147 -#define T_CAND 148 -#define T_COR 149 -#define T_LEQ 150 -#define T_EQ 151 -#define T_NEQ 152 -#define T_GEQ 153 -#define T_SHR 154 -#define T_SHL 155 -#define T_INCR 156 -#define T_DECR 157 -#define T_MUL 158 -#define T_DIV 159 -#define ID 160 -#define VAR 161 -#define CNUM 162 -#define CSTR 163 -#define EOI 164 +#define T_PASS 138 +#define T_FETCH 139 +#define T_CALL 140 +#define T_NO_CACHE 141 +#define T_NO_NEW_CACHE 142 +#define T_SET 143 +#define T_REWRITE 144 +#define T_FINISH 145 +#define T_SWITCH_CONFIG 146 +#define T_INC 147 +#define T_DEC 148 +#define T_CAND 149 +#define T_COR 150 +#define T_LEQ 151 +#define T_EQ 152 +#define T_NEQ 153 +#define T_GEQ 154 +#define T_SHR 155 +#define T_SHL 156 +#define T_INCR 157 +#define T_DECR 158 +#define T_MUL 159 +#define T_DIV 160 +#define ID 161 +#define VAR 162 +#define CNUM 163 +#define CSTR 164 +#define EOI 165 From phk at projects.linpro.no Thu Mar 30 08:05:11 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 30 Mar 2006 10:05:11 +0200 (CEST) Subject: r85 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20060330080511.B52BC1ED5FA@projects.linpro.no> Author: phk Date: 2006-03-30 10:05:11 +0200 (Thu, 30 Mar 2006) New Revision: 85 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cache_pool.c trunk/varnish-cache/bin/varnishd/cache_vcl.c trunk/varnish-cache/include/vcl_lang.h trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c Log: Promote the poll mutex to be a session mutex so that we can use it for the VCL reference as well, this saves locking operations. Call the atual VCL code when we get the request. Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-30 08:05:11 UTC (rev 85) @@ -8,6 +8,9 @@ /* cache_httpd.c */ void HttpdAnalyze(struct sess *sp); +/* cache_main.c */ +pthread_mutex_t sessmtx; + /* cache_pool.c */ void CacheInitPool(void); void DealWithSession(struct sess *sp); @@ -20,6 +23,8 @@ #endif /* cache_vcl.c */ +void RelVCL(struct VCL_conf *vc); +struct VCL_conf *GetVCL(void); int CVCL_Load(const char *fn, const char *name); #ifdef CLI_PRIV_H cli_func_t cli_func_config_list; Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-30 08:05:11 UTC (rev 85) @@ -25,6 +25,8 @@ static struct event ev_keepalive; static pthread_t vca_thread; +pthread_mutex_t sessmtx; + /*--------------------------------------------------------------------*/ static void @@ -100,6 +102,7 @@ setbuf(stderr, NULL); printf("Child starts\n"); + AZ(pthread_mutex_init(&sessmtx, NULL)); VSL_Init(); CacheInitPool(); Modified: trunk/varnish-cache/bin/varnishd/cache_pool.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-30 08:05:11 UTC (rev 85) @@ -12,7 +12,6 @@ static TAILQ_HEAD(, sess) shd = TAILQ_HEAD_INITIALIZER(shd); -static pthread_mutex_t shdmtx; static pthread_cond_t shdcnd; static void * @@ -20,31 +19,38 @@ { struct sess *sp; + AZ(pthread_mutex_lock(&sessmtx)); while (1) { - AZ(pthread_mutex_lock(&shdmtx)); while (1) { sp = TAILQ_FIRST(&shd); if (sp != NULL) break; - AZ(pthread_cond_wait(&shdcnd, &shdmtx)); + AZ(pthread_cond_wait(&shdcnd, &sessmtx)); } TAILQ_REMOVE(&shd, sp, list); - AZ(pthread_mutex_unlock(&shdmtx)); + sp->vcl = GetVCL(); + AZ(pthread_mutex_unlock(&sessmtx)); HttpdAnalyze(sp); - /* - * XXX send session to acceptor for reuse/disposal - */ + /* Call the VCL program */ + sp->vcl->main_func(sp); + + printf("Handling: %d\n", sp->handling); + + AZ(pthread_mutex_lock(&sessmtx)); + RelVCL(sp->vcl); + sp->vcl = NULL; + /* XXX send session to acceptor for reuse/disposal */ } } void DealWithSession(struct sess *sp) { - AZ(pthread_mutex_lock(&shdmtx)); + AZ(pthread_mutex_lock(&sessmtx)); TAILQ_INSERT_TAIL(&shd, sp, list); - AZ(pthread_mutex_unlock(&shdmtx)); + AZ(pthread_mutex_unlock(&sessmtx)); AZ(pthread_cond_signal(&shdcnd)); } @@ -53,7 +59,6 @@ { pthread_t tp; - AZ(pthread_mutex_init(&shdmtx, NULL)); AZ(pthread_cond_init(&shdcnd, NULL)); AZ(pthread_create(&tp, NULL, CacheWorker, NULL)); Modified: trunk/varnish-cache/bin/varnishd/cache_vcl.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-30 08:05:11 UTC (rev 85) @@ -12,6 +12,7 @@ #include "cli.h" #include "cli_priv.h" #include "vcl_lang.h" +#include "libvarnish.h" #include "cache.h" struct vcls { @@ -21,11 +22,42 @@ struct VCL_conf *conf; }; +/* + * XXX: Presently all modifications to this list happen from the + * CLI event-engine, so no locking is necessary + */ static TAILQ_HEAD(, vcls) vcl_head = TAILQ_HEAD_INITIALIZER(vcl_head); -static struct vcls *active_vcl; +static struct vcls *active_vcl; /* protected by sessmtx */ + + +/*--------------------------------------------------------------------*/ + +struct VCL_conf * +GetVCL(void) +{ + struct VCL_conf *vc; + + /* XXX: assert sessmtx (procects active_vcl && ->busy) */ + assert(active_vcl != NULL); + vc = active_vcl->conf; + assert(vc != NULL); + vc->busy++; + return (vc); +} + +void +RelVCL(struct VCL_conf *vc) +{ + + /* XXX: assert sessmtx (procects ->busy) */ + vc->busy--; +} + +/*--------------------------------------------------------------------*/ + int CVCL_Load(const char *fn, const char *name) { @@ -56,8 +88,10 @@ vcl->name = strdup(name); assert(vcl->name != NULL); TAILQ_INSERT_TAIL(&vcl_head, vcl, list); + AZ(pthread_mutex_lock(&sessmtx)); if (active_vcl == NULL) active_vcl = vcl; + AZ(pthread_mutex_unlock(&sessmtx)); fprintf(stderr, "Loaded \"%s\" as \"%s\"\n", fn , name); return (0); } @@ -68,24 +102,34 @@ struct vcls *vcl; TAILQ_FOREACH(vcl, &vcl_head, list) { - cli_out(cli, "%s%s\n", + cli_out(cli, "%s %6u %s\n", vcl == active_vcl ? "* " : " ", + vcl->conf->busy, vcl->name); } } +static struct vcls * +find_vcls(const char *name) +{ + struct vcls *vcl; + TAILQ_FOREACH(vcl, &vcl_head, list) + if (!strcmp(vcl->name, name)) + return (vcl); + return (NULL); +} + void cli_func_config_load(struct cli *cli, char **av, void *priv) { struct vcls *vcl; - TAILQ_FOREACH(vcl, &vcl_head, list) { - if (!strcmp(vcl->name, av[2])) { - cli_out(cli, "Config '%s' already loaded", av[2]); - cli_result(cli, CLIS_PARAM); - return; - } + vcl = find_vcls(av[2]); + if (vcl != NULL) { + cli_out(cli, "Config '%s' already loaded", av[2]); + cli_result(cli, CLIS_PARAM); + return; } vcl = calloc(sizeof *vcl, 1); assert(vcl != NULL); @@ -115,9 +159,8 @@ vcl->name = strdup(av[2]); assert(vcl->name != NULL); TAILQ_INSERT_TAIL(&vcl_head, vcl, list); - if (active_vcl == NULL) - active_vcl = vcl; cli_out(cli, "Loaded \"%s\" from \"%s\"\n", vcl->name , av[3]); + return; } void @@ -131,16 +174,15 @@ { struct vcls *vcl; - TAILQ_FOREACH(vcl, &vcl_head, list) { - if (!strcmp(vcl->name, av[2])) - break; - } - if (vcl == NULL) { + vcl = find_vcls(av[2]); + if (vcl != NULL) { + AZ(pthread_mutex_lock(&sessmtx)); + active_vcl = vcl; + AZ(pthread_mutex_unlock(&sessmtx)); + } else { cli_out(cli, "No config named '%s' loaded", av[2]); cli_result(cli, CLIS_PARAM); - return; } - active_vcl = vcl; } /*--------------------------------------------------------------------*/ Modified: trunk/varnish-cache/include/vcl_lang.h =================================================================== --- trunk/varnish-cache/include/vcl_lang.h 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/include/vcl_lang.h 2006-03-30 08:05:11 UTC (rev 85) @@ -6,6 +6,7 @@ */ #include +#include struct vcl_ref { unsigned line; @@ -52,17 +53,28 @@ TAILQ_ENTRY(sess) list; + struct VCL_conf *vcl; + /* Various internal stuff */ struct event *rd_e; struct sessmem *mem; }; +struct be_conn { + TAILQ_ENTRY(be_conn) list; + int fd; +}; + struct backend { unsigned ip; double responsetime; double timeout; double bandwidth; int down; + + /* Internals */ + TAILQ_HEAD(,be_conn) bec_head; + unsigned nbec; }; #define VCL_FARGS struct sess *sess @@ -90,4 +102,5 @@ struct backend *default_backend; struct vcl_ref *ref; unsigned nref; + unsigned busy; }; Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-30 07:05:10 UTC (rev 84) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-30 08:05:11 UTC (rev 85) @@ -387,6 +387,7 @@ fputs(" */\n", f); fputs("\n", f); fputs("#include \n", f); + fputs("#include \n", f); fputs("\n", f); fputs("struct vcl_ref {\n", f); fputs(" unsigned line;\n", f); @@ -404,44 +405,57 @@ fputs("#define VCA_ADDRBUFSIZE 32\n", f); fputs("\n", f); fputs("struct sess {\n", f); - fputs(" int fd;\n", f); + fputs(" int fd;\n", f); fputs("\n", f); fputs(" /* formatted ascii client address */\n", f); - fputs(" char addr[VCA_ADDRBUFSIZE];\n", f); + fputs(" char addr[VCA_ADDRBUFSIZE];\n", f); fputs("\n", f); fputs(" /* Receive buffer for HTTP header */\n", f); - fputs(" char rcv[VCA_RXBUFSIZE + 1];\n", f); - fputs(" unsigned rcv_len;\n", f); + fputs(" char rcv[VCA_RXBUFSIZE + 1];\n", f); + fputs(" unsigned rcv_len;\n", f); fputs("\n", f); fputs(" /* HTTP request info, points into rcv */\n", f); - fputs(" const char *req_b;\n", f); - fputs(" const char *req_e;\n", f); - fputs(" const char *url_b;\n", f); - fputs(" const char *url_e;\n", f); - fputs(" const char *proto_b;\n", f); - fputs(" const char *proto_e;\n", f); - fputs(" const char *hdr_b;\n", f); - fputs(" const char *hdr_e;\n", f); + fputs(" const char *req_b;\n", f); + fputs(" const char *req_e;\n", f); + fputs(" const char *url_b;\n", f); + fputs(" const char *url_e;\n", f); + fputs(" const char *proto_b;\n", f); + fputs(" const char *proto_e;\n", f); + fputs(" const char *hdr_b;\n", f); + fputs(" const char *hdr_e;\n", f); fputs("\n", f); fputs(" enum {\n", f); fputs(" HND_Unclass,\n", f); fputs(" HND_Handle,\n", f); fputs(" HND_Pass\n", f); - fputs(" } handling;\n", f); + fputs(" } handling;\n", f); fputs("\n", f); - fputs(" char done;\n", f); + fputs(" char done;\n", f); fputs("\n", f); + fputs(" TAILQ_ENTRY(sess) list;\n", f); + fputs("\n", f); + fputs(" struct VCL_conf *vcl;\n", f); + fputs("\n", f); fputs(" /* Various internal stuff */\n", f); - fputs(" struct event *rd_e;\n", f); - fputs(" struct sessmem *mem;\n", f); + fputs(" struct event *rd_e;\n", f); + fputs(" struct sessmem *mem;\n", f); fputs("};\n", f); fputs("\n", f); + fputs("struct be_conn {\n", f); + fputs(" TAILQ_ENTRY(be_conn) list;\n", f); + fputs(" int fd;\n", f); + fputs("};\n", f); + fputs("\n", f); fputs("struct backend {\n", f); fputs(" unsigned ip;\n", f); fputs(" double responsetime;\n", f); fputs(" double timeout;\n", f); fputs(" double bandwidth;\n", f); fputs(" int down;\n", f); + fputs("\n", f); + fputs(" /* Internals */\n", f); + fputs(" TAILQ_HEAD(,be_conn) bec_head;\n", f); + fputs(" unsigned nbec;\n", f); fputs("};\n", f); fputs("\n", f); fputs("#define VCL_FARGS struct sess *sess\n", f); @@ -469,5 +483,6 @@ fputs(" struct backend *default_backend;\n", f); fputs(" struct vcl_ref *ref;\n", f); fputs(" unsigned nref;\n", f); + fputs(" unsigned busy;\n", f); fputs("};\n", f); } From phk at projects.linpro.no Thu Mar 30 09:26:34 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 30 Mar 2006 11:26:34 +0200 (CEST) Subject: r86 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20060330092634.9890D1ED606@projects.linpro.no> Author: phk Date: 2006-03-30 11:26:34 +0200 (Thu, 30 Mar 2006) New Revision: 86 Added: trunk/varnish-cache/bin/varnishd/cache_backend.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cache_pool.c trunk/varnish-cache/bin/varnishd/varnishd.c trunk/varnish-cache/include/vcl_lang.h trunk/varnish-cache/lib/libvcl/vcl_compile.c trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c Log: Add the beginning of a backend connection pool Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2006-03-30 09:26:34 UTC (rev 86) @@ -6,6 +6,7 @@ varnishd_SOURCES = \ cache_acceptor.c \ + cache_backend.c \ cache_httpd.c \ cache_main.c \ cache_pool.c \ Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/cache.h 2006-03-30 09:26:34 UTC (rev 86) @@ -5,6 +5,9 @@ /* cache_acceptor.c */ void *vca_main(void *arg); +/* cache_backend.c */ +void VBE_Init(void); + /* cache_httpd.c */ void HttpdAnalyze(struct sess *sp); Added: trunk/varnish-cache/bin/varnishd/cache_backend.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-30 09:26:34 UTC (rev 86) @@ -0,0 +1,92 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include "libvarnish.h" +#include "vcl_lang.h" + +/* + * The internal backend structure for managing connection pools per + * backend. We need to shadow the backend stucture from the VCL + * in order let connections live across VCL switches. + */ + +struct vbe_conn { + TAILQ_ENTRY(vbe_conn) list; + struct vbe *vbe; + int fd; +}; + +struct vbe { + unsigned ip; + TAILQ_ENTRY(vbe) list; + TAILQ_HEAD(,vbe_conn) fconn; + TAILQ_HEAD(,vbe_conn) bconn; + unsigned nconn; +}; + +static TAILQ_HEAD(,vbe) vbe_head = TAILQ_HEAD_INITIALIZER(vbe_head); + +static pthread_mutex_t vbemtx; + +/*--------------------------------------------------------------------*/ +void +connect_to_backend(struct vbe_conn *vc, struct backend *bp) +{ +} + +/*--------------------------------------------------------------------*/ + +int +VBE_GetFd(struct backend *bp) +{ + struct vbe *vp; + struct vbe_conn *vc; + + AZ(pthread_mutex_lock(&vbemtx)); + vp = bp->vbe; + if (vp == NULL) { + TAILQ_FOREACH(vp, &vbe_head, list) + if (vp->ip == bp->ip) + break; + } + if (vp == NULL) { + vp = calloc(sizeof *vp, 1); + assert(vp != NULL); + TAILQ_INIT(&vp->fconn); + TAILQ_INIT(&vp->bconn); + vp->ip = bp->ip; + bp->vbe = vp; + TAILQ_INSERT_TAIL(&vbe_head, vp, list); + } + /* XXX: check nconn vs backend->maxcon */ + vc = TAILQ_FIRST(&vp->fconn); + if (vc != NULL) { + TAILQ_REMOVE(&vp->fconn, vc, list); + TAILQ_INSERT_TAIL(&vp->bconn, vc, list); + AZ(pthread_mutex_unlock(&vbemtx)); + return (vc->fd); + } + vc = calloc(sizeof *vc, 1); + assert(vc != NULL); + vc->vbe = vp; + TAILQ_INSERT_TAIL(&vp->bconn, vc, list); + AZ(pthread_mutex_unlock(&vbemtx)); + connect_to_backend(vc, bp); + + /* XXX */ + return (-1); +} + + + + +void +VBE_Init(void) +{ + + AZ(pthread_mutex_init(&vbemtx, NULL)); +} Modified: trunk/varnish-cache/bin/varnishd/cache_main.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/cache_main.c 2006-03-30 09:26:34 UTC (rev 86) @@ -103,6 +103,7 @@ printf("Child starts\n"); AZ(pthread_mutex_init(&sessmtx, NULL)); + VBE_Init(); VSL_Init(); CacheInitPool(); Modified: trunk/varnish-cache/bin/varnishd/cache_pool.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/cache_pool.c 2006-03-30 09:26:34 UTC (rev 86) @@ -33,6 +33,7 @@ HttpdAnalyze(sp); + sp->backend = sp->vcl->default_backend; /* Call the VCL program */ sp->vcl->main_func(sp); Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-30 09:26:34 UTC (rev 86) @@ -68,7 +68,7 @@ buf = NULL; asprintf(&buf, - "backend default { set backend.ip = %s; }\n" + "backend default { set backend.host = \"%s\"; }\n" "sub main {\n" " pass;\n" #if 0 Modified: trunk/varnish-cache/include/vcl_lang.h =================================================================== --- trunk/varnish-cache/include/vcl_lang.h 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/include/vcl_lang.h 2006-03-30 09:26:34 UTC (rev 86) @@ -53,6 +53,7 @@ TAILQ_ENTRY(sess) list; + struct backend *backend; struct VCL_conf *vcl; /* Various internal stuff */ @@ -60,21 +61,18 @@ struct sessmem *mem; }; -struct be_conn { - TAILQ_ENTRY(be_conn) list; - int fd; -}; - struct backend { + const char *hostname; + const char *portname; + struct addrinfo *addr; unsigned ip; double responsetime; double timeout; double bandwidth; int down; - /* Internals */ - TAILQ_HEAD(,be_conn) bec_head; - unsigned nbec; + /* internal stuff */ + struct vbe *vbe; }; #define VCL_FARGS struct sess *sess Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-30 09:26:34 UTC (rev 86) @@ -109,6 +109,9 @@ static struct var vars[] = { + { "backend.host", STRING, 0, "backend->hostname" }, + { "backend.port", STRING, 0, "backend->portname" }, +#if 0 { "req.ttlfactor", FLOAT, 0, "req->ttlfactor" }, { "req.url.host", STRING, 0, "req->url.host" }, { "req.url.path", STRING, 0, "req->url.path" }, @@ -116,7 +119,6 @@ { "req.backend", BACKEND, 0, "req->backend" }, { "client.ip", IP, 0, "client->ip" }, { "backend.response_time", TIME, 0, "backend->responsetime" }, - { "backend.ip", IP, 0, "backend->ip" }, { "backend.down", BOOL, 0, "backend->down" }, { "backend.timeout", TIME, 0, "backend->timeout" }, { "backend.bandwidth", RATE, 0, "backend->bandwidth" }, @@ -125,6 +127,7 @@ { "obj.result", INT, 0, "obj->result" }, { "obj.size", SIZE, 0, "obj->size" }, { "obj.usage", INT, 0, "obj->usage" }, +#endif { NULL, INT, 0, "NULL" } }; Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-30 08:05:11 UTC (rev 85) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-30 09:26:34 UTC (rev 86) @@ -434,6 +434,7 @@ fputs("\n", f); fputs(" TAILQ_ENTRY(sess) list;\n", f); fputs("\n", f); + fputs(" struct backend *backend;\n", f); fputs(" struct VCL_conf *vcl;\n", f); fputs("\n", f); fputs(" /* Various internal stuff */\n", f); @@ -441,21 +442,18 @@ fputs(" struct sessmem *mem;\n", f); fputs("};\n", f); fputs("\n", f); - fputs("struct be_conn {\n", f); - fputs(" TAILQ_ENTRY(be_conn) list;\n", f); - fputs(" int fd;\n", f); - fputs("};\n", f); - fputs("\n", f); fputs("struct backend {\n", f); + fputs(" const char *hostname;\n", f); + fputs(" const char *portname;\n", f); + fputs(" struct addrinfo *addr;\n", f); fputs(" unsigned ip;\n", f); fputs(" double responsetime;\n", f); fputs(" double timeout;\n", f); fputs(" double bandwidth;\n", f); fputs(" int down;\n", f); fputs("\n", f); - fputs(" /* Internals */\n", f); - fputs(" TAILQ_HEAD(,be_conn) bec_head;\n", f); - fputs(" unsigned nbec;\n", f); + fputs(" /* internal stuff */\n", f); + fputs(" struct vbe *vbe;\n", f); fputs("};\n", f); fputs("\n", f); fputs("#define VCL_FARGS struct sess *sess\n", f); From phk at projects.linpro.no Thu Mar 30 10:56:57 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 30 Mar 2006 12:56:57 +0200 (CEST) Subject: r87 - trunk/varnish-cache/lib/libvcl Message-ID: <20060330105657.3FA621ED5D6@projects.linpro.no> Author: phk Date: 2006-03-30 12:56:57 +0200 (Thu, 30 Mar 2006) New Revision: 87 Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c Log: Rework the compilation of backend specifications in order to be able to check the provided hostname/portname at compile time. Modified: trunk/varnish-cache/lib/libvcl/vcl_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-30 09:26:34 UTC (rev 86) +++ trunk/varnish-cache/lib/libvcl/vcl_compile.c 2006-03-30 10:56:57 UTC (rev 87) @@ -44,6 +44,11 @@ #include #include #include + +#include +#include +#include + #include "vcl_priv.h" #include "libvcl.h" @@ -82,7 +87,9 @@ RATE, TIME, STRING, - IP + IP, + HOSTNAME, + PORTNAME }; struct var { @@ -90,7 +97,6 @@ enum var_type fmt; int len; const char *cname; - }; enum ref_type { @@ -108,9 +114,13 @@ }; +static struct var be_vars[] = { + { "backend.host", HOSTNAME, 0, "backend->hostname" }, + { "backend.port", PORTNAME, 0, "backend->portname" }, +}; + + static struct var vars[] = { - { "backend.host", STRING, 0, "backend->hostname" }, - { "backend.port", STRING, 0, "backend->portname" }, #if 0 { "req.ttlfactor", FLOAT, 0, "req->ttlfactor" }, { "req.url.host", STRING, 0, "req->url.host" }, @@ -279,6 +289,58 @@ return (1); } +/*--------------------------------------------------------------------*/ + +char * +EncString(struct token *t) +{ + char *p, *q; + const char *r; + unsigned u; + + assert(t->tok == CSTR); + p = malloc(t->e - t->b); + assert(p != NULL); + q = p; + for (r = t->b + 1; r < t->e - 1; ) { + if (*r != '\\') { + *q++ = *r++; + continue; + } + switch (r[1]) { + case 'n': *q++ = '\n'; r += 2; break; + case 'r': *q++ = '\r'; r += 2; break; + case 'v': *q++ = '\v'; r += 2; break; + case 'f': *q++ = '\f'; r += 2; break; + case 't': *q++ = '\t'; r += 2; break; + case 'b': *q++ = '\b'; r += 2; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + u = digittoint(r[1]); + r += 2; + if (isdigit(r[0]) && digittoint(r[0]) < 8) { + u <<= 3; + u |= digittoint(r[0]); + r++; + if (isdigit(r[0]) && digittoint(r[0]) < 8) { + u <<= 3; + u |= digittoint(r[0]); + r++; + } + } + *q++ = u; + break; + default: + *q++ = r[1]; + r += 2; + break; + } + } + *q = '\0'; + return (p); +} + + /*-------------------------------------------------------------------- * Keep track of definitions and references */ @@ -487,11 +549,11 @@ /*--------------------------------------------------------------------*/ static struct var * -FindVar(struct tokenlist *tl, struct token *t) +FindVar(struct tokenlist *tl, struct token *t, struct var *vl) { struct var *v; - for (v = vars; v->name != NULL; v++) { + for (v = vl; v->name != NULL; v++) { if (t->e - t->b != v->len) continue; if (!memcmp(t->b, v->name, v->len)) @@ -683,7 +745,7 @@ ExpectErr(tl, ')'); NextToken(tl); } else if (tl->t->tok == VAR) { - vp = FindVar(tl, tl->t); + vp = FindVar(tl, tl->t, vars); ERRCHK(tl); assert(vp != NULL); NextToken(tl); @@ -876,7 +938,7 @@ return; case T_SET: ExpectErr(tl, VAR); - vp = FindVar(tl, tl->t); + vp = FindVar(tl, tl->t, vars); ERRCHK(tl); assert(vp != NULL); I(tl); @@ -1046,12 +1108,36 @@ /*--------------------------------------------------------------------*/ +static const char * +CheckHostPort(const char *host, const char *port) +{ + struct addrinfo *res, hint; + int error; + + memset(&hint, 0, sizeof hint); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hint, &res); + if (error) + return (gai_strerror(error)); + freeaddrinfo(res); + return (NULL); +} + static void Backend(struct tokenlist *tl) { + struct var *vp; + struct token *t_be = NULL; + struct token *t_host = NULL; + struct token *t_port = NULL; + char *host = NULL; + char *port = NULL; + const char *ep; NextToken(tl); ExpectErr(tl, ID); + t_be = tl->t; AddDef(tl, tl->t, R_BACKEND); I(tl); sbuf_printf(tl->fh, "static struct backend VCL_backend_%*.*s;\n", @@ -1066,8 +1152,86 @@ "VCL_init_backend_%*.*s (struct backend *backend)\n", tl->t->e - tl->t->b, tl->t->e - tl->t->b, tl->t->b); + I(tl); + sbuf_printf(tl->fc, "{\n"); NextToken(tl); - L(tl, Compound(tl)); + ExpectErr(tl, '{'); + NextToken(tl); + while (1) { + if (tl->t->tok == '}') + break; + ExpectErr(tl, T_SET); + NextToken(tl); + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t, be_vars); + ERRCHK(tl); + assert(vp != NULL); + NextToken(tl); + ExpectErr(tl, '='); + NextToken(tl); + switch (vp->fmt) { + case HOSTNAME: + ExpectErr(tl, CSTR); + t_host = tl->t; + host = EncString(tl->t); + I(tl); + sbuf_printf(tl->fc, "\t%s = %*.*s;\n", + vp->cname, + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + case PORTNAME: + ExpectErr(tl, CSTR); + t_port = tl->t; + port = EncString(tl->t); + sbuf_printf(tl->fc, "\t%s = %*.*s;\n", + vp->cname, + tl->t->e - tl->t->b, + tl->t->e - tl->t->b, tl->t->b); + NextToken(tl); + break; + default: + sbuf_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + ErrWhere(tl, tl->t); + return; + } + ExpectErr(tl, ';'); + NextToken(tl); + } + ExpectErr(tl, '}'); + if (host == NULL) { + sbuf_printf(tl->sb, "Backend '%*.*s' has no hostname\n", + t_be->e - t_be->b, + t_be->e - t_be->b, t_be->b); + ErrWhere(tl, tl->t); + return; + } + ep = CheckHostPort(host, "80"); + if (ep != NULL) { + sbuf_printf(tl->sb, + "Backend '%*.*s': %s\n", + t_be->e - t_be->b, + t_be->e - t_be->b, t_be->b, ep); + ErrWhere(tl, t_host); + return; + } + if (port != NULL) { + ep = CheckHostPort(host, port); + if (ep != NULL) { + sbuf_printf(tl->sb, + "Backend '%*.*s': %s\n", + t_be->e - t_be->b, + t_be->e - t_be->b, t_be->b, ep); + ErrWhere(tl, t_port); + return; + } + } + + NextToken(tl); + I(tl); + sbuf_printf(tl->fc, "}\n"); sbuf_printf(tl->fc, "\n"); } @@ -1504,4 +1668,6 @@ vcl_init_tnames(); for (v = vars; v->name != NULL; v++) v->len = strlen(v->name); + for (v = be_vars; v->name != NULL; v++) + v->len = strlen(v->name); } From phk at projects.linpro.no Thu Mar 30 11:16:27 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 30 Mar 2006 13:16:27 +0200 (CEST) Subject: r88 - trunk/varnish-cache/bin/varnishd Message-ID: <20060330111627.C63811ED5DD@projects.linpro.no> Author: phk Date: 2006-03-30 13:16:27 +0200 (Thu, 30 Mar 2006) New Revision: 88 Modified: trunk/varnish-cache/bin/varnishd/cache_backend.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: get us closer to a connection to the backend Modified: trunk/varnish-cache/bin/varnishd/cache_backend.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-30 10:56:57 UTC (rev 87) +++ trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-30 11:16:27 UTC (rev 88) @@ -3,8 +3,15 @@ */ #include +#include +#include +#include #include #include +#include +#include +#include + #include "libvarnish.h" #include "vcl_lang.h" @@ -32,10 +39,47 @@ static pthread_mutex_t vbemtx; -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * XXX: we should not call getaddrinfo() every time, we should cache + * and apply round-robin with blacklisting of entries that do not respond + * etc. Periodic re-lookups to capture changed DNS records would also + * be a good thing in that case. + */ + void connect_to_backend(struct vbe_conn *vc, struct backend *bp) { + struct addrinfo *res, *res0, hint; + int error, s; + + assert(bp != NULL); + assert(bp->hostname != NULL); + memset(&hint, 0, sizeof hint); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + error = getaddrinfo(bp->hostname, + bp->portname == NULL ? "http" : bp->portname, + &hint, &res); + if (error) { + fprintf(stderr, "getaddrinfo: %s\n", + gai_strerror(error)); + return; + } + res0 = res; + do { + s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol); + if (s < 0) + continue; + error = connect(s, res0->ai_addr, res0->ai_addrlen); + if (!error) + break; + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + freeaddrinfo(res); + vc->fd = s; + return; } /*--------------------------------------------------------------------*/ @@ -73,6 +117,7 @@ vc = calloc(sizeof *vc, 1); assert(vc != NULL); vc->vbe = vp; + vc->fd = -1; TAILQ_INSERT_TAIL(&vp->bconn, vc, list); AZ(pthread_mutex_unlock(&vbemtx)); connect_to_backend(vc, bp); @@ -81,9 +126,6 @@ return (-1); } - - - void VBE_Init(void) { Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-30 10:56:57 UTC (rev 87) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2006-03-30 11:16:27 UTC (rev 88) @@ -68,7 +68,9 @@ buf = NULL; asprintf(&buf, - "backend default { set backend.host = \"%s\"; }\n" + "backend default {\n" + " set backend.host = \"%s\";\n" + "}\n" "sub main {\n" " pass;\n" #if 0 From phk at projects.linpro.no Fri Mar 31 08:24:36 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 31 Mar 2006 10:24:36 +0200 (CEST) Subject: r89 - trunk/varnish-cache/include Message-ID: <20060331082436.3F45B1ED53B@projects.linpro.no> Author: phk Date: 2006-03-31 10:24:36 +0200 (Fri, 31 Mar 2006) New Revision: 89 Added: trunk/varnish-cache/include/http_headers.h Log: Reusable macro definition of HTTP headers. We will need these several different places in the sources. Added: trunk/varnish-cache/include/http_headers.h =================================================================== --- trunk/varnish-cache/include/http_headers.h 2006-03-30 11:16:27 UTC (rev 88) +++ trunk/varnish-cache/include/http_headers.h 2006-03-31 08:24:36 UTC (rev 89) @@ -0,0 +1,25 @@ +/* + * $Id$ + */ + +HTTPH("Accept-Charset", H_Accept_Charset) +HTTPH("Accept-Encoding", H_Accept_Encoding) +HTTPH("Accept-Language", H_Accept_Language) +HTTPH("Accept", H_Accept) +HTTPH("Authorization", H_Authorization) +HTTPH("Connection", H_Connection) +HTTPH("Expect", H_Expect) +HTTPH("From", H_From) +HTTPH("Host", H_Host) +HTTPH("If-Match", H_If_Match) +HTTPH("If-Modified-Since", H_If_Modified_Since) +HTTPH("If-None-Match", H_If_None_Match) +HTTPH("If-Range", H_If_Range) +HTTPH("If-Unmodified-Since", H_If_Unmodifed_Since) +HTTPH("Keep-Alive", H_Keep_Alive) +HTTPH("Max-Forwards", H_Max_Forwards) +HTTPH("Proxy-Authorization", H_Proxy_Authorization) +HTTPH("Range", H_Range) +HTTPH("Referer", H_Referer) +HTTPH("TE", H_TE) +HTTPH("User-Agent", H_User_Agent) From phk at projects.linpro.no Fri Mar 31 08:25:29 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 31 Mar 2006 10:25:29 +0200 (CEST) Subject: r90 - trunk/varnish-cache/include Message-ID: <20060331082529.4F9701ED615@projects.linpro.no> Author: phk Date: 2006-03-31 10:25:29 +0200 (Fri, 31 Mar 2006) New Revision: 90 Modified: trunk/varnish-cache/include/shmlog_tags.h Log: Use http_headers.h to define HTTP header tags for logging Modified: trunk/varnish-cache/include/shmlog_tags.h =================================================================== --- trunk/varnish-cache/include/shmlog_tags.h 2006-03-31 08:24:36 UTC (rev 89) +++ trunk/varnish-cache/include/shmlog_tags.h 2006-03-31 08:25:29 UTC (rev 90) @@ -13,4 +13,7 @@ SLTM(Request) SLTM(URL) SLTM(Protocol) -SLTM(Headers) +SLTM(H_Unknown) +#define HTTPH(a, b) SLTM(b) +#include "http_headers.h" +#undef HTTPH From phk at projects.linpro.no Fri Mar 31 08:26:23 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 31 Mar 2006 10:26:23 +0200 (CEST) Subject: r91 - trunk/varnish-cache/bin/varnishd Message-ID: <20060331082623.2E5411ED616@projects.linpro.no> Author: phk Date: 2006-03-31 10:26:23 +0200 (Fri, 31 Mar 2006) New Revision: 91 Modified: trunk/varnish-cache/bin/varnishd/cache_backend.c trunk/varnish-cache/bin/varnishd/cache_vcl.c Log: Add missing pthread.h includes Modified: trunk/varnish-cache/bin/varnishd/cache_backend.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-31 08:25:29 UTC (rev 90) +++ trunk/varnish-cache/bin/varnishd/cache_backend.c 2006-03-31 08:26:23 UTC (rev 91) @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include Modified: trunk/varnish-cache/bin/varnishd/cache_vcl.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-31 08:25:29 UTC (rev 90) +++ trunk/varnish-cache/bin/varnishd/cache_vcl.c 2006-03-31 08:26:23 UTC (rev 91) @@ -6,6 +6,7 @@ #include #include #include +#include #include #include From phk at projects.linpro.no Fri Mar 31 08:27:08 2006 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 31 Mar 2006 10:27:08 +0200 (CEST) Subject: r92 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20060331082708.5B8B01ED615@projects.linpro.no> Author: phk Date: 2006-03-31 10:27:08 +0200 (Fri, 31 Mar 2006) New Revision: 92 Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/cache_httpd.c trunk/varnish-cache/include/vcl_lang.h trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl Log: Use http_headers.h to define session fields for headers and to parse them out of the header. Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-31 08:26:23 UTC (rev 91) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2006-03-31 08:27:08 UTC (rev 92) @@ -64,7 +64,6 @@ continue; break; } - sp->hdr_e = p; event_del(sp->rd_e); DealWithSession(sp); } Modified: trunk/varnish-cache/bin/varnishd/cache_httpd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-31 08:26:23 UTC (rev 91) +++ trunk/varnish-cache/bin/varnishd/cache_httpd.c 2006-03-31 08:27:08 UTC (rev 92) @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include "libvarnish.h" @@ -15,16 +17,16 @@ void HttpdAnalyze(struct sess *sp) { - const char *p, *q; + char *p, *q, *r; sp->handling = HND_Unclass; /* First, isolate and possibly identify request type */ - p = sp->req_b = sp->rcv; - for (q = p; isalpha(*q); q++) + sp->req_b = sp->rcv; + for (p = sp->rcv; isalpha(*p); p++) ; - p = sp->req_e = q; - VSLR(SLT_Request, sp->fd, sp->req_b, sp->req_e); + VSLR(SLT_Request, sp->fd, sp->req_b, p); + *p++ = '\0'; /* Next find the URI */ while (isspace(*p)) @@ -32,29 +34,54 @@ sp->url_b = p; while (!isspace(*p)) p++; - sp->url_e = p; - VSLR(SLT_URL, sp->fd, sp->url_b, sp->url_e); + VSLR(SLT_URL, sp->fd, sp->url_b, p); + *p++ = '\0'; /* Finally, look for protocol, if any */ while (isspace(*p) && *p != '\n') p++; - sp->proto_b = sp->proto_e = p; + sp->proto_b = p; if (*p != '\n') { while (!isspace(*p)) p++; - sp->proto_e = p; } - VSLR(SLT_Protocol, sp->fd, sp->proto_b, sp->proto_e); + VSLR(SLT_Protocol, sp->fd, sp->proto_b, p); + *p++ = '\0'; - /* - * And mark the start of headers. The end of headers - * is already set in acceptor where we detected the complete request. - */ - while (*p != '\n') + while (isspace(*p) && *p != '\n') p++; + p++; - while (isspace(*p) && *p != '\n') + if (*p == '\r') p++; - sp->hdr_b = p; - VSLR(SLT_Headers, sp->fd, sp->hdr_b, sp->hdr_e); + +#define HTTPH(a, b) sp->b = NULL; +#include "http_headers.h" +#undef HTTPH + + for (; p < sp->rcv + sp->rcv_len; p = r) { + q = strchr(p, '\n'); + r = q + 1; + if (q > p && q[-1] == '\r') + q--; + *q = '\0'; + if (p == q) + break; + +#define W(a, b, p, q, sp) \ + if (!strncasecmp(p, a, strlen(a))) { \ + for (p += strlen(a); p < q && isspace(*p); p++) \ + continue; \ + sp->b = p; \ + VSLR(SLT_##b, sp->fd, p, q); \ + continue; \ + } + +#define HTTPH(a, b) W(a ":", b, p, q, sp) +#include "http_headers.h" +#undef HTTPH +#undef W + VSLR(SLT_H_Unknown, sp->fd, p, q); + } + } Modified: trunk/varnish-cache/include/vcl_lang.h =================================================================== --- trunk/varnish-cache/include/vcl_lang.h 2006-03-31 08:26:23 UTC (rev 91) +++ trunk/varnish-cache/include/vcl_lang.h 2006-03-31 08:27:08 UTC (rev 92) @@ -5,8 +5,8 @@ * XXX: *MUST* be rerun. */ +/* XXX: This include is bad. The VCL compiler shouldn't know about it. */ #include -#include struct vcl_ref { unsigned line; @@ -35,13 +35,11 @@ /* HTTP request info, points into rcv */ const char *req_b; - const char *req_e; const char *url_b; - const char *url_e; const char *proto_b; - const char *proto_e; - const char *hdr_b; - const char *hdr_e; +#define HTTPH(a, b) const char *b; +#include +#undef HTTPH enum { HND_Unclass, Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-31 08:26:23 UTC (rev 91) +++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-03-31 08:27:08 UTC (rev 92) @@ -386,8 +386,8 @@ fputs(" * XXX: *MUST* be rerun.\n", f); fputs(" */\n", f); fputs("\n", f); + fputs("/* XXX: This include is bad. The VCL compiler shouldn't know about it. */\n", f); fputs("#include \n", f); - fputs("#include \n", f); fputs("\n", f); fputs("struct vcl_ref {\n", f); fputs(" unsigned line;\n", f); @@ -416,14 +416,36 @@ fputs("\n", f); fputs(" /* HTTP request info, points into rcv */\n", f); fputs(" const char *req_b;\n", f); - fputs(" const char *req_e;\n", f); fputs(" const char *url_b;\n", f); - fputs(" const char *url_e;\n", f); fputs(" const char *proto_b;\n", f); - fputs(" const char *proto_e;\n", f); - fputs(" const char *hdr_b;\n", f); - fputs(" const char *hdr_e;\n", f); + fputs("#define HTTPH(a, b) const char *b;\n", f); + fputs("/*\n", f); + fputs(" * $Id$\n", f); + fputs(" */\n", f); fputs("\n", f); + fputs("HTTPH(\"Accept-Charset\", H_Accept_Charset)\n", f); + fputs("HTTPH(\"Accept-Encoding\", H_Accept_Encoding)\n", f); + fputs("HTTPH(\"Accept-Language\", H_Accept_Language)\n", f); + fputs("HTTPH(\"Accept\", H_Accept)\n", f); + fputs("HTTPH(\"Authorization\", H_Authorization)\n", f); + fputs("HTTPH(\"Connection\", H_Connection)\n", f); + fputs("HTTPH(\"Expect\", H_Expect)\n", f); + fputs("HTTPH(\"From\", H_From)\n", f); + fputs("HTTPH(\"Host\", H_Host)\n", f); + fputs("HTTPH(\"If-Match\", H_If_Match)\n", f); + fputs("HTTPH(\"If-Modified-Since\", H_If_Modified_Since)\n", f); + fputs("HTTPH(\"If-None-Match\", H_If_None_Match)\n", f); + fputs("HTTPH(\"If-Range\", H_If_Range)\n", f); + fputs("HTTPH(\"If-Unmodified-Since\", H_If_Unmodifed_Since)\n", f); + fputs("HTTPH(\"Keep-Alive\", H_Keep_Alive)\n", f); + fputs("HTTPH(\"Max-Forwards\", H_Max_Forwards)\n", f); + fputs("HTTPH(\"Proxy-Authorization\", H_Proxy_Authorization)\n", f); + fputs("HTTPH(\"Range\", H_Range)\n", f); + fputs("HTTPH(\"Referer\", H_Referer)\n", f); + fputs("HTTPH(\"TE\", H_TE)\n", f); + fputs("HTTPH(\"User-Agent\", H_User_Agent)\n", f); + fputs("#undef HTTPH\n", f); + fputs("\n", f); fputs(" enum {\n", f); fputs(" HND_Unclass,\n", f); fputs(" HND_Handle,\n", f); Modified: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-31 08:26:23 UTC (rev 91) +++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-03-31 08:27:08 UTC (rev 92) @@ -180,6 +180,16 @@ puts $fo "vcl_output_lang_h(FILE *f)" puts $fo "{" while {[gets $fi a] >= 0} { + if {"$a" == "#include "} { + puts "FOO $a" + set fx [open "../../include/http_headers.h"] + while {[gets $fx b] >= 0} { + regsub -all {"} $b {\"} b + puts $fo "\tfputs(\"$b\\n\", f);" + } + close $fx + continue + } puts $fo "\tfputs(\"$a\\n\", f);" } puts $fo "}"