From patchwork Tue Jun 21 18:27:22 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 902722 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p5LIRfIK021944 for ; Tue, 21 Jun 2011 18:28:04 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1EBC89EF96 for ; Tue, 21 Jun 2011 11:27:41 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from fireflyinternet.com (server109-228-6-236.live-servers.net [109.228.6.236]) by gabe.freedesktop.org (Postfix) with ESMTP id 8B9049E885 for ; Tue, 21 Jun 2011 11:27:31 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.66.37; Received: from arrandale.alporthouse.com (unverified [78.156.66.37]) by fireflyinternet.com (Firefly Internet SMTP) with ESMTP id 37612191-1500050 for multiple; Tue, 21 Jun 2011 19:27:23 +0100 From: Chris Wilson To: dri-devel@lists.freedesktop.org Subject: [PATCH] drm: Honour O_NONBLOCK on the device for reading events Date: Tue, 21 Jun 2011 19:27:22 +0100 Message-Id: <1308680842-10735-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <20110608234035.04a3498f@lxorguk.ukuu.org.uk> References: <20110608234035.04a3498f@lxorguk.ukuu.org.uk> X-Originating-IP: 78.156.66.37 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Tue, 21 Jun 2011 18:28:04 +0000 (UTC) Otherwise drmHandleEvent will block if accidentally read too often. In order to handle the case where the event is read off the queue by another thread before we dequeue the event, we delay the actual checking for EAGAIN to under the spinlock and so inline drm_dequeue_event(). Signed-off-by: Chris Wilson --- drivers/gpu/drm/drm_fops.c | 76 +++++++++++++++++++++----------------------- 1 files changed, 36 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 2ec7d48..d248366 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -580,61 +580,57 @@ int drm_release(struct inode *inode, struct file *filp) } EXPORT_SYMBOL(drm_release); -static bool -drm_dequeue_event(struct drm_file *file_priv, - size_t total, size_t max, struct drm_pending_event **out) +ssize_t drm_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset) { + struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; struct drm_pending_event *e; unsigned long flags; - bool ret = false; - - spin_lock_irqsave(&dev->event_lock, flags); + ssize_t ret; + int err; - *out = NULL; - if (list_empty(&file_priv->event_list)) - goto out; - e = list_first_entry(&file_priv->event_list, - struct drm_pending_event, link); - if (e->event->length + total > max) - goto out; + if ((filp->f_flags & O_NONBLOCK) == 0) { + ret = wait_event_interruptible(file_priv->event_wait, + !list_empty(&file_priv->event_list)); + if (ret < 0) + return ret; + } - file_priv->event_space += e->event->length; - list_del(&e->link); - *out = e; - ret = true; + ret = err = 0; + spin_lock_irqsave(&dev->event_lock, flags); + do { + if (list_empty(&file_priv->event_list)) { + if (flip->f_flags & O_NONBLOCK) + err = -EAGAIN; + break; + } -out: - spin_unlock_irqrestore(&dev->event_lock, flags); - return ret; -} + e = list_first_entry(&file_priv->event_list, + struct drm_pending_event, link); + if (e->event->length + ret > max) { + err = -EINVAL; + break; + } -ssize_t drm_read(struct file *filp, char __user *buffer, - size_t count, loff_t *offset) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_pending_event *e; - size_t total; - ssize_t ret; + file_priv->event_space += e->event->length; + list_del(&e->link); - ret = wait_event_interruptible(file_priv->event_wait, - !list_empty(&file_priv->event_list)); - if (ret < 0) - return ret; + spin_unlock_irqrestore(&dev->event_lock, flags); - total = 0; - while (drm_dequeue_event(file_priv, total, count, &e)) { - if (copy_to_user(buffer + total, - e->event, e->event->length)) { - total = -EFAULT; + if (copy_to_user(buffer + ret, e->event, e->event->length)) { + err = -EFAULT; break; } - total += e->event->length; + ret += e->event->length; e->destroy(e); - } - return total; + spin_lock_irqsave(&dev->event_lock, flags); + } while (1); + spin_unlock_irqrestore(&dev->event_lock, flags); + + return ret ? ret : err; } EXPORT_SYMBOL(drm_read);