I've updated the drm.watchdog.2.patch
http://marc.theaimsgroup.com/?l=dri-devel&m=108551485018672&w=2
to latest DRM CVS and it works together with
"ati.unlock.1.patch" and "ati.drm-r300-version.1.patch"
http://marc.theaimsgroup.com/?l=dri-devel&m=108551675805810&w=2
when the UT2003/2004 lockups ('Shock Rifle') arise.

But the 3D engine wouldn't run again before a hard reset take place ;-(
Any newly started 3D app would be stopped after an empty window popped up.

setenv R200_DEBUG sanity
progs/demos> ./ipers >& log

gave some weird numbers

   R200_VS_LIGHT_ATTENUATION_ADDR[2] <-- 1.000 *** NEW MAX (prev 0.000)
   R200_SS_LIGHT_RANGE_CUTOFF_SQRD <-- 
340282346638528859811704183484516925440.000 *** NEW MAX (prev 0.000)

Any hints?

-Dieter
diff -ru drm.orig/linux/drm_drv.h drm/linux/drm_drv.h
--- drm.orig/linux/drm_drv.h	2004-09-13 12:46:47.000000000 +0200
+++ drm/linux/drm_drv.h	2004-09-13 21:39:40.657676794 +0200
@@ -185,6 +185,8 @@
 MODULE_PARM( drm_opts, "s" );
 MODULE_LICENSE("GPL and additional rights");
 
+static void drm_lock_watchdog( unsigned long __data );
+
 static int DRM(setup)( drm_device_t *dev )
 {
 	int i;
@@ -323,6 +325,7 @@
 
 	down( &dev->struct_sem );
 	del_timer( &dev->timer );
+	del_timer_sync( &dev->lock.watchdog );
 
 	if ( dev->devname ) {
 		DRM(free)( dev->devname, strlen( dev->devname ) + 1,
@@ -433,6 +436,7 @@
 	if ( dev->lock.hw_lock ) {
 		dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
 		dev->lock.filp = NULL;
+		dev->lock.dontbreak = 1;
 		wake_up_interruptible( &dev->lock.lock_queue );
 	}
 	up( &dev->struct_sem );
@@ -530,6 +534,10 @@
 	  goto error_out;
 	}
 
+	init_timer( &dev->lock.watchdog );
+	dev->lock.watchdog.data = (unsigned long) dev;
+	dev->lock.watchdog.function = drm_lock_watchdog;
+
 	if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
 	{
 		retcode = -EPERM;
@@ -888,6 +896,11 @@
 		if (dev->fn_tbl.release)
 			dev->fn_tbl.release(dev, filp);
 
+		/* Avoid potential race where the watchdog callback is still
+		 * running when filp is freed.
+		 */
+                del_timer_sync( &dev->lock.watchdog );
+
 		DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
 				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
 
@@ -910,6 +923,7 @@
 			}
 			if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 					     DRM_KERNEL_CONTEXT ) ) {
+				dev->lock.dontbreak = 1;
 				dev->lock.filp	    = filp;
 				dev->lock.lock_time = jiffies;
                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
@@ -1060,6 +1074,40 @@
 	return retcode;
 }
 
+
+/**
+ * Lock watchdog callback function.
+ *
+ * Whenever a privileged client must sleep on the lock waitqueue
+ * in the LOCK ioctl, the watchdog timer is started.
+ * When the UNLOCK ioctl is called, the timer is stopped.
+ *
+ * When the watchdog timer expires, the process holding the lock
+ * is killed. Privileged clients set lock.dontbreak and are exempt
+ * from this rule.
+ */
+static void drm_lock_watchdog( unsigned long __data )
+{
+	drm_device_t *dev = (drm_device_t *)__data;
+	drm_file_t *priv;
+	
+	if ( !dev->lock.filp ) {
+		DRM_DEBUG( "held by kernel\n" );
+		return;
+	}
+	
+	if ( dev->lock.dontbreak ) {
+		DRM_DEBUG( "privileged lock\n" );
+		return;
+	}
+	
+	priv = dev->lock.filp->private_data;
+	DRM_DEBUG( "Kill pid=%d\n", priv->pid );
+	
+	kill_proc( priv->pid, SIGKILL, 1 );
+}
+
+
 /** 
  * Lock ioctl.
  *
@@ -1079,6 +1127,7 @@
         DECLARE_WAITQUEUE( entry, current );
         drm_lock_t lock;
         int ret = 0;
+	int privileged = capable( CAP_SYS_ADMIN );
 
 	++priv->lock_count;
 
@@ -1109,6 +1158,7 @@
 		}
 		if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 				     lock.context ) ) {
+			dev->lock.dontbreak = privileged;
 			dev->lock.filp      = filp;
 			dev->lock.lock_time = jiffies;
 			atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
@@ -1116,6 +1166,14 @@
 		}
 		
 		/* Contention */
+
+		if ( privileged ) {
+			if ( !timer_pending( &dev->lock.watchdog ) ) {
+				DRM_DEBUG( "Starting lock watchdog\n" );
+				mod_timer( &dev->lock.watchdog, jiffies + 5 * HZ );
+			}
+		}
+
 		schedule();
 		if ( signal_pending( current ) ) {
 			ret = -ERESTARTSYS;
@@ -1180,8 +1238,12 @@
 		return -EINVAL;
 	}
 
+	DRM_DEBUG( "\n" );
+
 	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
 
+	del_timer_sync( &dev->lock.watchdog );
+
 	if (dev->fn_tbl.kernel_context_switch_unlock)
 		dev->fn_tbl.kernel_context_switch_unlock(dev);
 	else
diff -ru drm.orig/linux/drmP.h drm/linux/drmP.h
--- drm.orig/linux/drmP.h	2004-09-05 17:42:45.000000000 +0200
+++ drm/linux/drmP.h	2004-09-13 16:22:16.000000000 +0200
@@ -403,6 +403,8 @@
 	struct file       *filp;	/**< File descr of lock holder (0=kernel) */
 	wait_queue_head_t lock_queue;	/**< Queue of blocked processes */
 	unsigned long	  lock_time;	/**< Time of last lock in jiffies */
+	struct timer_list watchdog;	/**< Watchdog timer to kill runaway processes */
+	int               dontbreak;	/**< Even watchdog honours the current lock */
 } drm_lock_data_t;
 
 /**

Reply via email to