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;