Index: configure.ac
===================================================================
--- configure.ac	(revision 3095)
+++ configure.ac	(working copy)
@@ -22,6 +22,9 @@
 AC_CHECK_PROGS(XSLTPROC, [xsltproc])
 
 # Checks for libraries.
+
+AC_CHECK_LIB(umem, malloc)
+
 save_LIBS="${LIBS}"
 LIBS=""
 AC_CHECK_LIB(rt, clock_gettime)
@@ -59,6 +62,7 @@
 LIBS=""
 AC_CHECK_LIB(socket, socket)
 AC_CHECK_LIB(nsl, getaddrinfo)
+AC_CHECK_LIB(sendfile, sendfile)
 NET_LIBS="${LIBS}"
 LIBS="${save_LIBS}"
 AC_SUBST(NET_LIBS)
@@ -74,12 +78,14 @@
 AC_CHECK_HEADERS([sys/mount.h])
 AC_CHECK_HEADERS([sys/statvfs.h])
 AC_CHECK_HEADERS([sys/vfs.h])
+AC_CHECK_HEADERS([sys/filio.h])
 AC_CHECK_HEADERS([netinet/in.h])
 AC_CHECK_HEADERS([pthread_np.h])
 AC_CHECK_HEADERS([stddef.h])
 AC_CHECK_HEADERS([stdlib.h])
 AC_CHECK_HEADERS([unistd.h])
 AC_CHECK_HEADERS([vis.h])
+AC_CHECK_HEADERS([umem.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -129,6 +135,15 @@
 	   AC_DEFINE([SENDFILE_WORKS], [1], [Define if SENDFILE works])
 	fi
  	;;
+*-*-solaris*)
+	if test "$ac_cv_lib_sendfile_sendfile" = yes; then
+		save_LIBS="${LIBS}"
+		LIBS="${NET_LIBS}"
+		AC_CHECK_FUNCS([sendfile])
+		AC_CHECK_FUNCS([sendfilev])
+		LIBS="${save_LIBS}"
+	fi
+	;;
 *)
 	AC_MSG_WARN([won't look for sendfile() on $host])
 	;;
@@ -204,9 +219,23 @@
 	ac_cv_func_poll=no
 fi
 
+# --enable-ports
+AC_ARG_ENABLE(ports,
+    AS_HELP_STRING([--enable-ports],
+	[use ports if available (default is YES)]),
+    ,
+    [enable_ports=yes])
+
+if test "$enable_ports" = yes; then
+	AC_CHECK_FUNCS([port_create])
+else
+	ac_cv_func_port_create=no
+fi
+
 if test "$ac_cv_func_kqueue" != yes &&
    test "$ac_cv_func_epoll_ctl" != yes &&
-   test "$ac_cv_func_poll" != yes; then
+   test "$ac_cv_func_poll" != yes &&
+   test "$ac_cv_func_port_create" != yes; then
 	AC_MSG_ERROR([no usable acceptor mechanism])
 fi
 
Index: bin/varnishd/tcp.c
===================================================================
--- bin/varnishd/tcp.c	(revision 3095)
+++ bin/varnishd/tcp.c	(working copy)
@@ -38,6 +38,9 @@
 
 #include <errno.h>
 #include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 #include <netdb.h>
 #include <poll.h>
 #include <stdio.h>
Index: bin/varnishd/cache_acceptor_ports.c
===================================================================
--- bin/varnishd/cache_acceptor_ports.c	(revision 0)
+++ bin/varnishd/cache_acceptor_ports.c	(revision 0)
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * Copyright (c) 2007 OmniTI Computer Consulting, Inc.
+ * Copyright (c) 2007 Theo Schlossnagle
+ * 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 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 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$
+ *
+ * XXX: We need to pass sessions back into the event engine when they are
+ * reused.  Not sure what the most efficient way is for that.  For now
+ * write the session pointer to a pipe which the event engine monitors.
+ */
+
+#include "config.h"
+#if defined(HAVE_PORT_CREATE)
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <port.h>
+
+#ifndef HAVE_CLOCK_GETTIME
+#include "compat/clock_gettime.h"
+#endif
+
+#include "shmlog.h"
+#include "cache.h"
+#include "cache_acceptor.h"
+
+#define MAX_EVENTS 256
+static pthread_t vca_ports_thread;
+int solaris_dport = -1;
+
+static VTAILQ_HEAD(,sess) sesshead = VTAILQ_HEAD_INITIALIZER(sesshead);
+
+static void
+vca_add(int fd, void *data)
+{
+	AZ(port_associate(solaris_dport, PORT_SOURCE_FD, fd, POLLIN | POLLERR | POLLPRI, data));
+}
+
+static void
+vca_del(int fd)
+{
+	port_dissociate(solaris_dport, PORT_SOURCE_FD, fd);
+}
+
+static void
+vca_port_ev(port_event_t *ev) {
+	struct sess *sp;
+	if(ev->portev_source == PORT_SOURCE_USER) {
+		sp = ev->portev_user;
+		CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+		assert(sp->fd >= 0);
+		AZ(sp->obj);
+		VTAILQ_INSERT_TAIL(&sesshead, sp, list);
+		vca_add(sp->fd, sp);
+	} else {
+		int i;
+		CAST_OBJ_NOTNULL(sp, ev->portev_user, SESS_MAGIC);
+		if(ev->portev_events & POLLERR) {
+			VTAILQ_REMOVE(&sesshead, sp, list);
+			vca_close_session(sp, "EOF");
+			SES_Delete(sp);
+			return;
+		}
+		i = HTC_Rx(sp->htc);
+		if (i == 0)
+			return;
+		if (i > 0) {
+			VTAILQ_REMOVE(&sesshead, sp, list);
+			if (sp->fd != -1)
+				vca_del(sp->fd);
+			vca_handover(sp, i);
+		}
+	}
+	return;
+}
+
+static void *
+vca_main(void *arg)
+{
+	struct sess *sp;
+
+	(void)arg;
+
+	solaris_dport = port_create();
+	assert(solaris_dport >= 0);
+
+	while (1) {
+		port_event_t ev[MAX_EVENTS];
+		int nevents, ei;
+		double deadline;
+		struct timespec ts;
+		ts.tv_sec = 0L;
+		ts.tv_nsec = 50L /*ms*/  * 1000L /*us*/  * 1000L /*ns*/;
+		nevents = 1;
+		if (port_getn(solaris_dport, ev, MAX_EVENTS, &nevents, &ts) == 0) {
+			for (ei=0; ei<nevents; ei++) {
+				vca_port_ev(ev + ei);
+			}
+		}
+		/* check for timeouts */
+		deadline = TIM_real() - params->sess_timeout;
+		for (;;) {
+			sp = VTAILQ_FIRST(&sesshead);
+			if (sp == NULL)
+				break;
+			if (sp->t_open > deadline)
+				break;
+			VTAILQ_REMOVE(&sesshead, sp, list);
+			if(sp->fd != -1)
+				vca_del(sp->fd);
+			vca_close_session(sp, "timeout");
+			SES_Delete(sp);
+		}
+	}
+}
+
+static void
+vca_ports_pass(struct sess *sp)
+{
+	int r;
+	while((r = port_send(solaris_dport, 0, sp)) == -1 &&
+		errno == EAGAIN);
+	AZ(r);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+vca_ports_init(void)
+{
+
+	AZ(pthread_create(&vca_ports_thread, NULL, vca_main, NULL));
+}
+
+struct acceptor acceptor_ports = {
+	.name =		"ports",
+	.init =		vca_ports_init,
+	.pass =		vca_ports_pass
+};
+
+#endif /* defined(HAVE_PORT_CREATE) */
Index: bin/varnishd/varnishd.c
===================================================================
--- bin/varnishd/varnishd.c	(revision 3095)
+++ bin/varnishd/varnishd.c	(working copy)
@@ -113,10 +113,16 @@
 /*--------------------------------------------------------------------*/
 extern struct stevedore sma_stevedore;
 extern struct stevedore smf_stevedore;
+#ifdef HAVE_LIBUMEM
+extern struct stevedore smu_stevedore;
+#endif
 
 static struct choice stv_choice[] = {
 	{ "file",	&smf_stevedore },
 	{ "malloc",	&sma_stevedore },
+#ifdef HAVE_LIBUMEM
+	{ "umem",	&smu_stevedore },
+#endif
 	{ NULL,		NULL }
 };
 
@@ -214,6 +220,9 @@
 	fprintf(stderr, FMT,
 	    "-s kind[,storageoptions]", "Backend storage specification");
 	fprintf(stderr, FMT, "", "  -s malloc");
+#ifdef HAVE_LIBUMEM
+	fprintf(stderr, FMT, "", "  -s umem");
+#endif
 	fprintf(stderr, FMT, "", "  -s file  [default: use /tmp]");
 	fprintf(stderr, FMT, "", "  -s file,<dir_or_file>");
 	fprintf(stderr, FMT, "", "  -s file,<dir_or_file>,<size>");
Index: bin/varnishd/storage_umem.c
===================================================================
--- bin/varnishd/storage_umem.c	(revision 0)
+++ bin/varnishd/storage_umem.c	(revision 0)
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * 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 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: storage_umem.c 3036 2008-07-31 09:24:25Z phk $
+ *
+ * Storage method based on umem_alloc(3MALLOC)
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#ifdef HAVE_UMEM_H
+#include <umem.h>
+
+#include "config.h"
+#include "shmlog.h"
+#include "cache.h"
+#include "stevedore.h"
+
+static size_t			smu_max = SIZE_MAX;
+static MTX			smu_mtx;
+
+struct smu {
+	struct storage		s;
+	size_t			sz;
+};
+
+static struct storage *
+smu_alloc(struct stevedore *st, size_t size)
+{
+	struct smu *smu;
+
+	LOCK(&smu_mtx);
+	VSL_stats->sma_nreq++;
+	if (VSL_stats->sma_nbytes + size > smu_max)
+		size = 0;
+	else {
+		VSL_stats->sma_nobj++;
+		VSL_stats->sma_nbytes += size;
+		VSL_stats->sma_balloc += size;
+	}
+	UNLOCK(&smu_mtx);
+
+	if (size == 0)
+		return (NULL);
+
+	smu = umem_zalloc(sizeof *smu, UMEM_DEFAULT);
+	if (smu == NULL)
+		return (NULL);
+	smu->sz = size;
+	smu->s.priv = smu;
+	smu->s.ptr = umem_alloc(size, UMEM_DEFAULT);
+	XXXAN(smu->s.ptr);
+	smu->s.len = 0;
+	smu->s.space = size;
+	smu->s.fd = -1;
+	smu->s.stevedore = st;
+	smu->s.magic = STORAGE_MAGIC;
+	return (&smu->s);
+}
+
+/*lint -e{818} not const-able */
+static void
+smu_free(struct storage *s)
+{
+	struct smu *smu;
+
+	CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
+	smu = s->priv;
+	assert(smu->sz == smu->s.space);
+	LOCK(&smu_mtx);
+	VSL_stats->sma_nobj--;
+	VSL_stats->sma_nbytes -= smu->sz;
+	VSL_stats->sma_bfree += smu->sz;
+	UNLOCK(&smu_mtx);
+	umem_free(smu->s.ptr, smu->s.space);
+	umem_free(smu, sizeof *smu);
+}
+
+static void
+smu_trim(const struct storage *s, size_t size)
+{
+	struct smu *smu;
+	void *p;
+
+	CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
+	smu = s->priv;
+	assert(smu->sz == smu->s.space);
+	if ((p = umem_alloc(size, UMEM_DEFAULT)) != NULL) {
+		memcpy(p, smu->s.ptr, size);
+		umem_free(smu->s.ptr, smu->s.space);
+		LOCK(&smu_mtx);
+		VSL_stats->sma_nbytes -= (smu->sz - size);
+		VSL_stats->sma_bfree += smu->sz - size;
+		smu->sz = size;
+		UNLOCK(&smu_mtx);
+		smu->s.ptr = p;
+		smu->s.space = size;
+	}
+}
+
+static void
+smu_init(struct stevedore *parent, int ac, char * const *av)
+{
+	const char *e;
+	uintmax_t u;
+
+	(void)parent;
+
+	AZ(av[ac]);
+	if (ac > 1) 
+		ARGV_ERR("(-sumem) too many arguments\n");
+
+	if (ac == 0 || *av[0] == '\0')
+		 return;
+
+	e = str2bytes(av[0], &u, 0);
+	if (e != NULL)
+		ARGV_ERR("(-sumem) size \"%s\": %s\n", av[0], e);
+	if ((u != (uintmax_t)(size_t)u)) 
+		ARGV_ERR("(-sumem) size \"%s\": too big\n", av[0]);
+	smu_max = u;
+}
+
+static void
+smu_open(const struct stevedore *st)
+{
+	(void)st;
+	AZ(pthread_mutex_init(&smu_mtx, NULL));
+}
+
+struct stevedore smu_stevedore = {
+	.magic	=	STEVEDORE_MAGIC,
+	.name	=	"umem",
+	.init	=	smu_init,
+	.open	=	smu_open,
+	.alloc	=	smu_alloc,
+	.free	=	smu_free,
+	.trim	=	smu_trim,
+};
+
+#endif
Index: bin/varnishd/cache_pool.c
===================================================================
--- bin/varnishd/cache_pool.c	(revision 3095)
+++ bin/varnishd/cache_pool.c	(working copy)
@@ -52,6 +52,8 @@
 #include <sys/socket.h>
 #elif defined(__linux__)
 #include <sys/sendfile.h>
+#elif defined(__sun)
+#include <sys/sendfile.h>
 #else
 #error Unknown sendfile() implementation
 #endif
@@ -191,7 +193,38 @@
 		    sendfile(*w->wfd, fd, &off, len) != len)
 			w->werr++;
 	} while (0);
+#elif defined(__sun)
+#ifdef HAVE_SENDFILEV
+	do {
+		sendfilevec_t svvec[HTTP_HDR_MAX * 2 + 1];
+		size_t xferred = 0, expected = 0;
+		int i;
+		for (i = 0; i < w->niov; i++) {
+			svvec[i].sfv_fd = SFV_FD_SELF;
+			svvec[i].sfv_flag = 0;
+			svvec[i].sfv_off = (off_t) w->iov[i].iov_base;
+			svvec[i].sfv_len = w->iov[i].iov_len;
+			expected += svvec[i].sfv_len;
+		}
+		svvec[i].sfv_fd = fd;
+		svvec[i].sfv_flag = 0;
+		svvec[i].sfv_off = off;
+		svvec[i].sfv_len = len;
+		expected += svvec[i].sfv_len;
+		if (sendfilev(*w->wfd, svvec, i, &xferred) == -1 ||
+		    xferred != expected)
+			w->werr++;
+		w->liov = 0;
+		w->niov = 0;
+	} while (0);
 #else
+	do {
+		if (WRK_Flush(w) == 0 &&
+		    sendfile(*w->wfd, fd, &off, len) != len)
+			w->werr++;
+	} while (0);
+#endif
+#else
 #error Unknown sendfile() implementation
 #endif
 }
Index: bin/varnishd/cache_acceptor.c
===================================================================
--- bin/varnishd/cache_acceptor.c	(revision 3095)
+++ bin/varnishd/cache_acceptor.c	(working copy)
@@ -46,7 +46,6 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
-#include "config.h"
 #include "cli.h"
 #include "cli_priv.h"
 #include "shmlog.h"
@@ -60,6 +59,9 @@
 #if defined(HAVE_EPOLL_CTL)
 	&acceptor_epoll,
 #endif
+#if defined(HAVE_PORT_CREATE)
+	&acceptor_ports,
+#endif
 #if defined(HAVE_POLL)
 	&acceptor_poll,
 #endif
Index: bin/varnishd/cache_acceptor.h
===================================================================
--- bin/varnishd/cache_acceptor.h	(revision 3095)
+++ bin/varnishd/cache_acceptor.h	(working copy)
@@ -48,6 +48,10 @@
 extern struct acceptor acceptor_kqueue;
 #endif
 
+#if defined(HAVE_PORT_CREATE)
+extern struct acceptor acceptor_ports;
+#endif
+
 #if defined(HAVE_POLL)
 extern struct acceptor acceptor_poll;
 #endif
Index: bin/varnishd/Makefile.am
===================================================================
--- bin/varnishd/Makefile.am	(revision 3095)
+++ bin/varnishd/Makefile.am	(working copy)
@@ -11,6 +11,7 @@
 	cache_acceptor_epoll.c \
 	cache_acceptor_poll.c \
 	cache_acceptor_kqueue.c \
+	cache_acceptor_ports.c \
 	cache_backend.c \
 	cache_backend_cfg.c \
 	cache_backend_poll.c \
@@ -49,6 +50,7 @@
 	shmlog.c \
 	stevedore.c \
 	storage_file.c \
+	storage_umem.c \
 	storage_malloc.c \
 	storage_synth.c \
 	tcp.c \
