int selwait, nselcoll; /* * Select system call. */ struct select_args { u_int nd; fd_set *in, *ou, *ex; struct timeval *tv; }; select(p, uap, retval) register struct proc *p; register struct select_args *uap; int *retval; { fd_set ibits[3], obits[3]; struct timeval atv; int s, ncoll, error = 0, timo; u_int ni; bzero((caddr_t)ibits, sizeof(ibits)); bzero((caddr_t)obits, sizeof(obits)); if (uap->nd > FD_SETSIZE) return (EINVAL); if (uap->nd > p->p_fd->fd_nfiles) uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */ ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); #define getbits(name, x) / if (uap->name && / (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) / goto done; getbits(in, 0); getbits(ou, 1); getbits(ex, 2); #undef getbits if (uap->tv) { error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv)); if (error) goto done; if (itimerfix(&atv)) { error = EINVAL; goto done; } s = splclock(); timevaladd(&atv, (struct timeval *)&time); timo = hzto(&atv); /* * Avoid inadvertently sleeping forever. */ if (timo == 0) timo = 1; splx(s); } else timo = 0; retry: ncoll = nselcoll; p->p_flag |= P_SELECT; error = selscan(p, ibits, obits, uap->nd, retval); if (error || *retval) goto done; s = splhigh(); /* this should be timercmp(&time, &atv, >=) */ if (uap->tv && (time.tv_sec > atv.tv_sec || time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { splx(s); goto done; } if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { splx(s); goto retry; } p->p_flag &= ~P_SELECT; error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); splx(s); if (error == 0) goto retry; done: p->p_flag &= ~P_SELECT; /* select is not restarted after signals... */ if (error == ERESTART) error = EINTR; if (error == EWOULDBLOCK) error = 0; #define putbits(name, x) / if (uap->name && / (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) / error = error2; if (error == 0) { int error2; putbits(in, 0); putbits(ou, 1); putbits(ex, 2); #undef putbits } return (error);