Home | History | Annotate | Line # | Download | only in rpc
svc_fdset.c revision 1.2
      1  1.2  christos /*	$NetBSD: svc_fdset.c,v 1.2 2015/11/06 19:34:13 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos #include <sys/cdefs.h>
      4  1.2  christos __RCSID("$NetBSD: svc_fdset.c,v 1.2 2015/11/06 19:34:13 christos Exp $");
      5  1.2  christos 
      6  1.2  christos 
      7  1.2  christos #include "reentrant.h"
      8  1.2  christos 
      9  1.2  christos #include <sys/fd_set.h>
     10  1.2  christos 
     11  1.2  christos #include <rpc/rpc.h>
     12  1.1  christos 
     13  1.1  christos #include <stdlib.h>
     14  1.1  christos #include <string.h>
     15  1.1  christos 
     16  1.2  christos struct svc_fdset {
     17  1.2  christos 	fd_set *fdset;
     18  1.2  christos 	int	fdmax;
     19  1.2  christos 	int	fdsize;
     20  1.2  christos };
     21  1.2  christos 
     22  1.2  christos 
     23  1.2  christos /* The single threaded, one global fd_set version */
     24  1.2  christos static fd_set *__svc_fdset;
     25  1.2  christos static int svc_fdsize = 0;
     26  1.2  christos 
     27  1.2  christos /*
     28  1.2  christos  * Update the old global svc_fdset if needed for binary compatibility
     29  1.2  christos  */
     30  1.2  christos #define COMPAT_UPDATE(a)				\
     31  1.2  christos 	do						\
     32  1.2  christos 		if ((a) == __svc_fdset)			\
     33  1.2  christos 			svc_fdset = *__svc_fdset;	\
     34  1.2  christos 	while (/*CONSTCOND*/0)
     35  1.2  christos 
     36  1.2  christos static thread_key_t fdsetkey = -2;
     37  1.2  christos 
     38  1.2  christos #ifdef FDSET_DEBUG
     39  1.2  christos #include <stdio.h>
     40  1.2  christos #include <stdarg.h>
     41  1.2  christos #include <unistd.h>
     42  1.2  christos #include <lwp.h>
     43  1.2  christos 
     44  1.2  christos static void  __printflike(3, 0)
     45  1.2  christos svc_header(const char *func, size_t line, const char *fmt, va_list ap)
     46  1.2  christos {
     47  1.2  christos 	fprintf(stderr, "%s[%d.%d]: %s, %zu: ", getprogname(), (int)getpid(),
     48  1.2  christos 	    (int)_lwp_self(), func, line);
     49  1.2  christos 	vfprintf(stderr, fmt, ap);
     50  1.2  christos 	va_end(ap);
     51  1.2  christos }
     52  1.2  christos 
     53  1.2  christos static void __printflike(5, 6)
     54  1.2  christos svc_fdset_print(const char *func, size_t line, const fd_set *fds, int fdmax,
     55  1.2  christos     const char *fmt, ...)
     56  1.2  christos {
     57  1.2  christos 	va_list ap;
     58  1.2  christos 	const char *did = "";
     59  1.2  christos 
     60  1.2  christos 	va_start(ap, fmt);
     61  1.2  christos 	svc_header(func, line, fmt, ap);
     62  1.2  christos 	va_end(ap);
     63  1.2  christos 
     64  1.2  christos 	if (fdmax == 0)
     65  1.2  christos 		fdmax = FD_SETSIZE;
     66  1.2  christos 
     67  1.2  christos 	fprintf(stderr, "%p[%d] <", fds, fdmax);
     68  1.2  christos 	for (int i = 0; i <= fdmax; i++) {
     69  1.2  christos 		if (!FD_ISSET(i, fds))
     70  1.2  christos 			continue;
     71  1.2  christos 		fprintf(stderr, "%s%d", did, i);
     72  1.2  christos 		did = ", ";
     73  1.2  christos 	}
     74  1.2  christos 	fprintf(stderr, ">\n");
     75  1.2  christos }
     76  1.2  christos 
     77  1.2  christos static void __printflike(3, 4)
     78  1.2  christos svc_print(const char *func, size_t line, const char *fmt, ...)
     79  1.2  christos {
     80  1.2  christos 	va_list ap;
     81  1.2  christos 
     82  1.2  christos 	va_start(ap, fmt);
     83  1.2  christos 	svc_header(func, line, fmt, ap);
     84  1.2  christos 	va_end(ap);
     85  1.2  christos 	fprintf(stderr, "\n");
     86  1.2  christos }
     87  1.2  christos 
     88  1.2  christos #define DPRINTF_FDSET(...)	svc_fdset_print(__func__, __LINE__, __VA_ARGS__)
     89  1.2  christos #define DPRINTF(...)		svc_print(__func__, __LINE__, __VA_ARGS__)
     90  1.2  christos #else
     91  1.2  christos #define DPRINTF_FDSET(...)
     92  1.2  christos #define DPRINTF(...)
     93  1.2  christos #endif
     94  1.2  christos 
     95  1.2  christos 
     96  1.2  christos static void
     97  1.2  christos svc_fdset_free(void *v)
     98  1.2  christos {
     99  1.2  christos 	struct svc_fdset *rv = v;
    100  1.2  christos 	DPRINTF_FDSET(rv->fdset, 0, "free");
    101  1.2  christos 
    102  1.2  christos 	free(rv->fdset);
    103  1.2  christos 	free(rv);
    104  1.2  christos }
    105  1.2  christos 
    106  1.2  christos static fd_set *
    107  1.2  christos svc_fdset_resize(int fd, fd_set **fdset, int *fdsize)
    108  1.2  christos {
    109  1.2  christos 	if (*fdset && fd < *fdsize) {
    110  1.2  christos 		DPRINTF_FDSET(*fdset, 0, "keeping %d < %d",
    111  1.2  christos 		    fd, *fdsize);
    112  1.2  christos 		return *fdset;
    113  1.2  christos 	}
    114  1.2  christos 
    115  1.2  christos 	fd += FD_SETSIZE;
    116  1.2  christos 	if (fd == 517)
    117  1.2  christos 		abort();
    118  1.2  christos 
    119  1.2  christos 	char *newfdset = realloc(*fdset, __NFD_BYTES(fd));
    120  1.2  christos 	if (newfdset == NULL)
    121  1.2  christos 		return NULL;
    122  1.2  christos 
    123  1.2  christos 	memset(newfdset + __NFD_BYTES(*fdsize), 0,
    124  1.2  christos 	    __NFD_BYTES(fd) - __NFD_BYTES(*fdsize));
    125  1.2  christos 
    126  1.2  christos 
    127  1.2  christos 	*fdset = (void *)newfdset;
    128  1.2  christos 	DPRINTF_FDSET(*fdset, 0, "resize %d > %d", fd, *fdsize);
    129  1.2  christos 	*fdsize = fd;
    130  1.2  christos 
    131  1.2  christos 	COMPAT_UPDATE(*fdset);
    132  1.2  christos 
    133  1.2  christos 	return *fdset;
    134  1.2  christos }
    135  1.2  christos 
    136  1.2  christos static struct svc_fdset *
    137  1.2  christos svc_fdset_alloc(int fd)
    138  1.2  christos {
    139  1.2  christos 	struct svc_fdset *rv;
    140  1.2  christos 
    141  1.2  christos 	if (fdsetkey == -1)
    142  1.2  christos 		thr_keycreate(&fdsetkey, svc_fdset_free);
    143  1.2  christos 
    144  1.2  christos 	if ((rv = thr_getspecific(fdsetkey)) == NULL) {
    145  1.2  christos 
    146  1.2  christos 		rv = calloc(1, sizeof(*rv));
    147  1.2  christos 		if (rv == NULL)
    148  1.2  christos 			return NULL;
    149  1.2  christos 
    150  1.2  christos 		(void)thr_setspecific(fdsetkey, rv);
    151  1.2  christos 
    152  1.2  christos 		if (svc_fdsize != 0) {
    153  1.2  christos 			rv->fdset = __svc_fdset;
    154  1.2  christos 			DPRINTF("switching to %p", rv->fdset);
    155  1.2  christos 			rv->fdmax = svc_maxfd;
    156  1.2  christos 			rv->fdsize = svc_fdsize;
    157  1.2  christos 
    158  1.2  christos 			svc_fdsize = 0;
    159  1.2  christos 		} else {
    160  1.2  christos 			DPRINTF("first thread time %p", rv->fdset);
    161  1.2  christos 		}
    162  1.2  christos 	} else {
    163  1.2  christos 		DPRINTF("again for %p", rv->fdset);
    164  1.2  christos 		if (fd < rv->fdsize)
    165  1.2  christos 			return rv;
    166  1.2  christos 	}
    167  1.2  christos 	if (svc_fdset_resize(fd, &rv->fdset, &rv->fdsize) == NULL)
    168  1.2  christos 		return NULL;
    169  1.2  christos 	return rv;
    170  1.2  christos }
    171  1.2  christos 
    172  1.2  christos static fd_set *
    173  1.2  christos svc_fdset_get_internal(int fd)
    174  1.2  christos {
    175  1.2  christos 	struct svc_fdset *rv;
    176  1.2  christos 
    177  1.2  christos 	if (!__isthreaded || fdsetkey == -2)
    178  1.2  christos 		return svc_fdset_resize(fd, &__svc_fdset, &svc_fdsize);
    179  1.2  christos 
    180  1.2  christos 	rv = svc_fdset_alloc(fd);
    181  1.2  christos 	if (rv == NULL)
    182  1.2  christos 		return NULL;
    183  1.2  christos 	return rv->fdset;
    184  1.2  christos }
    185  1.2  christos 
    186  1.1  christos 
    187  1.2  christos /* allow each thread to have their own copy */
    188  1.2  christos void
    189  1.2  christos svc_fdset_init(int flags)
    190  1.2  christos {
    191  1.2  christos 	DPRINTF("%x", flags);
    192  1.2  christos 	if ((flags & SVC_FDSET_MT) && fdsetkey == -2)
    193  1.2  christos 		fdsetkey = -1;
    194  1.2  christos }
    195  1.1  christos 
    196  1.1  christos void
    197  1.2  christos svc_fdset_zero(void)
    198  1.1  christos {
    199  1.2  christos 	DPRINTF("zero");
    200  1.2  christos 	fd_set *fds = svc_fdset_get_internal(0);
    201  1.2  christos 	int size = svc_fdset_getsize(0);
    202  1.2  christos 	memset(fds, 0, __NFD_BYTES(size));
    203  1.2  christos 	*svc_fdset_getmax() = 0;
    204  1.2  christos 
    205  1.2  christos 	COMPAT_UPDATE(fds);
    206  1.1  christos 
    207  1.1  christos }
    208  1.1  christos 
    209  1.1  christos void
    210  1.2  christos svc_fdset_set(int fd)
    211  1.1  christos {
    212  1.2  christos 	fd_set *fds = svc_fdset_get_internal(fd);
    213  1.2  christos 	int *fdmax = svc_fdset_getmax();
    214  1.2  christos 	FD_SET(fd, fds);
    215  1.2  christos 	if (fd > *fdmax)
    216  1.2  christos 		*fdmax = fd;
    217  1.2  christos 	DPRINTF_FDSET(fds, *fdmax, "%d", fd);
    218  1.1  christos 
    219  1.2  christos 	COMPAT_UPDATE(fds);
    220  1.2  christos }
    221  1.2  christos 
    222  1.2  christos int
    223  1.2  christos svc_fdset_isset(int fd)
    224  1.2  christos {
    225  1.2  christos 	fd_set *fds = svc_fdset_get_internal(fd);
    226  1.2  christos 	DPRINTF_FDSET(fds, 0, "%d", fd);
    227  1.2  christos 	return FD_ISSET(fd, fds);
    228  1.2  christos }
    229  1.2  christos 
    230  1.2  christos void
    231  1.2  christos svc_fdset_clr(int fd)
    232  1.2  christos {
    233  1.2  christos 	fd_set *fds = svc_fdset_get_internal(fd);
    234  1.2  christos 	FD_CLR(fd, fds);
    235  1.2  christos 	/* XXX: update fdmax? */
    236  1.2  christos 	DPRINTF_FDSET(fds, 0, "%d", fd);
    237  1.2  christos 
    238  1.2  christos 	COMPAT_UPDATE(fds);
    239  1.1  christos }
    240  1.1  christos 
    241  1.1  christos fd_set *
    242  1.2  christos svc_fdset_copy(const fd_set *orig)
    243  1.1  christos {
    244  1.2  christos 	int len, fdmax;
    245  1.2  christos 	fd_set *fds;
    246  1.2  christos 
    247  1.2  christos 	len = 0;
    248  1.2  christos 	fds = 0;
    249  1.2  christos 	fdmax = *svc_fdset_getmax();
    250  1.2  christos 
    251  1.2  christos 	DPRINTF_FDSET(orig, 0, "[orig]");
    252  1.2  christos 	fds = svc_fdset_resize(fdmax, &fds, &len);
    253  1.2  christos 	if (fds == NULL)
    254  1.2  christos 		return NULL;
    255  1.2  christos 
    256  1.2  christos 	if (orig)
    257  1.2  christos 		memcpy(fds, orig, __NFD_BYTES(fdmax));
    258  1.2  christos 	DPRINTF_FDSET(fds, 0, "[copy]");
    259  1.2  christos 	return fds;
    260  1.2  christos }
    261  1.1  christos 
    262  1.2  christos fd_set *
    263  1.2  christos svc_fdset_get(void)
    264  1.2  christos {
    265  1.2  christos 	fd_set *fds = svc_fdset_get_internal(0);
    266  1.2  christos 	DPRINTF_FDSET(fds, 0, "get");
    267  1.2  christos 	return fds;
    268  1.1  christos }
    269  1.1  christos 
    270  1.1  christos int *
    271  1.2  christos svc_fdset_getmax(void)
    272  1.2  christos {
    273  1.2  christos 	struct svc_fdset *rv;
    274  1.2  christos 
    275  1.2  christos 	if (!__isthreaded || fdsetkey == -2)
    276  1.2  christos 		return &svc_maxfd;
    277  1.2  christos 
    278  1.2  christos 	rv = svc_fdset_alloc(0);
    279  1.2  christos 	if (rv == NULL)
    280  1.2  christos 		return NULL;
    281  1.2  christos 	return &rv->fdmax;
    282  1.2  christos }
    283  1.2  christos 
    284  1.2  christos int
    285  1.2  christos svc_fdset_getsize(int fd)
    286  1.1  christos {
    287  1.2  christos 	struct svc_fdset *rv;
    288  1.1  christos 
    289  1.2  christos 	if (!__isthreaded || fdsetkey == -2) {
    290  1.2  christos 		if (svc_fdset_resize(fd, &__svc_fdset, &svc_fdsize) == NULL)
    291  1.2  christos 			return -1;
    292  1.2  christos 		else
    293  1.2  christos 			return svc_fdsize;
    294  1.2  christos 	}
    295  1.2  christos 
    296  1.2  christos 	rv = svc_fdset_alloc(fd);
    297  1.2  christos 	if (rv == NULL)
    298  1.2  christos 		return -1;
    299  1.2  christos 	return rv->fdsize;
    300  1.1  christos }
    301