From: Brandon Philips <brandon@ifup.org>
To: mchehab@infradead.org
Cc: v4l-dvb-maintainer@linuxtv.org, Jonathan Corbet <corbet@lwn.net>,
video4linux-list@redhat.com, Trent Piepho <xyzzy@speakeasy.org>
Subject: [PATCH 8 of 9] videobuf: Avoid deadlock with QBUF and bring up to spec for empty queue
Date: Fri, 28 Mar 2008 03:18:39 -0700 [thread overview]
Message-ID: <0b7eea4e7b7dc24b1c01.1206699519@localhost> (raw)
In-Reply-To: <patchbomb.1206699511@localhost>
# HG changeset patch
# User Brandon Philips <brandon@ifup.org>
# Date 1206699281 25200
# Node ID 0b7eea4e7b7dc24b1c015e5768fdb8f70f70c751
# Parent 304e0a371d12f77e1575ae43fa0133855165f63e
videobuf: Avoid deadlock with QBUF and bring up to spec for empty queue
Add a waitqueue to wait on when there are no buffers in the buffer queue.
DQBUF waits on this queue without holding vb_lock to allow a QBUF to happen.
Once a buffer has been queued we recheck that the queue is still streaming and
wait on the new buffer's waitqueue while holding the vb_lock. The driver
should come along in a timely manner and put the buffer into its next state
finishing the DQBUF.
By implementing this waitqueue it also brings the videobuf DQBUF up to spec and
it now blocks on O_NONBLOCK even when no buffers have been queued via QBUF:
"By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue."
- V4L2 spec
CC: Trent Piepho <xyzzy@speakeasy.org>
CC: Carl Karsten <carl@personnelware.com>
CC: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Brandon Philips <bphilips@suse.de>
---
linux/drivers/media/video/videobuf-core.c | 96 +++++++++++++++++++++++-------
linux/include/media/videobuf-core.h | 2
2 files changed, 78 insertions(+), 20 deletions(-)
diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c
--- a/linux/drivers/media/video/videobuf-core.c
+++ b/linux/drivers/media/video/videobuf-core.c
@@ -140,6 +140,7 @@ void videobuf_queue_core_init(struct vid
BUG_ON(!q->int_ops);
mutex_init(&q->vb_lock);
+ init_waitqueue_head(&q->wait);
INIT_LIST_HEAD(&q->stream);
}
@@ -186,6 +187,10 @@ void videobuf_queue_cancel(struct videob
{
unsigned long flags = 0;
int i;
+
+ q->streaming = 0;
+ q->reading = 0;
+ wake_up_all(&q->wait);
/* remove queued buffers from list */
spin_lock_irqsave(q->irqlock, flags);
@@ -561,6 +566,7 @@ int videobuf_qbuf(struct videobuf_queue
}
dprintk(1, "qbuf: succeded\n");
retval = 0;
+ wake_up(&q->wait);
done:
mutex_unlock(&q->vb_lock);
@@ -571,37 +577,88 @@ int videobuf_qbuf(struct videobuf_queue
return retval;
}
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
+{
+ int retval;
+
+checks:
+ if (!q->streaming) {
+ dprintk(1, "next_buffer: Not streaming\n");
+ retval = -EINVAL;
+ goto done;
+ }
+
+ if (list_empty(&q->stream)) {
+ if (noblock) {
+ retval = -EAGAIN;
+ dprintk(2, "next_buffer: no buffers to dequeue\n");
+ goto done;
+ } else {
+ dprintk(2, "next_buffer: waiting on buffer\n");
+
+ /* Drop lock to avoid deadlock with qbuf */
+ mutex_unlock(&q->vb_lock);
+
+ /* Checking list_empty and streaming is safe without
+ * locks because we goto checks to validate while
+ * holding locks before proceeding */
+ retval = wait_event_interruptible(q->wait,
+ !list_empty(&q->stream) || !q->streaming);
+ mutex_lock(&q->vb_lock);
+
+ if (retval)
+ goto done;
+
+ goto checks;
+ }
+ }
+
+ retval = 0;
+
+done:
+ return retval;
+}
+
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer(struct videobuf_queue *q,
+ struct videobuf_buffer **vb, int nonblocking)
+{
+ int retval;
+ struct videobuf_buffer *buf = NULL;
+
+ retval = stream_next_buffer_check_queue(q, nonblocking);
+ if (retval)
+ goto done;
+
+ buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+ retval = videobuf_waiton(buf, nonblocking, 1);
+ if (retval < 0)
+ goto done;
+
+ *vb = buf;
+done:
+ return retval;
+}
+
int videobuf_dqbuf(struct videobuf_queue *q,
struct v4l2_buffer *b, int nonblocking)
{
- struct videobuf_buffer *buf;
+ struct videobuf_buffer *buf = NULL;
int retval;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
mutex_lock(&q->vb_lock);
- retval = -EBUSY;
- if (q->reading) {
- dprintk(1, "dqbuf: Reading running...\n");
+
+ retval = stream_next_buffer(q, &buf, nonblocking);
+ if (retval < 0) {
+ dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
goto done;
}
- retval = -EINVAL;
- if (b->type != q->type) {
- dprintk(1, "dqbuf: Wrong type.\n");
- goto done;
- }
- if (list_empty(&q->stream)) {
- dprintk(1, "dqbuf: stream running\n");
- goto done;
- }
- buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
- mutex_unlock(&q->vb_lock);
- retval = videobuf_waiton(buf, nonblocking, 1);
- mutex_lock(&q->vb_lock);
- if (retval < 0) {
- dprintk(1, "dqbuf: waiton returned %d\n", retval);
- goto done;
- }
+
switch (buf->state) {
case VIDEOBUF_ERROR:
dprintk(1, "dqbuf: state is error\n");
@@ -648,6 +705,7 @@ int videobuf_streamon(struct videobuf_qu
q->ops->buf_queue(q, buf);
spin_unlock_irqrestore(q->irqlock, flags);
+ wake_up(&q->wait);
done:
mutex_unlock(&q->vb_lock);
return retval;
@@ -660,7 +718,6 @@ static int __videobuf_streamoff(struct v
return -EINVAL;
videobuf_queue_cancel(q);
- q->streaming = 0;
return 0;
}
@@ -858,7 +915,6 @@ static void __videobuf_read_stop(struct
q->bufs[i] = NULL;
}
q->read_buf = NULL;
- q->reading = 0;
}
diff --git a/linux/include/media/videobuf-core.h b/linux/include/media/videobuf-core.h
--- a/linux/include/media/videobuf-core.h
+++ b/linux/include/media/videobuf-core.h
@@ -159,6 +159,8 @@ struct videobuf_queue {
spinlock_t *irqlock;
struct device *dev;
+ wait_queue_head_t wait; /* wait if queue is empty */
+
enum v4l2_buf_type type;
unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */
unsigned int msize;
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
next prev parent reply other threads:[~2008-03-28 10:34 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-28 10:18 [PATCH 0 of 9] videobuf fixes Brandon Philips
2008-03-28 10:18 ` [PATCH 1 of 9] soc_camera: Introduce a spinlock for use with videobuf Brandon Philips
2008-03-28 20:53 ` Guennadi Liakhovetski
2008-03-29 3:59 ` Brandon Philips
2008-04-04 13:46 ` [PATCH] soc-camera: use a spinlock for videobuffer queue Guennadi Liakhovetski
2008-04-04 20:17 ` Brandon Philips
2008-03-28 10:18 ` [PATCH 2 of 9] videobuf: Require spinlocks for all videobuf users Brandon Philips
2008-03-28 10:18 ` [PATCH 3 of 9] videobuf: Wakeup queues after changing the state to ERROR Brandon Philips
2008-03-28 10:18 ` [PATCH 4 of 9] videobuf: Simplify videobuf_waiton logic and possibly avoid missed wakeup Brandon Philips
2008-03-28 10:18 ` [PATCH 5 of 9] videobuf-vmalloc.c: Remove buf_release from videobuf_vm_close Brandon Philips
2008-03-28 10:18 ` [PATCH 6 of 9] videobuf-vmalloc.c: Fix hack of postponing mmap on remap failure Brandon Philips
[not found] ` <20080405131236.7c083554@gaivota>
[not found] ` <20080406080011.GA3596@plankton.ifup.org>
[not found] ` <20080407183226.703217fc@gaivota>
[not found] ` <20080408152238.GA8438@plankton.public.utexas.edu>
2008-04-08 18:40 ` Mauro Carvalho Chehab
[not found] ` <c8b4dbe10804081306xb1e8f91q64d1e6d18d3d2531@mail.gmail.com>
2008-04-08 20:50 ` Mauro Carvalho Chehab
[not found] ` <c8b4dbe10804090626l6b2b10d9p1c22e02dfe2850fe@mail.gmail.com>
2008-04-09 20:42 ` Mauro Carvalho Chehab
[not found] ` <20080408204514.GA6844@plankton.public.utexas.edu>
2008-04-08 21:37 ` Mauro Carvalho Chehab
[not found] ` <20080415021558.GA22068@plankton.ifup.org>
2008-04-15 14:10 ` Mauro Carvalho Chehab
2008-03-28 10:18 ` [PATCH 7 of 9] vivi: Simplify the vivi driver and avoid deadlocks Brandon Philips
2008-03-28 18:34 ` Mauro Carvalho Chehab
2008-03-29 5:35 ` Brandon Philips
2008-03-31 19:35 ` Mauro Carvalho Chehab
2008-03-28 10:18 ` Brandon Philips [this message]
2008-03-28 10:18 ` [PATCH 9 of 9] videobuf-dma-sg.c: Avoid NULL dereference and add comment about backwards compatibility Brandon Philips
2008-03-28 19:09 ` [PATCH 0 of 9] videobuf fixes Mauro Carvalho Chehab
2008-03-29 5:25 ` Brandon Philips
2008-03-29 22:49 ` Vanessa Ezekowitz
2008-03-31 18:35 ` Mauro Carvalho Chehab
2008-03-31 19:26 ` Brandon Philips
2008-03-31 21:31 ` Mauro Carvalho Chehab
2008-04-01 3:11 ` Brandon Philips
2008-04-01 20:49 ` Mauro Carvalho Chehab
2008-04-02 18:54 ` Brandon Philips
2008-04-02 20:06 ` Mauro Carvalho Chehab
2008-04-02 18:56 ` Brandon Philips
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0b7eea4e7b7dc24b1c01.1206699519@localhost \
--to=brandon@ifup.org \
--cc=corbet@lwn.net \
--cc=mchehab@infradead.org \
--cc=v4l-dvb-maintainer@linuxtv.org \
--cc=video4linux-list@redhat.com \
--cc=xyzzy@speakeasy.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox