From 85f190e4d10ec172630759349586e04719f30bad Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Thu, 14 Mar 2002 01:32:30 +0000 Subject: Fixes to make select/poll mpsafe. Problem: selwakeup required calling pfind which would cause lock order reversals with the allproc_lock and the per-process filedesc lock. Solution: Instead of recording the pid of the select()'ing process into the selinfo structure, actually record a pointer to the thread. To avoid dereferencing a bad address all the selinfo structures that are in use by a thread are kept in a list hung off the thread (protected by sellock). When a selwakeup occurs the selinfo is removed from that threads list, it is also removed on the way out of select or poll where the thread will traverse its list removing all the selinfos from its own list. Problem: Previously the PROC_LOCK was used to provide the mutual exclusion needed to ensure proper locking, this couldn't work because there was a single condvar used for select and poll and condvars can only be used with a single mutex. Solution: Introduce a global mutex 'sellock' which is used to provide mutual exclusion when recording events to wait on as well as performing notification when an event occurs. Interesting note: schedlock is required to manipulate the per-thread TDF_SELECT flag, however if given its own field it would not need schedlock, also because TDF_SELECT is only manipulated under sellock one doesn't actually use schedlock for syncronization, only to protect against corruption. Proc locks are no longer used in select/poll. Portions contributed by: davidc --- sys/dev/atkbdc/psm.c | 2 -- sys/dev/bktr/bktr_core.c | 2 +- sys/dev/kbd/kbd.c | 2 -- sys/dev/snp/snp.c | 2 -- sys/dev/sound/midi/midibuf.c | 4 ++-- sys/dev/sound/pcm/channel.c | 2 +- sys/dev/usb/ums.c | 2 ++ 7 files changed, 6 insertions(+), 10 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index d43207e7f4fb..6be30d459f69 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 528f09acb054..1a062dd2444e 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 1a1c13221aab..6eef728733bc 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 a72940b84bc7..78d5cd3c8c52 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 d764b684fa88..8b4eda7dbc00 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 3d36e10afe34..c55229ccc8d5 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 0fdafdefd585..bb7193dd1724 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, -- cgit v1.3