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)
{