From 301b9cec8851010b8f538d86f85f2a2f2b266297 Mon Sep 17 00:00:00 2001 From: bde Date: Thu, 20 Feb 1997 11:51:52 +0000 Subject: Improved select(): - avoid malloc() if the number of fds is small. - pack the bits better so that `small' is quite large. - don't waste time generating zero bits for null fd_set pointers or scanning these bits. Possibly improved select(): - free malloc()ed storage before returning. This is simpler and I think huge select()s aren't worth optimizing since they are rare, relative gain would be small and there would be tiny costs for all selects(). Reviewed by: ache (first version by him too) --- sys/kern/sys_generic.c | 87 +++++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 36 deletions(-) (limited to 'sys') diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index fdefc21..8389293 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -527,54 +527,66 @@ select(p, uap, retval) register struct select_args *uap; int *retval; { - fd_mask *ibits[3], *obits[3]; + /* + * The magic 2048 here is chosen to be just enough for FD_SETSIZE + * infds with the new FD_SETSIZE of 1024, and more than enough for + * FD_SETSIZE infds, outfds and exceptfds with the old FD_SETSIZE + * of 256. + */ + fd_mask s_selbits[howmany(2048, NFDBITS)]; + fd_mask *ibits[3], *obits[3], *selbits, *sbp; struct timeval atv; - int s, ncoll, error = 0, timo, i; - u_int ni; + int s, ncoll, error, timo; + u_int nbufbytes, ncpbytes, nfdbits; if (uap->nd < 0) return (EINVAL); - if (uap->nd > p->p_fd->fd_nfiles) uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */ - /* The amount of space we need to allocate */ - ni = howmany(roundup2 (uap->nd, FD_SETSIZE), NFDBITS) * - sizeof(fd_mask); - - if (ni > p->p_selbits_size) { - if (p->p_selbits_size) - free (p->p_selbits, M_SELECT); - - while (p->p_selbits_size < ni) - p->p_selbits_size += 32; /* Increase by 256 bits */ - - p->p_selbits = malloc(p->p_selbits_size * 6, M_SELECT, - M_WAITOK); - } - for (i = 0; i < 3; i++) { - ibits[i] = (fd_mask *)(p->p_selbits + i * p->p_selbits_size); - obits[i] = (fd_mask *)(p->p_selbits + (i + 3) * - p->p_selbits_size); - } - /* - * This buffer is usually very small therefore it's probably faster - * to just zero it, rather than calculate what needs to be zeroed. + * Allocate just enough bits for the non-null fd_sets. Use the + * preallocated auto buffer if possible. */ - bzero (p->p_selbits, p->p_selbits_size * 6); - - /* The amount of space we need to copyin/copyout */ - ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); + nfdbits = roundup(uap->nd, NFDBITS); + ncpbytes = nfdbits / NBBY; + nbufbytes = 0; + if (uap->in != NULL) + nbufbytes += 2 * ncpbytes; + if (uap->ou != NULL) + nbufbytes += 2 * ncpbytes; + if (uap->ex != NULL) + nbufbytes += 2 * ncpbytes; + if (nbufbytes <= sizeof s_selbits) + selbits = &s_selbits[0]; + else + selbits = malloc(nbufbytes, M_SELECT, M_WAITOK); + /* + * Assign pointers into the bit buffers and fetch the input bits. + * Put the output buffers together so that they can be bzeroed + * together. + */ + sbp = selbits; #define getbits(name, x) \ - if (uap->name && \ - (error = copyin((caddr_t)uap->name, (caddr_t)ibits[x], ni))) \ - goto done; + do { \ + if (uap->name == NULL) \ + ibits[x] = NULL; \ + else { \ + ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \ + obits[x] = sbp; \ + sbp += ncpbytes / sizeof *sbp; \ + error = copyin(uap->name, ibits[x], ncpbytes); \ + if (error != 0) \ + goto done; \ + } \ + } while (0) getbits(in, 0); getbits(ou, 1); getbits(ex, 2); #undef getbits + if (nbufbytes != 0) + bzero(selbits, nbufbytes / 2); if (uap->tv) { error = copyin((caddr_t)uap->tv, (caddr_t)&atv, @@ -626,8 +638,7 @@ done: if (error == EWOULDBLOCK) error = 0; #define putbits(name, x) \ - if (uap->name && \ - (error2 = copyout((caddr_t)obits[x], (caddr_t)uap->name, ni))) \ + if (uap->name && (error2 = copyout(obits[x], uap->name, ncpbytes))) \ error = error2; if (error == 0) { int error2; @@ -637,6 +648,8 @@ done: putbits(ex, 2); #undef putbits } + if (selbits != &s_selbits[0]) + free(selbits, M_SELECT); return (error); } @@ -654,6 +667,8 @@ selscan(p, ibits, obits, nfd, retval) static int flag[3] = { FREAD, FWRITE, 0 }; for (msk = 0; msk < 3; msk++) { + if (ibits[msk] == NULL) + continue; for (i = 0; i < nfd; i += NFDBITS) { bits = ibits[msk][i/NFDBITS]; while ((j = ffs(bits)) && (fd = i + --j) < nfd) { @@ -662,7 +677,7 @@ selscan(p, ibits, obits, nfd, retval) if (fp == NULL) return (EBADF); if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { - obits[msk][(fd)/NFDBITS] |= + obits[msk][(fd)/NFDBITS] |= (1 << ((fd) % NFDBITS)); n++; } -- cgit v1.1