Diff below extends the existing drmkqfilter() to support EVFILT_READ.
This makes drm(4)'s kqueue support in pair with poll().

The event list queried in the filt_drmread() should be protected by the
`event_lock' mutex.  This could be done by using the `kdev' backpointer
as shown in comment.  However this would require some plumbing to make
use of `minor'.  The side effect of this approach would be to reduce the
diff with Linux.

I'd be interested to hear if somebody sees a different approach.

That said, as long as the KERNEL_LOCK() is taken in all these code paths
it should be safe to commit the filter as it is.

Comments, Oks?

Index: sys/conf.h
===================================================================
RCS file: /cvs/src/sys/sys/conf.h,v
retrieving revision 1.150
diff -u -p -r1.150 conf.h
--- sys/conf.h  21 Apr 2020 08:29:27 -0000      1.150
+++ sys/conf.h  27 Apr 2020 14:43:48 -0000
@@ -439,7 +439,7 @@ extern struct cdevsw cdevsw[];
        (dev_type_stop((*))) enodev, 0, selfalse, \
        (dev_type_mmap((*))) enodev }
 
-/* open, close, read, ioctl, poll, mmap, nokqfilter */
+/* open, close, read, ioctl, poll, mmap, kqfilter */
 #define      cdev_drm_init(c,n)        { \
        dev_init(c,n,open), dev_init(c,n,close), dev_init(c, n, read), \
        (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
Index: dev/pci/drm/drm_drv.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/drm_drv.c,v
retrieving revision 1.174
diff -u -p -r1.174 drm_drv.c
--- dev/pci/drm/drm_drv.c       7 Apr 2020 13:27:51 -0000       1.174
+++ dev/pci/drm/drm_drv.c       27 Apr 2020 14:43:48 -0000
@@ -484,6 +484,30 @@ filt_drmkms(struct knote *kn, long hint)
        return (kn->kn_fflags != 0);
 }
 
+void
+filt_drmreaddetach(struct knote *kn)
+{
+       struct drm_file         *file_priv = kn->kn_hook;
+       int s;
+
+       s = spltty();
+       klist_remove(&file_priv->rsel.si_note, kn);
+       splx(s);
+}
+
+int
+filt_drmread(struct knote *kn, long hint)
+{
+       struct drm_file         *file_priv = kn->kn_hook;
+       int                      val = 0;
+
+       //mtx_enter(&file_priv->minor->kdev->event_lock);
+       val = !list_empty(&file_priv->event_list);
+       //mtx_leave(&file_priv->minor->kdev->event_lock);
+
+       return (val);
+}
+
 const struct filterops drm_filtops = {
        .f_flags        = FILTEROP_ISFD,
        .f_attach       = NULL,
@@ -491,30 +515,51 @@ const struct filterops drm_filtops = {
        .f_event        = filt_drmkms,
 };
 
+const struct filterops drmread_filtops = {
+       .f_flags        = FILTEROP_ISFD,
+       .f_attach       = NULL,
+       .f_detach       = filt_drmreaddetach,
+       .f_event        = filt_drmread,
+};
+
 int
 drmkqfilter(dev_t kdev, struct knote *kn)
 {
        struct drm_device       *dev = NULL;
-       int s;
+       struct drm_file         *file_priv = NULL;
+       int                      s;
 
        dev = drm_get_device_from_kdev(kdev);
        if (dev == NULL || dev->dev_private == NULL)
                return (ENXIO);
 
        switch (kn->kn_filter) {
+       case EVFILT_READ:
+               mutex_lock(&dev->struct_mutex);
+               file_priv = drm_find_file_by_minor(dev, minor(kdev));
+               mutex_unlock(&dev->struct_mutex);
+               if (file_priv == NULL)
+                       return (ENXIO);
+
+               kn->kn_fop = &drmread_filtops;
+               kn->kn_hook = file_priv;
+
+               s = spltty();
+               klist_insert(&file_priv->rsel.si_note, kn);
+               splx(s);
+               break;
        case EVFILT_DEVICE:
                kn->kn_fop = &drm_filtops;
+               kn->kn_hook = dev;
+
+               s = spltty();
+               klist_insert(&dev->note, kn);
+               splx(s);
                break;
        default:
                return (EINVAL);
        }
 
-       kn->kn_hook = dev;
-
-       s = spltty();
-       klist_insert(&dev->note, kn);
-       splx(s);
-
        return (0);
 }
 
@@ -772,7 +817,6 @@ out:
        return (gotone);
 }
 
-/* XXX kqfilter ... */
 int
 drmpoll(dev_t kdev, int events, struct proc *p)
 {

Reply via email to