[RFC PATCH] v4l2-event/dev: wakeup pending events when unregistering

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When the video device is unregistered any filehandles waiting on
an event (i.e. in VIDIOC_DQEVENT) will never wake up.

Wake them up and detect that the video device is unregistered in
__v4l2_event_dequeue() and return -ENODEV in that case.

Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
---
Note: this is a quick hack, just for events. We have the same problem
with vb2 (waiting for a buffer) and cec (waiting for an event). Not sure if rc
or dvb are also suffering from the same problem.

I wonder if there is an easier way to wake up all fhs that are waiting for
some event.

Michael: most applications use non-blocking mode and poll/select to wait
for something to happen. In such applications the poll/select will return
when the device is unregistered and this problem does not occur.
---
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index d5e0e536ef04..42574ccbd770 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -1017,6 +1017,9 @@ EXPORT_SYMBOL(__video_register_device);
  */
 void video_unregister_device(struct video_device *vdev)
 {
+	unsigned long flags;
+	struct v4l2_fh *fh;
+
 	/* Check if vdev was ever registered at all */
 	if (!vdev || !video_is_registered(vdev))
 		return;
@@ -1027,6 +1030,12 @@ void video_unregister_device(struct video_device *vdev)
 	 */
 	clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
 	mutex_unlock(&videodev_lock);
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+	list_for_each_entry(fh, &vdev->fh_list, list)
+		wake_up_all(&fh->wait);
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
 	device_unregister(&vdev->dev);
 }
 EXPORT_SYMBOL(video_unregister_device);
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index 968c2eb08b5a..d04977cd1bfb 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -36,12 +36,17 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 {
 	struct v4l2_kevent *kev;
 	unsigned long flags;
+	int ret = 0;

 	spin_lock_irqsave(&fh->vdev->fh_lock, flags);

+	if (!video_is_registered(fh->vdev)) {
+		ret = -ENODEV;
+		goto err;
+	}
 	if (list_empty(&fh->available)) {
-		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto err;
 	}

 	WARN_ON(fh->navailable == 0);
@@ -54,10 +59,10 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 	*event = kev->event;
 	kev->sev->first = sev_pos(kev->sev, 1);
 	kev->sev->in_use--;
-
+err:
 	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);

-	return 0;
+	return ret;
 }

 int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux