This is a patch to call the context handles destructors and free the context bitmap entries when a process does not destroy its contexts before it exits. It saves context handles in a linked list in the drm_device struct. I decided to use per device list instead of a per file descriptor list for simplicity because the number of contexts will usually be small. A new semaphore, ctxlist_sem, is added to the drm_device struct because the patch will call functions that will down the struct_sem during list traversal. The patch is generated against the DRI CVS tree that is updated at 02-19-2004. It should also apply to the VIA branch with the exception that the line that calls sema_init would fail.

Thanks,
Erdi Chen
diff -Nru drm-orig/drm_context.h drm/drm_context.h
--- drm-orig/drm_context.h      2003-05-26 17:37:32.000000000 -0700
+++ drm/drm_context.h   2004-02-19 23:10:00.333785800 -0800
@@ -402,6 +402,7 @@
 {
        drm_file_t *priv = filp->private_data;
        drm_device_t *dev = priv->dev;
+       drm_ctx_list_t * ctx_entry;
        drm_ctx_t ctx;
 
        if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
@@ -422,6 +423,20 @@
        if ( ctx.handle != DRM_KERNEL_CONTEXT )
                DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */
 #endif
+       ctx_entry = DRM(alloc)( sizeof(*ctx_entry), DRM_MEM_CTXLIST );
+       if ( !ctx_entry ) {
+               DRM_DEBUG("out of memory\n");
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD( &ctx_entry->head );
+       ctx_entry->handle = ctx.handle;
+       ctx_entry->tag = priv;
+
+       down( &dev->ctxlist_sem );
+       list_add( &ctx_entry->head, &dev->ctxlist->head );
+       ++dev->ctx_count;
+       up( &dev->ctxlist_sem );
 
        if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) )
                return -EFAULT;
@@ -544,6 +559,20 @@
                DRM(ctxbitmap_free)( dev, ctx.handle );
        }
 
+       down( &dev->ctxlist_sem );
+       if ( !list_empty( &dev->ctxlist->head ) ) {
+               drm_ctx_list_t *pos, *n;
+
+               list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) {
+                       if ( pos->handle == ctx.handle ) {
+                               list_del( &pos->head );
+                               DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );
+                               --dev->ctx_count;
+                       }
+               }
+       }
+       up( &dev->ctxlist_sem );
+
        return 0;
 }
 
diff -Nru drm-orig/drm_drv.h drm/drm_drv.h
--- drm-orig/drm_drv.h  2003-11-05 00:13:52.000000000 -0800
+++ drm/drm_drv.h       2004-02-19 23:09:53.809777600 -0800
@@ -329,6 +329,12 @@
        memset(dev->maplist, 0, sizeof(*dev->maplist));
        INIT_LIST_HEAD(&dev->maplist->head);
 
+       dev->ctxlist = DRM(alloc)(sizeof(*dev->ctxlist),
+                                 DRM_MEM_CTXLIST);
+       if(dev->ctxlist == NULL) return -ENOMEM;
+       memset(dev->ctxlist, 0, sizeof(*dev->ctxlist));
+       INIT_LIST_HEAD(&dev->ctxlist->head);
+
        dev->vmalist = NULL;
        dev->sigdata.lock = dev->lock.hw_lock = NULL;
        init_waitqueue_head( &dev->lock.lock_queue );
@@ -567,6 +573,7 @@
        dev->count_lock = SPIN_LOCK_UNLOCKED;
        init_timer( &dev->timer );
        sema_init( &dev->struct_sem, 1 );
+       sema_init( &dev->ctxlist_sem, 1 );
 
        if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
                return -EPERM;
@@ -896,6 +903,25 @@
 
        DRM(fasync)( -1, filp, 0 );
 
+       down( &dev->ctxlist_sem );
+       if ( !list_empty( &dev->ctxlist->head ) ) {
+               drm_ctx_list_t *pos, *n;
+
+               list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) {
+                       if ( pos->tag == priv &&
+                            pos->handle != DRM_KERNEL_CONTEXT ) {
+#ifdef DRIVER_CTX_DTOR
+                               DRIVER_CTX_DTOR(pos->handle);
+#endif
+                               DRM(ctxbitmap_free)( dev, pos->handle );
+
+                               list_del( &pos->head );
+                               DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );
+                       }
+               }
+       }
+       up( &dev->ctxlist_sem );
+
        down( &dev->struct_sem );
        if ( priv->remove_auth_on_close == 1 ) {
                drm_file_t *temp = dev->file_first;
diff -Nru drm-orig/drm_memory_debug.h drm/drm_memory_debug.h
--- drm-orig/drm_memory_debug.h 2003-08-29 12:16:13.000000000 -0700
+++ drm/drm_memory_debug.h      2004-02-19 22:53:49.789330984 -0800
@@ -68,6 +68,7 @@
        [DRM_MEM_TOTALAGP]  = { "totalagp" },
        [DRM_MEM_BOUNDAGP]  = { "boundagp" },
        [DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
+       [DRM_MEM_CTXLIST]   = { "ctxlist"  },
        [DRM_MEM_STUB]      = { "stub"     },
        { NULL, 0, }            /* Last entry must be null */
 };
diff -Nru drm-orig/drmP.h drm/drmP.h
--- drm-orig/drmP.h     2004-01-10 16:14:28.000000000 -0800
+++ drm/drmP.h  2004-02-19 23:04:29.641058736 -0800
@@ -158,6 +158,7 @@
 #define DRM_MEM_CTXBITMAP 18
 #define DRM_MEM_STUB      19
 #define DRM_MEM_SGLISTS   20
+#define DRM_MEM_CTXLIST  21
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
        
@@ -651,6 +652,15 @@
 
 typedef drm_map_t drm_local_map_t;
 
+/**
+ * Context handle list
+ */
+typedef struct drm_ctx_list {
+       struct list_head        head;   /**< list head */
+       drm_context_t           handle; /**< context handle */
+       drm_file_t              *tag;   /**< associated fd private data */
+} drm_ctx_list_t;
+
 #if __HAVE_VBL_IRQ
 
 typedef struct drm_vbl_sig {
@@ -711,6 +721,12 @@
        drm_map_list_t    *maplist;     /**< Linked list of regions */
        int               map_count;    /**< Number of mappable regions */
 
+       /** \name Context handle management */
+       /[EMAIL PROTECTED]/
+       drm_ctx_list_t    *ctxlist;     /**< Linked list of context handles */
+       int               ctx_count;    /**< Number of context handles */
+       struct semaphore  ctxlist_sem;  /**< For ctxlist */
+
        drm_map_t         **context_sareas; /**< per-context SAREA's */
        int               max_context;
 

Reply via email to