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)

Reply via email to