diff options
-rw-r--r-- | sys/dev/atkbdc/psm.c | 2 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_core.c | 2 | ||||
-rw-r--r-- | sys/dev/kbd/kbd.c | 2 | ||||
-rw-r--r-- | sys/dev/snp/snp.c | 2 | ||||
-rw-r--r-- | sys/dev/sound/midi/midibuf.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/ums.c | 2 | ||||
-rw-r--r-- | sys/i386/isa/asc.c | 5 | ||||
-rw-r--r-- | sys/i386/isa/pcaudio.c | 7 | ||||
-rw-r--r-- | sys/isa/psm.c | 2 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 226 | ||||
-rw-r--r-- | sys/kern/tty.c | 4 | ||||
-rw-r--r-- | sys/sys/proc.h | 3 | ||||
-rw-r--r-- | sys/sys/selinfo.h | 9 | ||||
-rw-r--r-- | sys/sys/systm.h | 2 |
15 files changed, 135 insertions, 139 deletions
diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index d43207e..6be30d4 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -1314,8 +1314,6 @@ psmopen(dev_t dev, int flag, int fmt, struct thread *td) device_busy(devclass_get_device(psm_devclass, unit)); /* Initialize state */ - sc->rsel.si_flags = 0; - sc->rsel.si_pid = 0; sc->mode.level = sc->dflt_mode.level; sc->mode.protocol = sc->dflt_mode.protocol; sc->watchdog = FALSE; diff --git a/sys/dev/bktr/bktr_core.c b/sys/dev/bktr/bktr_core.c index 528f09a..1a062dd 100644 --- a/sys/dev/bktr/bktr_core.c +++ b/sys/dev/bktr/bktr_core.c @@ -809,7 +809,7 @@ common_bktr_intr( void *arg ) } /* If someone has a select() on /dev/vbi, inform them */ - if (bktr->vbi_select.si_pid) { + if (SEL_WAITING(&bktr->vbi_select)) { selwakeup(&bktr->vbi_select); } diff --git a/sys/dev/kbd/kbd.c b/sys/dev/kbd/kbd.c index 1a1c132..6eef728 100644 --- a/sys/dev/kbd/kbd.c +++ b/sys/dev/kbd/kbd.c @@ -523,8 +523,6 @@ genkbdopen(dev_t dev, int mode, int flag, struct thread *td) bzero(&sc->gkb_q, sizeof(sc->gkb_q)); #endif clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ - sc->gkb_rsel.si_flags = 0; - sc->gkb_rsel.si_pid = 0; splx(s); return 0; diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c index a72940b..78d5cd3 100644 --- a/sys/dev/snp/snp.c +++ b/sys/dev/snp/snp.c @@ -374,7 +374,6 @@ snp_in(snp, buf, n) wakeup((caddr_t)snp); } selwakeup(&snp->snp_sel); - snp->snp_sel.si_pid = 0; return (n); } @@ -449,7 +448,6 @@ snp_detach(snp) detach_notty: selwakeup(&snp->snp_sel); - snp->snp_sel.si_pid = 0; if ((snp->snp_flags & SNOOP_OPEN) == 0) free(snp, M_SNP); diff --git a/sys/dev/sound/midi/midibuf.c b/sys/dev/sound/midi/midibuf.c index d764b68..8b4eda7 100644 --- a/sys/dev/sound/midi/midibuf.c +++ b/sys/dev/sound/midi/midibuf.c @@ -357,7 +357,7 @@ queuerawdata(midi_dbuf *dbuf, char *data, int len) /* Wake up the processes sleeping on input data. */ cv_broadcast(&dbuf->cv_in); - if (dbuf->sel.si_pid && dbuf->rl >= dbuf->blocksize) + if (SEL_WAITING(&dbuf->sel) && dbuf->rl >= dbuf->blocksize) selwakeup(&dbuf->sel); } @@ -398,6 +398,6 @@ deleterawdata(midi_dbuf *dbuf, int len) /* Wake up the processes sleeping on queueing. */ cv_broadcast(&dbuf->cv_out); - if (dbuf->sel.si_pid && dbuf->fl >= dbuf->blocksize) + if (SEL_WAITING(&dbuf->sel) && dbuf->fl >= dbuf->blocksize) selwakeup(&dbuf->sel); } diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 3d36e10..c55229c 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -116,7 +116,7 @@ chn_wakeup(struct pcm_channel *c) struct snd_dbuf *bs = c->bufsoft; CHN_LOCKASSERT(c); - if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c)) + if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) selwakeup(sndbuf_getsel(bs)); wakeup(bs); } diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c index 0fdafde..bb7193d 100644 --- a/sys/dev/usb/ums.c +++ b/sys/dev/usb/ums.c @@ -344,8 +344,10 @@ USB_ATTACH(ums) sc->status.button = sc->status.obutton = 0; sc->status.dx = sc->status.dy = sc->status.dz = 0; +#ifndef __FreeBSD__ sc->rsel.si_flags = 0; sc->rsel.si_pid = 0; +#endif sc->dev = make_dev(&ums_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR, diff --git a/sys/i386/isa/asc.c b/sys/i386/isa/asc.c index ca90a0d..292b6d5 100644 --- a/sys/i386/isa/asc.c +++ b/sys/i386/isa/asc.c @@ -484,7 +484,6 @@ ascattach(struct isa_device *isdp) scu->flags &= ~FLAG_DEBUG; scu->selp.si_flags=0; - scu->selp.si_pid=(pid_t)0; #define ASC_UID 0 #define ASC_GID 13 make_dev(&asc_cdevsw, unit<<6, ASC_UID, ASC_GID, 0666, "asc%d", unit); @@ -531,10 +530,8 @@ ascintr(int unit) if (scu->sbuf.size - scu->sbuf.count >= scu->linesize) { dma_restart(scu); } - if (scu->selp.si_pid) { + if (SEL_WAITING(&scu->selp)) { selwakeup(&scu->selp); - scu->selp.si_pid=(pid_t)0; - scu->selp.si_flags = 0; } } } diff --git a/sys/i386/isa/pcaudio.c b/sys/i386/isa/pcaudio.c index a4809ed..e457eed 100644 --- a/sys/i386/isa/pcaudio.c +++ b/sys/i386/isa/pcaudio.c @@ -542,11 +542,8 @@ pcaintr(struct clockframe *frame) pca_status.buffer = pca_status.buf[pca_status.current]; if (pca_sleep) wakeup(&pca_sleep); - if (pca_status.wsel.si_pid) { - selwakeup((struct selinfo *)&pca_status.wsel.si_pid); - pca_status.wsel.si_pid = 0; - pca_status.wsel.si_flags = 0; - } + if (SEL_WAITING(&pca_status.wsel)) + selwakeup(&pca_status.wsel); } } diff --git a/sys/isa/psm.c b/sys/isa/psm.c index d43207e..6be30d4 100644 --- a/sys/isa/psm.c +++ b/sys/isa/psm.c @@ -1314,8 +1314,6 @@ psmopen(dev_t dev, int flag, int fmt, struct thread *td) device_busy(devclass_get_device(psm_devclass, unit)); /* Initialize state */ - sc->rsel.si_flags = 0; - sc->rsel.si_pid = 0; sc->mode.level = sc->dflt_mode.level; sc->mode.protocol = sc->dflt_mode.protocol; sc->watchdog = FALSE; diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 3462e6c..dff12a1 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -696,8 +696,12 @@ done: return (error); } -static int nselcoll; /* Select collisions since boot */ +/* + * sellock and selwait are initialized in selectinit() via SYSINIT. + */ +struct mtx sellock; struct cv selwait; +int nselcoll; /* Select collisions since boot */ SYSCTL_INT(_kern, OID_AUTO, nselcoll, CTLFLAG_RD, &nselcoll, 0, ""); /* @@ -775,7 +779,7 @@ select(td, uap) sbp += ncpbytes / sizeof *sbp; \ error = copyin(uap->name, ibits[x], ncpbytes); \ if (error != 0) \ - goto done_noproclock; \ + goto done_nosellock; \ } \ } while (0) getbits(in, 0); @@ -789,10 +793,10 @@ select(td, uap) error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv)); if (error) - goto done_noproclock; + goto done_nosellock; if (itimerfix(&atv)) { error = EINVAL; - goto done_noproclock; + goto done_nosellock; } getmicrouptime(&rtv); timevaladd(&atv, &rtv); @@ -801,61 +805,59 @@ select(td, uap) atv.tv_usec = 0; } timo = 0; - PROC_LOCK(td->td_proc); + mtx_lock(&sellock); retry: ncoll = nselcoll; mtx_lock_spin(&sched_lock); td->td_flags |= TDF_SELECT; mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); + mtx_unlock(&sellock); + + /* XXX Is there a better place for this? */ + TAILQ_INIT(&td->td_selq); error = selscan(td, ibits, obits, uap->nd); - PROC_LOCK(td->td_proc); + mtx_lock(&sellock); if (error || td->td_retval[0]) goto done; if (atv.tv_sec || atv.tv_usec) { getmicrouptime(&rtv); - if (timevalcmp(&rtv, &atv, >=)) { - /* - * An event of our interest may occur during locking a process. - * In order to avoid missing the event that occured during locking - * the process, test TDF_SELECT and rescan file descriptors if - * necessary. - */ - mtx_lock_spin(&sched_lock); - if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { - ncoll = nselcoll; - td->td_flags |= TDF_SELECT; - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); - error = selscan(td, ibits, obits, uap->nd); - PROC_LOCK(td->td_proc); - } else - mtx_unlock_spin(&sched_lock); + if (timevalcmp(&rtv, &atv, >=)) goto done; - } ttv = atv; timevalsub(&ttv, &rtv); timo = ttv.tv_sec > 24 * 60 * 60 ? 24 * 60 * 60 * hz : tvtohz(&ttv); } + + /* + * An event of interest may occur while we do not hold + * sellock, so check TDF_SELECT and the number of + * collisions and rescan the file descriptors if + * necessary. + */ mtx_lock_spin(&sched_lock); - td->td_flags &= ~TDF_SELECT; + if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { + mtx_unlock_spin(&sched_lock); + goto retry; + } mtx_unlock_spin(&sched_lock); if (timo > 0) - error = cv_timedwait_sig(&selwait, &td->td_proc->p_mtx, timo); + error = cv_timedwait_sig(&selwait, &sellock, timo); else - error = cv_wait_sig(&selwait, &td->td_proc->p_mtx); + error = cv_wait_sig(&selwait, &sellock); if (error == 0) goto retry; done: + clear_selinfo_list(td); mtx_lock_spin(&sched_lock); td->td_flags &= ~TDF_SELECT; mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); -done_noproclock: + mtx_unlock(&sellock); + +done_nosellock: /* select is not restarted after signals... */ if (error == ERESTART) error = EINTR; @@ -967,13 +969,13 @@ poll(td, uap) bits = smallbits; error = copyin(SCARG(uap, fds), bits, ni); if (error) - goto done_noproclock; + goto done_nosellock; if (SCARG(uap, timeout) != INFTIM) { atv.tv_sec = SCARG(uap, timeout) / 1000; atv.tv_usec = (SCARG(uap, timeout) % 1000) * 1000; if (itimerfix(&atv)) { error = EINVAL; - goto done_noproclock; + goto done_nosellock; } getmicrouptime(&rtv); timevaladd(&atv, &rtv); @@ -982,59 +984,57 @@ poll(td, uap) atv.tv_usec = 0; } timo = 0; - PROC_LOCK(td->td_proc); + mtx_lock(&sellock); retry: ncoll = nselcoll; mtx_lock_spin(&sched_lock); td->td_flags |= TDF_SELECT; mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); + mtx_unlock(&sellock); + + /* XXX Is there a better place for this? */ + TAILQ_INIT(&td->td_selq); error = pollscan(td, (struct pollfd *)bits, nfds); - PROC_LOCK(td->td_proc); + mtx_lock(&sellock); if (error || td->td_retval[0]) goto done; if (atv.tv_sec || atv.tv_usec) { getmicrouptime(&rtv); - if (timevalcmp(&rtv, &atv, >=)) { - /* - * An event of our interest may occur during locking a process. - * In order to avoid missing the event that occured during locking - * the process, test TDF_SELECT and rescan file descriptors if - * necessary. - */ - mtx_lock_spin(&sched_lock); - if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { - ncoll = nselcoll; - td->td_flags |= TDF_SELECT; - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); - error = pollscan(td, (struct pollfd *)bits, nfds); - PROC_LOCK(td->td_proc); - } else - mtx_unlock_spin(&sched_lock); + if (timevalcmp(&rtv, &atv, >=)) goto done; - } ttv = atv; timevalsub(&ttv, &rtv); timo = ttv.tv_sec > 24 * 60 * 60 ? 24 * 60 * 60 * hz : tvtohz(&ttv); } + /* + * An event of interest may occur while we do not hold + * sellock, so check TDF_SELECT and the number of collisions + * and rescan the file descriptors if necessary. + */ mtx_lock_spin(&sched_lock); - td->td_flags &= ~TDF_SELECT; + if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { + mtx_unlock_spin(&sched_lock); + goto retry; + } mtx_unlock_spin(&sched_lock); + if (timo > 0) - error = cv_timedwait_sig(&selwait, &td->td_proc->p_mtx, timo); + error = cv_timedwait_sig(&selwait, &sellock, timo); else - error = cv_wait_sig(&selwait, &td->td_proc->p_mtx); + error = cv_wait_sig(&selwait, &sellock); + if (error == 0) goto retry; done: + clear_selinfo_list(td); mtx_lock_spin(&sched_lock); td->td_flags &= ~TDF_SELECT; mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(td->td_proc); -done_noproclock: + mtx_unlock(&sellock); + +done_nosellock: /* poll is not restarted after signals... */ if (error == ERESTART) error = EINTR; @@ -1115,6 +1115,26 @@ openbsd_poll(td, uap) return (poll(td, (struct poll_args *)uap)); } +/* + * Remove the references to the thread from all of the objects + * we were polling. + * + * This code assumes that the underlying owner of the selinfo + * structure will hold sellock before it changes it, and that + * it will unlink itself from our list if it goes away. + */ +void +clear_selinfo_list(td) + struct thread *td; +{ + struct selinfo *si; + + mtx_assert(&sellock, MA_OWNED); + TAILQ_FOREACH(si, &td->td_selq, si_thrlist) + si->si_thread = NULL; + TAILQ_INIT(&td->td_selq); +} + /*ARGSUSED*/ int seltrue(dev, events, td) @@ -1126,18 +1146,6 @@ seltrue(dev, events, td) return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); } -static int -find_thread_in_proc(struct proc *p, struct thread *td) -{ - struct thread *td2; - FOREACH_THREAD_IN_PROC(p, td2) { - if (td2 == td) { - return (1); - } - } - return (0); -} - /* * Record a select request. */ @@ -1146,29 +1154,22 @@ selrecord(selector, sip) struct thread *selector; struct selinfo *sip; { - struct proc *p; - pid_t mypid; - mypid = selector->td_proc->p_pid; - if ((sip->si_pid == mypid) && - (sip->si_thread == selector)) { /* XXXKSE should be an ID? */ - return; - } - if (sip->si_pid && - (p = pfind(sip->si_pid)) && - (find_thread_in_proc(p, sip->si_thread))) { - mtx_lock_spin(&sched_lock); - if (sip->si_thread->td_wchan == (caddr_t)&selwait) { - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(p); - sip->si_flags |= SI_COLL; - return; - } - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(p); + mtx_lock(&sellock); + /* + * If the thread is NULL then take ownership of selinfo + * however if the thread is not NULL and the thread points to + * someone else, then we have a collision, otherwise leave it alone + * as we've owned it in a previous selrecord on this selinfo. + */ + if (sip->si_thread == NULL) { + sip->si_thread = selector; + TAILQ_INSERT_TAIL(&selector->td_selq, sip, si_thrlist); + } else if (sip->si_thread != selector) { + sip->si_flags |= SI_COLL; } - sip->si_pid = mypid; - sip->si_thread = selector; + + mtx_unlock(&sellock); } /* @@ -1176,37 +1177,33 @@ selrecord(selector, sip) */ void selwakeup(sip) - register struct selinfo *sip; + struct selinfo *sip; { struct thread *td; - register struct proc *p; - if (sip->si_pid == 0) - return; - if (sip->si_flags & SI_COLL) { + mtx_lock(&sellock); + td = sip->si_thread; + if ((sip->si_flags & SI_COLL) != 0) { nselcoll++; sip->si_flags &= ~SI_COLL; cv_broadcast(&selwait); } - p = pfind(sip->si_pid); - sip->si_pid = 0; - td = sip->si_thread; - if (p != NULL) { - if (!find_thread_in_proc(p, td)) { - PROC_UNLOCK(p); /* lock is in pfind() */; - return; - } - mtx_lock_spin(&sched_lock); - if (td->td_wchan == (caddr_t)&selwait) { - if (td->td_proc->p_stat == SSLEEP) - setrunnable(td); - else - cv_waitq_remove(td); - } else - td->td_flags &= ~TDF_SELECT; - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(p); /* Lock is in pfind() */ + if (td == NULL) { + mtx_unlock(&sellock); + return; } + TAILQ_REMOVE(&td->td_selq, sip, si_thrlist); + sip->si_thread = NULL; + mtx_lock_spin(&sched_lock); + if (td->td_wchan == (caddr_t)&selwait) { + if (td->td_proc->p_stat == SSLEEP) + setrunnable(td); + else + cv_waitq_remove(td); + } else + td->td_flags &= ~TDF_SELECT; + mtx_unlock_spin(&sched_lock); + mtx_unlock(&sellock); } static void selectinit __P((void *)); @@ -1218,4 +1215,5 @@ selectinit(dummy) void *dummy; { cv_init(&selwait, "select"); + mtx_init(&sellock, "sellck", MTX_DEF); } diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 923923a..89207e6 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -2273,7 +2273,7 @@ ttwakeup(tp) register struct tty *tp; { - if (tp->t_rsel.si_pid != 0) + if (SEL_WAITING(&tp->t_rsel)) selwakeup(&tp->t_rsel); if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL)); @@ -2289,7 +2289,7 @@ ttwwakeup(tp) register struct tty *tp; { - if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_olowat) + if (SEL_WAITING(&tp->t_wsel) && tp->t_outq.c_cc <= tp->t_olowat) selwakeup(&tp->t_wsel); if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL) pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL)); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 02ddfe4..a458f66 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -147,6 +147,7 @@ struct pargs { * m - Giant * n - not locked, lazy * o - locked by pgrpsess_lock sx + * p - select lock (sellock) * * If the locking key specifies two identifiers (for example, p_pptr) then * either lock is sufficient for read access, but both locks must be held @@ -260,6 +261,8 @@ struct thread { TAILQ_ENTRY(thread) td_blkq; /* (j) Mutex queue. XXXKSE */ TAILQ_ENTRY(thread) td_runq; /* (j) Run queue(s). XXXKSE */ + TAILQ_HEAD(, selinfo) td_selq; /* (p) List of selinfos. */ + #define td_startzero td_flags int td_flags; /* (j) TDF_* flags. */ int td_dupfd; /* (k) Ret value from fdopen. XXX */ diff --git a/sys/sys/selinfo.h b/sys/sys/selinfo.h index aa1bb89..318681f 100644 --- a/sys/sys/selinfo.h +++ b/sys/sys/selinfo.h @@ -45,18 +45,23 @@ struct thread; * notified when I/O becomes possible. */ struct selinfo { - pid_t si_pid; /* process to be notified */ - struct thread *si_thread; /* thread in that process XXXKSE */ + TAILQ_ENTRY(selinfo) si_thrlist; /* list hung off of thread */ + struct thread *si_thread; /* thread waiting */ struct klist si_note; /* kernel note list */ short si_flags; /* see below */ }; #define SI_COLL 0x0001 /* collision occurred */ +#define SEL_WAITING(si) \ + ((si)->si_thread != NULL || ((si)->si_flags & SI_COLL) != 0) + #ifdef _KERNEL struct thread; +void clear_selinfo_list(struct thread *); void selrecord __P((struct thread *selector, struct selinfo *)); void selwakeup __P((struct selinfo *)); + #endif #endif /* !_SYS_SELINFO_H_ */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index c2178f1..37eb4bf 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -57,6 +57,8 @@ extern char copyright[]; /* system copyright */ extern int nswap; /* size of swap space */ +extern int nselcoll; /* select collisions since boot */ +extern struct mtx sellock; /* select lock variable */ extern struct cv selwait; /* select conditional variable */ extern int physmem; /* physical memory */ |