selwakeup() does a filtered wakeup because all threads waiting in poll(2) or select(2) are blocking on the same wait channel.
The wakeup is currently implemented by first grabbing a reference to a thread via tfind(). This makes removing the KERNEL_LOCK() complicated because we need to ensure the thread isn't disappearing while we want to wake it up. We can instead rely on a single datastructure: the global sleep queue. That's what the diff below does, ok? Index: kern/kern_synch.c =================================================================== RCS file: /cvs/src/sys/kern/kern_synch.c,v retrieving revision 1.148 diff -u -p -r1.148 kern_synch.c --- kern/kern_synch.c 23 Apr 2019 13:35:12 -0000 1.148 +++ kern/kern_synch.c 12 May 2019 18:31:08 -0000 @@ -425,7 +425,7 @@ unsleep(struct proc *p) * Make a number of processes sleeping on the specified identifier runnable. */ void -wakeup_n(const volatile void *ident, int n) +wakeup_n_id(const volatile void *ident, int n, pid_t tid) { struct slpque *qp; struct proc *p; @@ -449,24 +449,33 @@ wakeup_n(const volatile void *ident, int if (p->p_stat != SSLEEP && p->p_stat != SSTOP) panic("wakeup: p_stat is %d", (int)p->p_stat); #endif - if (p->p_wchan == ident) { + if (p->p_wchan == ident && (tid == -1 || p->p_tid == tid)) { --n; p->p_wchan = 0; TAILQ_REMOVE(qp, p, p_runq); if (p->p_stat == SSLEEP) setrunnable(p); + /* Hack for poll(2)/select(2). */ + if ((tid != -1) && (p->p_flag & P_SELECT)) + atomic_clearbits_int(&p->p_flag, P_SELECT); } } SCHED_UNLOCK(s); } +void +wakeup_n(const volatile void *ident, int n) +{ + wakeup_n_id(ident, n, -1); +} + /* * Make all processes sleeping on the specified identifier runnable. */ void wakeup(const volatile void *chan) { - wakeup_n(chan, -1); + wakeup_n_id(chan, -1, -1); } int Index: kern/sys_generic.c =================================================================== RCS file: /cvs/src/sys/kern/sys_generic.c,v retrieving revision 1.123 diff -u -p -r1.123 sys_generic.c --- kern/sys_generic.c 21 Jan 2019 23:41:26 -0000 1.123 +++ kern/sys_generic.c 12 May 2019 18:30:24 -0000 @@ -789,8 +789,7 @@ selrecord(struct proc *selector, struct void selwakeup(struct selinfo *sip) { - struct proc *p; - int s; + pid_t tid; KNOTE(&sip->si_note, NOTE_SUBMIT); if (sip->si_seltid == 0) @@ -800,19 +799,9 @@ selwakeup(struct selinfo *sip) sip->si_flags &= ~SI_COLL; wakeup(&selwait); } - p = tfind(sip->si_seltid); + tid = sip->si_seltid; sip->si_seltid = 0; - if (p != NULL) { - SCHED_LOCK(s); - if (p->p_wchan == (caddr_t)&selwait) { - if (p->p_stat == SSLEEP) - setrunnable(p); - else - unsleep(p); - } else if (p->p_flag & P_SELECT) - atomic_clearbits_int(&p->p_flag, P_SELECT); - SCHED_UNLOCK(s); - } + wakeup_n_id(&selwait, 1, tid); } void Index: sys/systm.h =================================================================== RCS file: /cvs/src/sys/sys/systm.h,v retrieving revision 1.141 diff -u -p -r1.141 systm.h --- sys/systm.h 23 Apr 2019 13:35:12 -0000 1.141 +++ sys/systm.h 12 May 2019 18:25:02 -0000 @@ -261,6 +261,7 @@ void cond_signal(struct cond *); struct mutex; struct rwlock; +void wakeup_n_id(const volatile void *, int, pid_t); void wakeup_n(const volatile void *, int); void wakeup(const volatile void *); #define wakeup_one(c) wakeup_n((c), 1)