aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrandon Philips <brandon@ifup.org>2008-04-02 17:10:59 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:57 -0400
commit137d1cb19d9da163ce6cb57a6fa1e6a3468af6a4 (patch)
tree197f2548c82390d9c0a730c26d548752fdca12ad
parent78718e5d44cd450431d5b16ee36d3a7de1db6dfa (diff)
V4L/DVB (7493): 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 Signed-off-by: Brandon Philips <bphilips@suse.de> CC: Trent Piepho <xyzzy@speakeasy.org> CC: Carl Karsten <carl@personnelware.com> CC: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/videobuf-core.c96
-rw-r--r--include/media/videobuf-core.h2
2 files changed, 78 insertions, 20 deletions
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 1ba3aaa29dd0..3ab556093ca7 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -141,6 +141,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
141 BUG_ON(!q->int_ops); 141 BUG_ON(!q->int_ops);
142 142
143 mutex_init(&q->vb_lock); 143 mutex_init(&q->vb_lock);
144 init_waitqueue_head(&q->wait);
144 INIT_LIST_HEAD(&q->stream); 145 INIT_LIST_HEAD(&q->stream);
145} 146}
146 147
@@ -188,6 +189,10 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
188 unsigned long flags = 0; 189 unsigned long flags = 0;
189 int i; 190 int i;
190 191
192 q->streaming = 0;
193 q->reading = 0;
194 wake_up_interruptible_sync(&q->wait);
195
191 /* remove queued buffers from list */ 196 /* remove queued buffers from list */
192 if (q->irqlock) 197 if (q->irqlock)
193 spin_lock_irqsave(q->irqlock, flags); 198 spin_lock_irqsave(q->irqlock, flags);
@@ -565,6 +570,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
565 } 570 }
566 dprintk(1, "qbuf: succeded\n"); 571 dprintk(1, "qbuf: succeded\n");
567 retval = 0; 572 retval = 0;
573 wake_up_interruptible_sync(&q->wait);
568 574
569 done: 575 done:
570 mutex_unlock(&q->vb_lock); 576 mutex_unlock(&q->vb_lock);
@@ -575,37 +581,88 @@ int videobuf_qbuf(struct videobuf_queue *q,
575 return retval; 581 return retval;
576} 582}
577 583
578int videobuf_dqbuf(struct videobuf_queue *q, 584
579 struct v4l2_buffer *b, int nonblocking) 585/* Locking: Caller holds q->vb_lock */
586static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
580{ 587{
581 struct videobuf_buffer *buf;
582 int retval; 588 int retval;
583 589
584 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); 590checks:
585 591 if (!q->streaming) {
586 mutex_lock(&q->vb_lock); 592 dprintk(1, "next_buffer: Not streaming\n");
587 retval = -EBUSY; 593 retval = -EINVAL;
588 if (q->reading) {
589 dprintk(1, "dqbuf: Reading running...\n");
590 goto done;
591 }
592 retval = -EINVAL;
593 if (b->type != q->type) {
594 dprintk(1, "dqbuf: Wrong type.\n");
595 goto done; 594 goto done;
596 } 595 }
596
597 if (list_empty(&q->stream)) { 597 if (list_empty(&q->stream)) {
598 dprintk(1, "dqbuf: stream running\n"); 598 if (noblock) {
599 goto done; 599 retval = -EAGAIN;
600 dprintk(2, "next_buffer: no buffers to dequeue\n");
601 goto done;
602 } else {
603 dprintk(2, "next_buffer: waiting on buffer\n");
604
605 /* Drop lock to avoid deadlock with qbuf */
606 mutex_unlock(&q->vb_lock);
607
608 /* Checking list_empty and streaming is safe without
609 * locks because we goto checks to validate while
610 * holding locks before proceeding */
611 retval = wait_event_interruptible(q->wait,
612 !list_empty(&q->stream) || !q->streaming);
613 mutex_lock(&q->vb_lock);
614
615 if (retval)
616 goto done;
617
618 goto checks;
619 }
600 } 620 }
621
622 retval = 0;
623
624done:
625 return retval;
626}
627
628
629/* Locking: Caller holds q->vb_lock */
630static int stream_next_buffer(struct videobuf_queue *q,
631 struct videobuf_buffer **vb, int nonblocking)
632{
633 int retval;
634 struct videobuf_buffer *buf = NULL;
635
636 retval = stream_next_buffer_check_queue(q, nonblocking);
637 if (retval)
638 goto done;
639
601 buf = list_entry(q->stream.next, struct videobuf_buffer, stream); 640 buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
602 mutex_unlock(&q->vb_lock);
603 retval = videobuf_waiton(buf, nonblocking, 1); 641 retval = videobuf_waiton(buf, nonblocking, 1);
642 if (retval < 0)
643 goto done;
644
645 *vb = buf;
646done:
647 return retval;
648}
649
650int videobuf_dqbuf(struct videobuf_queue *q,
651 struct v4l2_buffer *b, int nonblocking)
652{
653 struct videobuf_buffer *buf = NULL;
654 int retval;
655
656 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
657
604 mutex_lock(&q->vb_lock); 658 mutex_lock(&q->vb_lock);
659
660 retval = stream_next_buffer(q, &buf, nonblocking);
605 if (retval < 0) { 661 if (retval < 0) {
606 dprintk(1, "dqbuf: waiton returned %d\n", retval); 662 dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
607 goto done; 663 goto done;
608 } 664 }
665
609 switch (buf->state) { 666 switch (buf->state) {
610 case VIDEOBUF_ERROR: 667 case VIDEOBUF_ERROR:
611 dprintk(1, "dqbuf: state is error\n"); 668 dprintk(1, "dqbuf: state is error\n");
@@ -654,6 +711,7 @@ int videobuf_streamon(struct videobuf_queue *q)
654 if (q->irqlock) 711 if (q->irqlock)
655 spin_unlock_irqrestore(q->irqlock, flags); 712 spin_unlock_irqrestore(q->irqlock, flags);
656 713
714 wake_up_interruptible_sync(&q->wait);
657 done: 715 done:
658 mutex_unlock(&q->vb_lock); 716 mutex_unlock(&q->vb_lock);
659 return retval; 717 return retval;
@@ -666,7 +724,6 @@ static int __videobuf_streamoff(struct videobuf_queue *q)
666 return -EINVAL; 724 return -EINVAL;
667 725
668 videobuf_queue_cancel(q); 726 videobuf_queue_cancel(q);
669 q->streaming = 0;
670 727
671 return 0; 728 return 0;
672} 729}
@@ -869,7 +926,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
869 q->bufs[i] = NULL; 926 q->bufs[i] = NULL;
870 } 927 }
871 q->read_buf = NULL; 928 q->read_buf = NULL;
872 q->reading = 0;
873 929
874} 930}
875 931
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index fcdffdd63304..377a6c6e931b 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -153,6 +153,8 @@ struct videobuf_queue {
153 spinlock_t *irqlock; 153 spinlock_t *irqlock;
154 struct device *dev; 154 struct device *dev;
155 155
156 wait_queue_head_t wait; /* wait if queue is empty */
157
156 enum v4l2_buf_type type; 158 enum v4l2_buf_type type;
157 unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ 159 unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */
158 unsigned int msize; 160 unsigned int msize;