/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * SCCSID: @(#)select.c 3.0 4/21/86 */ #include <sys/param.h> #include <sys/dir.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/systm.h> #include <sys/inode.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/conf.h> #include <sys/seg.h> #define NBBY 8 /* number of bits to a byte */ int nselcoll; select() { register struct uap { int nfd; fd_set *rp, *wp; int *tp; } *ap = (struct uap *)u.u_ap; fd_set rd, wr; int nfds = 0; long selscan(); long readable = 0, writeable = 0; int timo = 0; time_t t = time; int s, tsel, ncoll, rem; if (ap->nfd > NOFILE) ap->nfd = NOFILE; if (ap->nfd < 0) { u.u_error = EBADF; return; } if (ap->rp && copyin((caddr_t)ap->rp, (caddr_t)&rd, sizeof(fd_set))) return; if (ap->wp && copyin((caddr_t)ap->wp, (caddr_t)&wr, sizeof(fd_set))) return; if (ap->tp && copyin((caddr_t)ap->tp, (caddr_t)&timo, sizeof(timo))) return; retry: ncoll = nselcoll; u.u_procp->p_flag |= SSEL; if (ap->rp) readable = selscan(ap->nfd, rd, &nfds, FREAD); if (ap->wp) writeable = selscan(ap->nfd, wr, &nfds, FWRITE); if (u.u_error) goto done; if (readable || writeable) goto done; if (ap->tp) if (timo == 0 || (rem = timo - (time - t)) <= 0) goto done; s = spl6(); if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) { u.u_procp->p_flag &= ~SSEL; splx(s); goto retry; } u.u_procp->p_flag &= ~SSEL; if (ap->tp) { tsel = tsleep((caddr_t)&selwait, PZERO + 1, rem); splx(s); switch (tsel) { case TS_OK: goto retry; case TS_SIG: u.u_error = EINTR; return; case TS_TIME: break; } } else { sleep((caddr_t)&selwait, PZERO + 1); splx(s); goto retry; } done: rd.fds_bits[0] = readable; wr.fds_bits[0] = writeable; s = sizeof (fd_set); if (s * NBBY < ap->nfd) s = (ap->nfd + NBBY - 1) / NBBY; u.u_r.r_val1 = nfds; if (ap->rp) copyout((caddr_t)&rd, (caddr_t)ap->rp, sizeof(fd_set)); if (ap->wp) copyout((caddr_t)&wr, (caddr_t)ap->wp, sizeof(fd_set)); } static long selscan(nfd, fds, nfdp, flag) int nfd; fd_set fds; int *nfdp, flag; { struct file *fp; struct inode *ip; long bits, res = 0; int i, able; bits = fds.fds_bits[0]; while (i = ffs(bits)) { if (i > nfd) break; bits &= ~(1L << (i - 1)); fp = u.u_ofile[i-1]; if (fp == NULL) { u.u_error = EBADF; return(0); } #ifdef UCB_NET if (fp->f_flag & FSOCKET) able = soo_select(fp->f_socket, flag); else #endif UCB_NET switch ((ip = fp->f_inode)->i_mode & IFMT) { case IFCHR: { register dev_t dev = ip->i_rdev; able = (*cdevsw[major(dev)].d_select)(dev, flag); break; } case IFIFO: able = pipeselect(ip, flag); break; case IFBLK: case IFREG: case IFDIR: able = 1; break; } if (able) { res |= (1L << (i - 1)); (*nfdp)++; } } return (res); } static ffs(mask) long mask; { register int i; register int imask; if (mask == 0) return(0); imask = loint(mask); for (i = 1; i < 16; i++) { if (imask & 1) return (i); imask >>= 1; } imask = hiint(mask); for (; i<=32; i++) { if (imask & 1) return (i); imask >>= 1; } return (0); /* can't get here anyway! */ } selwakeup(p, coll) register struct proc *p; int coll; { register int s; extern int selwait; if (coll) { nselcoll++; wakeup((caddr_t)&selwait); } s = spl6(); if (p) { segm map; /* * We can get called with ka5 not pointing to the * normal seg5. Since we know we'll be looking at the * proc table, we have to remap ourselves. */ saveseg5(map); normalseg5(); if (p->p_wchan == (caddr_t)&selwait) setrun(p); else if (p->p_flag & SSEL) p->p_flag &= ~SSEL; restorseg5(map); } splx(s); } seltrue(dev, flag) dev_t dev; int flag; { return(1); } static tsleep(chan, pri, seconds) caddr_t chan; int pri, seconds; { struct sqsav { label_t sq_t; } lqsav; register struct proc *pp; register sec, n, rval; pp = u.u_procp; n = spl7(); sec = 0; rval = 0; if (pp->p_clktim && pp->p_clktim < seconds) seconds = 0; if (seconds) { pp->p_flag |= STIMO; sec = pp->p_clktim - seconds; pp->p_clktim = seconds; } lqsav = *(struct sqsav *)&(u.u_qsav); if (save(u.u_qsav)) rval = TS_SIG; else { sleep(chan, pri); if ((pp->p_flag & STIMO) == 0 && seconds) rval = TS_TIME; else rval = TS_OK; } pp->p_flag &= ~STIMO; *(struct sqsav *)&(u.u_qsav) = lqsav; if (sec > 0) pp->p_clktim += sec; else pp->p_clktim = 0; splx(n); return(rval); }