Home | History | Annotate | Line # | Download | only in rpc
svc_fdset.c revision 1.4
      1  1.4  christos /*	$NetBSD: svc_fdset.c,v 1.4 2015/11/06 23:11:09 christos Exp $	*/
      2  1.4  christos 
      3  1.4  christos /*-
      4  1.4  christos  * Copyright (c) 2015 The NetBSD Foundation, Inc.
      5  1.4  christos  * All rights resefdsed.
      6  1.4  christos  *
      7  1.4  christos  * This code is derived from software contributed to The NetBSD Foundation
      8  1.4  christos  * by Christos Zoulas.
      9  1.4  christos  *
     10  1.4  christos  * Redistribution and use in source and binary forms, with or without
     11  1.4  christos  * modification, are permitted provided that the following conditions
     12  1.4  christos  * are met:
     13  1.4  christos  * 1. Redistributions of source code must retain the above copyright
     14  1.4  christos  *    notice, this list of conditions and the following disclaimer.
     15  1.4  christos  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.4  christos  *    notice, this list of conditions and the following disclaimer in the
     17  1.4  christos  *    documentation and/or other materials provided with the distribution.
     18  1.4  christos  *
     19  1.4  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.4  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.4  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.4  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.4  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.4  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.4  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.4  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.4  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.4  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.4  christos  * POSSIBILITY OF SUCH DAMAGE.
     30  1.4  christos  */
     31  1.1  christos 
     32  1.1  christos #include <sys/cdefs.h>
     33  1.4  christos __RCSID("$NetBSD: svc_fdset.c,v 1.4 2015/11/06 23:11:09 christos Exp $");
     34  1.2  christos 
     35  1.2  christos 
     36  1.2  christos #include "reentrant.h"
     37  1.2  christos 
     38  1.2  christos #include <sys/fd_set.h>
     39  1.2  christos 
     40  1.2  christos #include <rpc/rpc.h>
     41  1.1  christos 
     42  1.1  christos #include <stdlib.h>
     43  1.1  christos #include <string.h>
     44  1.1  christos 
     45  1.4  christos #undef svc_fdset
     46  1.4  christos #undef svc_maxfd
     47  1.4  christos extern fd_set svc_fdset;
     48  1.4  christos extern int svc_maxfd;
     49  1.4  christos 
     50  1.4  christos struct svc_fdset {
     51  1.2  christos 	fd_set *fdset;
     52  1.2  christos 	int	fdmax;
     53  1.2  christos 	int	fdsize;
     54  1.2  christos };
     55  1.2  christos 
     56  1.2  christos /* The single threaded, one global fd_set version */
     57  1.4  christos static struct svc_fdset __svc_fdset;
     58  1.2  christos 
     59  1.2  christos static thread_key_t fdsetkey = -2;
     60  1.2  christos 
     61  1.2  christos #ifdef FDSET_DEBUG
     62  1.2  christos #include <stdio.h>
     63  1.2  christos #include <stdarg.h>
     64  1.2  christos #include <unistd.h>
     65  1.2  christos #include <lwp.h>
     66  1.2  christos 
     67  1.2  christos static void  __printflike(3, 0)
     68  1.2  christos svc_header(const char *func, size_t line, const char *fmt, va_list ap)
     69  1.2  christos {
     70  1.2  christos 	fprintf(stderr, "%s[%d.%d]: %s, %zu: ", getprogname(), (int)getpid(),
     71  1.2  christos 	    (int)_lwp_self(), func, line);
     72  1.2  christos 	vfprintf(stderr, fmt, ap);
     73  1.2  christos 	va_end(ap);
     74  1.2  christos }
     75  1.2  christos 
     76  1.4  christos static void __printflike(4, 5)
     77  1.4  christos svc_fdset_print(const char *func, size_t line, struct svc_fdset *fds,
     78  1.2  christos     const char *fmt, ...)
     79  1.2  christos {
     80  1.2  christos 	va_list ap;
     81  1.2  christos 	const char *did = "";
     82  1.2  christos 
     83  1.2  christos 	va_start(ap, fmt);
     84  1.2  christos 	svc_header(func, line, fmt, ap);
     85  1.2  christos 	va_end(ap);
     86  1.2  christos 
     87  1.4  christos 	fprintf(stderr, "%p[%d] <", fds->fdset, fds->fdmax);
     88  1.4  christos 	for (int i = 0; i <= fds->fdmax; i++) {
     89  1.4  christos 		if (!FD_ISSET(i, fds->fdset))
     90  1.2  christos 			continue;
     91  1.2  christos 		fprintf(stderr, "%s%d", did, i);
     92  1.2  christos 		did = ", ";
     93  1.2  christos 	}
     94  1.2  christos 	fprintf(stderr, ">\n");
     95  1.2  christos }
     96  1.2  christos 
     97  1.2  christos static void __printflike(3, 4)
     98  1.2  christos svc_print(const char *func, size_t line, const char *fmt, ...)
     99  1.2  christos {
    100  1.2  christos 	va_list ap;
    101  1.2  christos 
    102  1.2  christos 	va_start(ap, fmt);
    103  1.2  christos 	svc_header(func, line, fmt, ap);
    104  1.2  christos 	va_end(ap);
    105  1.2  christos 	fprintf(stderr, "\n");
    106  1.2  christos }
    107  1.2  christos 
    108  1.4  christos #define DPRINTF(...)		svc_print(__func__, __LINE__, __VA_ARGS__)
    109  1.2  christos #define DPRINTF_FDSET(...)	svc_fdset_print(__func__, __LINE__, __VA_ARGS__)
    110  1.4  christos 
    111  1.2  christos #else
    112  1.4  christos 
    113  1.4  christos #define DPRINTF(...)
    114  1.2  christos #define DPRINTF_FDSET(...)
    115  1.4  christos 
    116  1.2  christos #endif
    117  1.2  christos 
    118  1.2  christos 
    119  1.4  christos static inline void
    120  1.4  christos svc_fdset_sanitize(struct svc_fdset *fds)
    121  1.4  christos {
    122  1.4  christos 	while (fds->fdmax >= 0 && !FD_ISSET(fds->fdmax, fds->fdset))
    123  1.4  christos 		fds->fdmax--;
    124  1.4  christos 	/* Compat update */
    125  1.4  christos 	if (fds == &__svc_fdset) {
    126  1.4  christos 		svc_fdset = *__svc_fdset.fdset;
    127  1.4  christos 		svc_maxfd = __svc_fdset.fdmax;
    128  1.4  christos 	}
    129  1.4  christos }
    130  1.4  christos 
    131  1.2  christos static void
    132  1.2  christos svc_fdset_free(void *v)
    133  1.2  christos {
    134  1.4  christos 	struct svc_fdset *fds = v;
    135  1.4  christos 	DPRINTF_FDSET(fds, "free");
    136  1.2  christos 
    137  1.4  christos 	free(fds->fdset);
    138  1.4  christos 	free(fds);
    139  1.2  christos }
    140  1.2  christos 
    141  1.4  christos static struct svc_fdset *
    142  1.4  christos svc_fdset_resize(int fd, struct svc_fdset *fds)
    143  1.2  christos {
    144  1.4  christos 	if (fds->fdset && fd < fds->fdsize) {
    145  1.4  christos 		DPRINTF_FDSET(fds, "keeping %d < %d", fd, fds->fdsize);
    146  1.4  christos 		return fds;
    147  1.2  christos 	}
    148  1.2  christos 
    149  1.2  christos 	fd += FD_SETSIZE;
    150  1.2  christos 
    151  1.4  christos 	char *newfdset = realloc(fds->fdset, __NFD_BYTES(fd));
    152  1.2  christos 	if (newfdset == NULL)
    153  1.2  christos 		return NULL;
    154  1.2  christos 
    155  1.4  christos 	memset(newfdset + __NFD_BYTES(fds->fdsize), 0,
    156  1.4  christos 	    __NFD_BYTES(fd) - __NFD_BYTES(fds->fdsize));
    157  1.2  christos 
    158  1.2  christos 
    159  1.4  christos 	fds->fdset = (void *)newfdset;
    160  1.4  christos 	DPRINTF_FDSET(fds, "resize %d > %d", fd, fds->fdsize);
    161  1.4  christos 	fds->fdsize = fd;
    162  1.2  christos 
    163  1.4  christos 	return fds;
    164  1.2  christos }
    165  1.2  christos 
    166  1.4  christos static struct svc_fdset *
    167  1.2  christos svc_fdset_alloc(int fd)
    168  1.2  christos {
    169  1.4  christos 	struct svc_fdset *fds;
    170  1.2  christos 
    171  1.2  christos 	if (fdsetkey == -1)
    172  1.2  christos 		thr_keycreate(&fdsetkey, svc_fdset_free);
    173  1.2  christos 
    174  1.4  christos 	if ((fds = thr_getspecific(fdsetkey)) == NULL) {
    175  1.2  christos 
    176  1.4  christos 		fds = calloc(1, sizeof(*fds));
    177  1.4  christos 		if (fds == NULL)
    178  1.2  christos 			return NULL;
    179  1.2  christos 
    180  1.4  christos 		(void)thr_setspecific(fdsetkey, fds);
    181  1.2  christos 
    182  1.4  christos 		if (__svc_fdset.fdsize != 0) {
    183  1.4  christos 			*fds = __svc_fdset;
    184  1.4  christos 			DPRINTF("switching to %p", fds->fdset);
    185  1.2  christos 		} else {
    186  1.4  christos 			DPRINTF("first thread time %p", fds->fdset);
    187  1.2  christos 		}
    188  1.2  christos 	} else {
    189  1.4  christos 		DPRINTF("again for %p", fds->fdset);
    190  1.4  christos 		if (fd < fds->fdsize)
    191  1.4  christos 			return fds;
    192  1.2  christos 	}
    193  1.4  christos 
    194  1.4  christos 	return svc_fdset_resize(fd, fds);
    195  1.2  christos }
    196  1.2  christos 
    197  1.4  christos static struct svc_fdset *
    198  1.2  christos svc_fdset_get_internal(int fd)
    199  1.2  christos {
    200  1.2  christos 	if (!__isthreaded || fdsetkey == -2)
    201  1.4  christos 		return svc_fdset_resize(fd, &__svc_fdset);
    202  1.2  christos 
    203  1.4  christos 	return svc_fdset_alloc(fd);
    204  1.2  christos }
    205  1.2  christos 
    206  1.1  christos 
    207  1.2  christos /* allow each thread to have their own copy */
    208  1.2  christos void
    209  1.2  christos svc_fdset_init(int flags)
    210  1.2  christos {
    211  1.2  christos 	DPRINTF("%x", flags);
    212  1.2  christos 	if ((flags & SVC_FDSET_MT) && fdsetkey == -2)
    213  1.2  christos 		fdsetkey = -1;
    214  1.2  christos }
    215  1.1  christos 
    216  1.1  christos void
    217  1.2  christos svc_fdset_zero(void)
    218  1.1  christos {
    219  1.2  christos 	DPRINTF("zero");
    220  1.4  christos 	struct svc_fdset *fds = svc_fdset_get_internal(0);
    221  1.4  christos 	memset(fds->fdset, 0, fds->fdsize);
    222  1.4  christos 	fds->fdmax = 0;
    223  1.1  christos }
    224  1.1  christos 
    225  1.1  christos void
    226  1.2  christos svc_fdset_set(int fd)
    227  1.1  christos {
    228  1.4  christos 	struct svc_fdset *fds = svc_fdset_get_internal(fd);
    229  1.4  christos 	FD_SET(fd, fds->fdset);
    230  1.4  christos 	if (fd > fds->fdmax)
    231  1.4  christos 		fds->fdmax = fd;
    232  1.4  christos 	DPRINTF_FDSET(fds, "%d", fd);
    233  1.1  christos 
    234  1.4  christos 	svc_fdset_sanitize(fds);
    235  1.2  christos }
    236  1.2  christos 
    237  1.2  christos int
    238  1.2  christos svc_fdset_isset(int fd)
    239  1.2  christos {
    240  1.4  christos 	struct svc_fdset *fds = svc_fdset_get_internal(fd);
    241  1.4  christos 	svc_fdset_sanitize(fds);
    242  1.4  christos 	DPRINTF_FDSET(fds, "%d", fd);
    243  1.4  christos 	return FD_ISSET(fd, fds->fdset);
    244  1.2  christos }
    245  1.2  christos 
    246  1.2  christos void
    247  1.2  christos svc_fdset_clr(int fd)
    248  1.2  christos {
    249  1.4  christos 	struct svc_fdset *fds = svc_fdset_get_internal(fd);
    250  1.4  christos 	FD_CLR(fd, fds->fdset);
    251  1.4  christos 	svc_fdset_sanitize(fds);
    252  1.4  christos 	DPRINTF_FDSET(fds, "%d", fd);
    253  1.1  christos }
    254  1.1  christos 
    255  1.1  christos fd_set *
    256  1.2  christos svc_fdset_copy(const fd_set *orig)
    257  1.1  christos {
    258  1.4  christos 	int size = svc_fdset_getsize(0);
    259  1.4  christos 	fd_set *copy = calloc(1, __NFD_BYTES(size));
    260  1.4  christos 	if (copy == NULL)
    261  1.2  christos 		return NULL;
    262  1.2  christos 	if (orig)
    263  1.4  christos 		memcpy(copy, orig, __NFD_BYTES(size));
    264  1.4  christos 	return copy;
    265  1.2  christos }
    266  1.1  christos 
    267  1.2  christos fd_set *
    268  1.2  christos svc_fdset_get(void)
    269  1.2  christos {
    270  1.4  christos 	struct svc_fdset *fds = svc_fdset_get_internal(0);
    271  1.4  christos 	svc_fdset_sanitize(fds);
    272  1.4  christos 
    273  1.4  christos 	DPRINTF_FDSET(fds, "get");
    274  1.4  christos 	return fds->fdset;
    275  1.1  christos }
    276  1.1  christos 
    277  1.1  christos int *
    278  1.2  christos svc_fdset_getmax(void)
    279  1.2  christos {
    280  1.4  christos 	struct svc_fdset *fds;
    281  1.2  christos 
    282  1.4  christos 	if (!__isthreaded || fdsetkey == -2) {
    283  1.4  christos 		svc_fdset_sanitize(&__svc_fdset);
    284  1.4  christos 		return &__svc_fdset.fdmax;
    285  1.4  christos 	}
    286  1.2  christos 
    287  1.4  christos 	fds = svc_fdset_alloc(0);
    288  1.4  christos 	if (fds == NULL)
    289  1.2  christos 		return NULL;
    290  1.4  christos 	return &fds->fdmax;
    291  1.2  christos }
    292  1.2  christos 
    293  1.2  christos int
    294  1.2  christos svc_fdset_getsize(int fd)
    295  1.1  christos {
    296  1.4  christos 	struct svc_fdset *fds;
    297  1.1  christos 
    298  1.2  christos 	if (!__isthreaded || fdsetkey == -2) {
    299  1.4  christos 		if (svc_fdset_resize(fd, &__svc_fdset) == NULL)
    300  1.2  christos 			return -1;
    301  1.2  christos 		else
    302  1.4  christos 			return __svc_fdset.fdsize;
    303  1.2  christos 	}
    304  1.2  christos 
    305  1.4  christos 	fds = svc_fdset_alloc(fd);
    306  1.4  christos 	if (fds == NULL)
    307  1.2  christos 		return -1;
    308  1.4  christos 	return fds->fdsize;
    309  1.1  christos }
    310