- for (msk = 0; msk < 3; msk++) {
- iptr = (u_int32_t *)&ibits[msk * nw];
- optr = (u_int32_t *)&obits[msk * nw];
- for (i = 0; i < nfd; i += NFDBITS) {
- bits = iptr[i/NFDBITS];
- while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
- bits &= ~(1 << j);
- fp = fdp->fd_ofiles[fd];
- if (fp == NULL ||
- (fdp->fd_ofileflags[fd] & UF_RESERVED))
- return (EBADF);
- if (fp->f_ops && (*fp->f_ops->fo_select)(fp, flag[msk], p)) {
- optr[fd/NFDBITS] |= (1 << (fd % NFDBITS));
- n++;
+ nc = 0;
+ if ( nfcount < count) {
+ /* some or all in kernel funnel */
+ for (msk = 0; msk < 3; msk++) {
+ iptr = (u_int32_t *)&ibits[msk * nw];
+ optr = (u_int32_t *)&obits[msk * nw];
+ for (i = 0; i < nfd; i += NFDBITS) {
+ bits = iptr[i/NFDBITS];
+ while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
+ bits &= ~(1 << j);
+ fp = fdp->fd_ofiles[fd];
+ if (fp == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ return(EBADF);
+ }
+ if (sel_pass == SEL_SECONDPASS)
+ wql_ptr = (char *)0;
+ else
+ wql_ptr = (wql+ nc * SIZEOF_WAITQUEUE_LINK);
+ /*
+ * Merlot: need to remove the bogus f_data check
+ * from the following "if" statement. It's there
+ * because of various problems stemming from
+ * races due to the split-funnels and lack of real
+ * referencing on sockets...
+ */
+ if (fp->f_ops && (fp->f_type != DTYPE_SOCKET)
+ && (fp->f_data != (caddr_t)-1)
+ && !(fp->f_type == DTYPE_VNODE
+ && (vp = (struct vnode *)fp->f_data)
+ && vp->v_type == VFIFO)
+ && fo_select(fp, flag[msk], wql_ptr, p)) {
+ optr[fd/NFDBITS] |= (1 << (fd % NFDBITS));
+ n++;
+ }
+ nc++;
+ }
+ }
+ }
+ }
+
+ if (nfcount) {
+ /* socket file descriptors for scan */
+ thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+
+ nc = 0;
+ for (msk = 0; msk < 3; msk++) {
+ iptr = (u_int32_t *)&ibits[msk * nw];
+ optr = (u_int32_t *)&obits[msk * nw];
+ for (i = 0; i < nfd; i += NFDBITS) {
+ bits = iptr[i/NFDBITS];
+ while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
+ bits &= ~(1 << j);
+ fp = fdp->fd_ofiles[fd];
+ if (fp == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+ return(EBADF);
+ }
+ if (sel_pass == SEL_SECONDPASS)
+ wql_ptr = (char *)0;
+ else
+ wql_ptr = (wql+ nc * SIZEOF_WAITQUEUE_LINK);
+ if (fp->f_ops
+ && (fp->f_type == DTYPE_SOCKET
+ || (fp->f_type == DTYPE_VNODE
+ && (vp = (struct vnode *)fp->f_data)
+ && vp != (struct vnode *)-1
+ && vp->v_type == VFIFO))
+ && fo_select(fp, flag[msk], wql_ptr, p)) {
+ optr[fd/NFDBITS] |= (1 << (fd % NFDBITS));
+ n++;
+ }
+ nc++;