From c6be27401fbc12ec72bac13d07e3cc93bd63732a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:34:30 +0200 Subject: Trap and be verbose about a deadlock that occurs with AIGLX and drivers that use drm_reclaim_buffers_locked(). --- linux-core/drm_fops.c | 16 ++++++++++++++-- linux-core/drm_lock.c | 8 +++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index dcc05a0a..e4385cf6 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -421,14 +421,26 @@ int drm_release(struct inode *inode, struct file *filp) dev->open_count); if (dev->driver->reclaim_buffers_locked) { - retcode = drm_kernel_take_hw_lock(filp); + unsigned long _end = jiffies + DRM_HZ*3; + + do { + retcode = drm_kernel_take_hw_lock(filp); + } while(retcode && !time_after_eq(jiffies,_end)); + if (!retcode) { dev->driver->reclaim_buffers_locked(dev, filp); drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + } else { + DRM_ERROR("Reclaim buffers locked deadlock.\n"); + DRM_ERROR("This is probably a single thread having multiple\n"); + DRM_ERROR("DRM file descriptors open either dying or " + "closing file descriptors\n"); + DRM_ERROR("while having the lock. I will not reclaim buffers.\n"); + DRM_ERROR("Locking context is 0x%08x\n", + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); } - } else if (drm_i_have_hw_lock(filp)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 04c145a6..0cf183a7 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -343,6 +343,7 @@ int drm_kernel_take_hw_lock(struct file *filp) DRM_DEVICE; int ret = 0; + unsigned long _end = jiffies + 3*DRM_HZ; if (!drm_i_have_hw_lock(filp)) { @@ -364,7 +365,12 @@ int drm_kernel_take_hw_lock(struct file *filp) break; /* Got lock */ } /* Contention */ - schedule(); + if (time_after_eq(jiffies,_end)) { + ret = -EBUSY; + break; + } + + schedule_timeout(1); if (signal_pending(current)) { ret = -ERESTARTSYS; break; -- cgit v1.2.3