Diff below adds a per-thread kqueue that will be initialized during the
first select(2) or poll(2) syscall and freed upon exit.

Along with this queue a per-thread serial number is used to check the
integrity of events enqueued during a given syscall.  This could also
later be used to perform lazy removal of events.

Ok?

Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.146
diff -u -p -r1.146 kern_event.c
--- kern/kern_event.c   7 Dec 2020 11:15:50 -0000       1.146
+++ kern/kern_event.c   7 Dec 2020 17:00:13 -0000
@@ -57,6 +57,7 @@
 #include <sys/timeout.h>
 #include <sys/wait.h>
 
+struct kqueue *kqueue_alloc(struct filedesc *);
 void   kqueue_terminate(struct proc *p, struct kqueue *);
 void   kqueue_free(struct kqueue *);
 void   kqueue_init(void);
@@ -504,6 +505,31 @@ const struct filterops dead_filtops = {
        .f_event        = filt_dead,
 };
 
+void
+kqpoll_init(void)
+{
+       struct proc *p = curproc;
+
+       if (p->p_kq != NULL)
+               return;
+
+       p->p_kq = kqueue_alloc(p->p_fd);
+       p->p_kq_serial = arc4random();
+}
+
+void
+kqpoll_exit(void)
+{
+       struct proc *p = curproc;
+
+       if (p->p_kq == NULL)
+               return;
+
+       kqueue_terminate(p, p->p_kq);
+       kqueue_free(p->p_kq);
+       p->p_kq = NULL;
+}
+
 struct kqueue *
 kqueue_alloc(struct filedesc *fdp)
 {
@@ -1144,7 +1170,7 @@ kqueue_stat(struct file *fp, struct stat
 }
 
 void
-kqueue_terminate(struct proc *p, struct kqueue *kq)
+kqueue_purge(struct proc *p, struct kqueue *kq)
 {
        int i;
 
@@ -1156,6 +1182,12 @@ kqueue_terminate(struct proc *p, struct 
                for (i = 0; i < kq->kq_knhashmask + 1; i++)
                        knote_remove(p, &kq->kq_knhash[i]);
        }
+}
+
+void
+kqueue_terminate(struct proc *p, struct kqueue *kq)
+{
+       kqueue_purge(p, kq);
        kq->kq_state |= KQ_DYING;
        kqueue_wakeup(kq);
 
Index: kern/kern_exit.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.191
diff -u -p -r1.191 kern_exit.c
--- kern/kern_exit.c    16 Nov 2020 18:37:06 -0000      1.191
+++ kern/kern_exit.c    7 Dec 2020 17:03:50 -0000
@@ -184,6 +184,8 @@ exit1(struct proc *p, int xexit, int xsi
        if ((p->p_flag & P_THREAD) == 0)
                pr->ps_siglist = 0;
 
+       kqpoll_exit();
+
 #if NKCOV > 0
        kcov_exit(p);
 #endif
Index: sys/event.h
===================================================================
RCS file: /cvs/src/sys/sys/event.h,v
retrieving revision 1.48
diff -u -p -r1.48 event.h
--- sys/event.h 7 Dec 2020 11:15:50 -0000       1.48
+++ sys/event.h 7 Dec 2020 17:01:10 -0000
@@ -215,6 +215,8 @@ struct timespec;
 extern const struct filterops sig_filtops;
 extern const struct filterops dead_filtops;
 
+extern void    kqpoll_init(void);
+extern void    kqpoll_exit(void);
 extern void    knote(struct klist *list, long hint);
 extern void    knote_activate(struct knote *);
 extern void    knote_remove(struct proc *p, struct knlist *list);
@@ -226,6 +228,7 @@ extern int  kqueue_scan(struct kqueue_sca
                    struct timespec *, struct proc *, int *);
 extern void    kqueue_scan_setup(struct kqueue_scan_state *, struct kqueue *);
 extern void    kqueue_scan_finish(struct kqueue_scan_state *);
+extern void    kqueue_purge(struct proc *, struct kqueue *);
 extern int     filt_seltrue(struct knote *kn, long hint);
 extern int     seltrue_kqfilter(dev_t, struct knote *);
 extern void    klist_insert(struct klist *, struct knote *);
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.301
diff -u -p -r1.301 proc.h
--- sys/proc.h  10 Nov 2020 17:26:54 -0000      1.301
+++ sys/proc.h  7 Dec 2020 17:03:17 -0000
@@ -320,6 +320,7 @@ struct process {
 
 struct kcov_dev;
 struct lock_list_entry;
+struct kqueue;
 
 struct p_inentry {
        u_long   ie_serial;
@@ -382,6 +383,8 @@ struct proc {
        struct  plimit  *p_limit;       /* [l] read ref. of p_p->ps_limit */
        struct  kcov_dev *p_kd;         /* kcov device handle */
        struct  lock_list_entry *p_sleeplocks;  /* WITNESS lock tracking */ 
+       struct  kqueue *p_kq;           /* [o] select/poll queue of evts */
+       unsigned long p_kq_serial;      /* [o] to check against enqueued evts */
 
        int      p_siglist;             /* [a] Signals arrived & not delivered*/
 

Reply via email to