Module Name:    src
Committed By:   christos
Date:           Sat Nov  7 23:09:20 UTC 2015

Modified Files:
        src/lib/libc/rpc: rpc_internal.h svc_fdset.c svc_run.c svc_vc.c

Log Message:
PR/50408: Pedro Giffuni: Provide a way for rpc to use poll(2) instead of
select(2), and the linux svc_pollfd and svc_maxpollfd members. Our select(2)
implementation does not suffer from the FD_SETSIZE limitation so this is
not turned on by default.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/lib/libc/rpc/rpc_internal.h
cvs rdiff -u -r1.8 -r1.9 src/lib/libc/rpc/svc_fdset.c
cvs rdiff -u -r1.24 -r1.25 src/lib/libc/rpc/svc_run.c
cvs rdiff -u -r1.32 -r1.33 src/lib/libc/rpc/svc_vc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/rpc/rpc_internal.h
diff -u src/lib/libc/rpc/rpc_internal.h:1.7 src/lib/libc/rpc/rpc_internal.h:1.8
--- src/lib/libc/rpc/rpc_internal.h:1.7	Tue May  7 17:08:45 2013
+++ src/lib/libc/rpc/rpc_internal.h	Sat Nov  7 18:09:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: rpc_internal.h,v 1.7 2013/05/07 21:08:45 christos Exp $	*/
+/*	$NetBSD: rpc_internal.h,v 1.8 2015/11/07 23:09:20 christos Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -63,5 +63,6 @@ u_int32_t __rpc_getxid(void);
 
 extern SVCXPRT **__svc_xports;
 extern int __svc_maxrec;
+extern int __svc_flags;
 
 int __clnt_sigfillset(sigset_t *);

Index: src/lib/libc/rpc/svc_fdset.c
diff -u src/lib/libc/rpc/svc_fdset.c:1.8 src/lib/libc/rpc/svc_fdset.c:1.9
--- src/lib/libc/rpc/svc_fdset.c:1.8	Sat Nov  7 15:24:00 2015
+++ src/lib/libc/rpc/svc_fdset.c	Sat Nov  7 18:09:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: svc_fdset.c,v 1.8 2015/11/07 20:24:00 christos Exp $	*/
+/*	$NetBSD: svc_fdset.c,v 1.9 2015/11/07 23:09:20 christos Exp $	*/
 
 /*-
  * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: svc_fdset.c,v 1.8 2015/11/07 20:24:00 christos Exp $");
+__RCSID("$NetBSD: svc_fdset.c,v 1.9 2015/11/07 23:09:20 christos Exp $");
 
 
 #include "reentrant.h"
@@ -47,6 +47,7 @@ __RCSID("$NetBSD: svc_fdset.c,v 1.8 2015
 #endif
 #include <stdlib.h>
 #include <string.h>
+#include <poll.h>
 
 #include "svc_fdset.h"
 
@@ -54,11 +55,17 @@ __RCSID("$NetBSD: svc_fdset.c,v 1.8 2015
 #undef svc_maxfd
 extern __fd_set_256 svc_fdset;
 extern int svc_maxfd;
+int __svc_flags;
 
 struct svc_fdset {
+	/* select */
 	fd_set *fdset;
 	int	fdmax;
 	int	fdsize;
+	/* poll */
+	struct pollfd *fdp;
+	int	fdnum;
+	int	fdused;
 };
 
 /* The single threaded, one global fd_set version */
@@ -138,10 +145,85 @@ svc_fdset_free(void *v)
 	struct svc_fdset *fds = v;
 	DPRINTF_FDSET(fds, "free");
 
+	free(fds->fdp);
 	free(fds->fdset);
 	free(fds);
 }
 
+static void
+svc_pollfd_init(struct pollfd *pfd, int nfd)
+{
+	for (int i = 0; i < nfd; i++) {
+		pfd[i].fd = -1;
+		pfd[i].events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
+	}
+}
+
+static struct pollfd *
+svc_pollfd_alloc(struct svc_fdset *fds)
+{
+	fds->fdnum = FD_SETSIZE;
+	fds->fdp = calloc(fds->fdnum, sizeof(*fds->fdp));
+	if (fds->fdp == NULL)
+		return NULL;
+	svc_pollfd_init(fds->fdp, fds->fdnum);
+	return fds->fdp;
+}
+
+
+static struct svc_fdset *
+svc_pollfd_add(int fd, struct svc_fdset *fds)
+{
+	struct pollfd *pfd;
+
+	if ((pfd = svc_pollfd_alloc(fds)) == NULL)
+		return NULL;
+
+	for (int i = 0; i < fds->fdnum; i++)
+		if (pfd[i].fd == -1) {
+			if (i > fds->fdused)
+				fds->fdused = i + 1;
+			pfd[i].fd = fd;
+			return fds;
+		}
+
+	pfd = realloc(fds->fdp, (fds->fdnum + FD_SETSIZE) * sizeof(*fds->fdp));
+	if (pfd == NULL)
+		return NULL;
+
+	svc_pollfd_init(pfd + fds->fdnum, FD_SETSIZE);
+	pfd[fds->fdnum].fd = fd;
+	fds->fdused = fds->fdnum + 1;
+	fds->fdnum += FD_SETSIZE;
+	return fds;
+}
+
+static struct svc_fdset *
+svc_pollfd_del(int fd, struct svc_fdset *fds)
+{
+	struct pollfd *pfd;
+
+	if ((pfd = svc_pollfd_alloc(fds)) == NULL)
+		return NULL;
+
+	for (int i = 0; i < fds->fdnum; i++) {
+		if (pfd[i].fd != fd)
+			continue;
+
+		pfd[i].fd = -1;
+		if (i != fds->fdused - 1)
+			return fds;
+
+		do
+			if (pfd[i].fd != -1) 
+				break;
+		while (--i >= 0);
+		fds->fdused = i + 1;
+		return fds;
+	}
+	return NULL;
+}
+
 static struct svc_fdset *
 svc_fdset_resize(int fd, struct svc_fdset *fds)
 {
@@ -206,6 +288,7 @@ void
 svc_fdset_init(int flags)
 {
 	DPRINTF("%x", flags);
+	__svc_flags = flags;
 	if ((flags & SVC_FDSET_MT) && fdsetkey == -2)
 		fdsetkey = -1;
 }
@@ -214,9 +297,14 @@ void
 svc_fdset_zero(void)
 {
 	DPRINTF("zero");
+
 	struct svc_fdset *fds = svc_fdset_alloc(0);
 	memset(fds->fdset, 0, fds->fdsize);
 	fds->fdmax = -1;
+
+	free(fds->fdp);
+	fds->fdp = NULL;
+	fds->fdnum = fds->fdused = 0;
 }
 
 int
@@ -234,7 +322,7 @@ svc_fdset_set(int fd)
 	DPRINTF_FDSET(fds, "%d", fd);
 
 	svc_fdset_sanitize(fds);
-	return 0;
+	return svc_pollfd_add(fd, fds) ? 0 : -1;
 }
 
 int
@@ -262,7 +350,7 @@ svc_fdset_clr(int fd)
 	DPRINTF_FDSET(fds, "%d", fd);
 
 	svc_fdset_sanitize(fds);
-	return 0;
+	return svc_pollfd_del(fd, fds) ? 0 : -1;
 }
 
 fd_set *
@@ -314,3 +402,49 @@ svc_fdset_getsize(int fd)
 	DPRINTF_FDSET(fds, "getsize");
 	return fds->fdsize;
 }
+
+struct pollfd *
+svc_pollfd_copy(const struct pollfd *orig)
+{
+	int size = svc_fdset_getsize(0);
+	struct pollfd *copy = calloc(size, sizeof(*orig));
+	if (copy == NULL)
+		return NULL;
+	if (orig)
+		memcpy(copy, orig, size * sizeof(*orig));
+	return copy;
+}
+
+struct pollfd *
+svc_pollfd_get(void)
+{
+	struct svc_fdset *fds = svc_fdset_alloc(0);
+
+	if (fds == NULL)
+		return NULL;
+
+	DPRINTF_FDSET(fds, "getpoll");
+	return fds->fdp;
+}
+
+int *
+svc_pollfd_getmax(void)
+{
+	struct svc_fdset *fds = svc_fdset_alloc(0);
+
+	if (fds == NULL)
+		return NULL;
+	return &fds->fdused;
+}
+
+int
+svc_pollfd_getsize(int fd)
+{
+	struct svc_fdset *fds = svc_fdset_alloc(fd);
+
+	if (fds == NULL)
+		return -1;
+
+	DPRINTF_FDSET(fds, "getsize");
+	return fds->fdnum;
+}

Index: src/lib/libc/rpc/svc_run.c
diff -u src/lib/libc/rpc/svc_run.c:1.24 src/lib/libc/rpc/svc_run.c:1.25
--- src/lib/libc/rpc/svc_run.c:1.24	Sat Nov  7 12:34:33 2015
+++ src/lib/libc/rpc/svc_run.c	Sat Nov  7 18:09:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: svc_run.c,v 1.24 2015/11/07 17:34:33 christos Exp $	*/
+/*	$NetBSD: svc_run.c,v 1.25 2015/11/07 23:09:20 christos Exp $	*/
 
 /*
  * Copyright (c) 2010, Oracle America, Inc.
@@ -37,7 +37,7 @@
 static char *sccsid = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";
 static char *sccsid = "@(#)svc_run.c	2.1 88/07/29 4.0 RPCSRC";
 #else
-__RCSID("$NetBSD: svc_run.c,v 1.24 2015/11/07 17:34:33 christos Exp $");
+__RCSID("$NetBSD: svc_run.c,v 1.25 2015/11/07 23:09:20 christos Exp $");
 #endif
 #endif
 
@@ -53,6 +53,7 @@ __RCSID("$NetBSD: svc_run.c,v 1.24 2015/
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <poll.h>
 
 #include <rpc/rpc.h>
 
@@ -64,10 +65,10 @@ __weak_alias(svc_run,_svc_run)
 __weak_alias(svc_exit,_svc_exit)
 #endif
 
-void
-svc_run(void)
+static void
+svc_run_select(void)
 {
-	fd_set *readfds, *cleanfds;
+	fd_set *readfds;
 	struct timeval timeout;
 	int *maxfd, fdsize;
 #ifndef RUMP_RPC		
@@ -78,27 +79,97 @@ svc_run(void)
 #endif
 
 	readfds = NULL;
-	cleanfds = NULL;
 	fdsize = 0;
 	timeout.tv_sec = 30;
 	timeout.tv_usec = 0;
 
 	for (;;) {
 		rwlock_rdlock(&svc_fd_lock);
+
+		maxfd = svc_fdset_getmax();
+		if (maxfd == NULL) {
+			warn("%s: can't get maxfd", __func__);
+			goto out;
+		}
+
 		if (fdsize != svc_fdset_getsize(0)) {
 			fdsize = svc_fdset_getsize(0);
 			free(readfds);
 			readfds = svc_fdset_copy(svc_fdset_get());
-			free(cleanfds);
-			cleanfds = svc_fdset_copy(svc_fdset_get());
+			if (readfds == NULL) {
+				warn("%s: can't copy fdset", __func__);
+				goto out;
+			}
+		} else
+			memcpy(readfds, svc_fdset_get(), __NFD_BYTES(fdsize));
+
+		rwlock_unlock(&svc_fd_lock);
+
+		switch (select(*maxfd + 1, readfds, NULL, NULL, &timeout)) {
+		case -1:
+#ifndef RUMP_RPC		
+			if ((errno == EINTR || errno == EBADF) && probs < 100) {
+				probs++;
+				continue;
+			}
+#endif
+			if (errno == EINTR) {
+				continue;
+			}
+			warn("%s: select failed", __func__);
+			goto out;
+		case 0:
+			__svc_clean_idle(NULL, 30, FALSE);
+			continue;
+		default:
+			svc_getreqset2(readfds, fdsize);
+#ifndef RUMP_RPC
+			probs = 0;
+#endif
 		}
-		maxfd = svc_fdset_getmax();
+	}
+out:
+	free(readfds);
+}
+
+static void
+svc_run_poll(void)
+{
+	struct pollfd *pfd;
+	int *maxfd, fdsize, i;
+#ifndef RUMP_RPC		
+	int probs = 0;
+#endif
+#ifdef _REENTRANT
+	extern rwlock_t svc_fd_lock;
+#endif
+
+	fdsize = 0;
+	pfd = NULL;
+
+	for (;;) {
+		rwlock_rdlock(&svc_fd_lock);
+
+		maxfd = svc_pollfd_getmax();
 		if (maxfd == NULL) {
 			warn("can't get maxfd");
-			continue;
+			goto out;
 		}
+
+		if (fdsize != svc_pollfd_getsize(0)) {
+			fdsize = svc_fdset_getsize(0);
+			free(pfd);
+			pfd = svc_pollfd_copy(svc_pollfd_get());
+			if (pfd == NULL) {
+				warn("can't get pollfd");
+				goto out;
+			}
+		} else
+			memcpy(pfd, svc_pollfd_get(), *maxfd * sizeof(*pfd));
+
 		rwlock_unlock(&svc_fd_lock);
-		switch (select(*maxfd + 1, readfds, NULL, NULL, &timeout)) {
+
+		switch ((i = poll(pfd, *maxfd, 30 * 1000))) {
 		case -1:
 #ifndef RUMP_RPC		
 			if ((errno == EINTR || errno == EBADF) && probs < 100) {
@@ -109,23 +180,26 @@ svc_run(void)
 			if (errno == EINTR) {
 				continue;
 			}
-			warn("%s: select failed", __func__);
+			warn("%s: poll failed", __func__);
 			goto out;
 		case 0:
-			if (cleanfds)
-				__svc_clean_idle(cleanfds, 30, FALSE);
+			__svc_clean_idle(NULL, 30, FALSE);
 			continue;
 		default:
-			if (readfds)
-				svc_getreqset2(readfds, fdsize);
+			svc_getreq_poll(pfd, i);
 #ifndef RUMP_RPC
 			probs = 0;
 #endif
 		}
 	}
 out:
-	free(readfds);
-	free(cleanfds);
+	free(pfd);
+}
+
+void
+svc_run(void)
+{
+	(__svc_flags & SVC_FDSET_POLL) ? svc_run_poll() : svc_run_select();
 }
 
 /*

Index: src/lib/libc/rpc/svc_vc.c
diff -u src/lib/libc/rpc/svc_vc.c:1.32 src/lib/libc/rpc/svc_vc.c:1.33
--- src/lib/libc/rpc/svc_vc.c:1.32	Sat Nov  7 12:34:33 2015
+++ src/lib/libc/rpc/svc_vc.c	Sat Nov  7 18:09:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: svc_vc.c,v 1.32 2015/11/07 17:34:33 christos Exp $	*/
+/*	$NetBSD: svc_vc.c,v 1.33 2015/11/07 23:09:20 christos Exp $	*/
 
 /*
  * Copyright (c) 2010, Oracle America, Inc.
@@ -37,7 +37,7 @@
 static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
 static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
 #else
-__RCSID("$NetBSD: svc_vc.c,v 1.32 2015/11/07 17:34:33 christos Exp $");
+__RCSID("$NetBSD: svc_vc.c,v 1.33 2015/11/07 23:09:20 christos Exp $");
 #endif
 #endif
 
@@ -328,12 +328,7 @@ again:
 		 * running out.
 		 */
 		if (errno == EMFILE || errno == ENFILE) {
-			fd_set *cleanfds = svc_fdset_copy(svc_fdset_get());
-			int rv = 0;
-			if (cleanfds)
-				rv = __svc_clean_idle(cleanfds, 0, FALSE);
-			free(cleanfds);
-			if (rv)
+			if (__svc_clean_idle(NULL, 0, FALSE))
 				goto again;
 		}
 		return FALSE;
@@ -761,7 +756,7 @@ svc_vc_rendezvous_ops(SVCXPRT *xprt)
  * cleaned. If timeout is 0, the least active connection is picked.
  */
 bool_t
-__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
+__svc_clean_idle(fd_set *fds __unused, int timeout, bool_t cleanblock)
 {
 	int i, ncleaned, *fdmax;
 	SVCXPRT *xprt, *least_active;

Reply via email to