intel: Protect bufmgr objects with a pthread mutex.
authorEric Anholt <eric@anholt.net>
Fri, 13 Jun 2008 06:22:26 +0000 (23:22 -0700)
committerDave Airlie <airlied@linux.ie>
Thu, 16 Oct 2008 20:38:57 +0000 (06:38 +1000)
We want to be able to use the bufmgr from multiple threads for GL, and thus
we need to protect the internal structures.

The pthread-stubs package is used so that programs not linked against
pthreads get weak symbols to stubs and don't eat most of the cost.

configure.ac
libdrm/Makefile.am
libdrm/intel/Makefile.am
libdrm/intel/intel_bufmgr_fake.c
libdrm/intel/intel_bufmgr_gem.c

index 0cf0974..92507cb 100644 (file)
@@ -32,6 +32,10 @@ AC_PROG_CC
 AC_HEADER_STDC
 AC_SYS_LARGEFILE
 
+PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs)
+AC_SUBST(PTHREADSTUBS_CFLAGS)
+AC_SUBST(PTHREADSTUBS_LIBS)
+
 pkgconfigdir=${libdir}/pkgconfig
 AC_SUBST(pkgconfigdir)
 AC_ARG_ENABLE(udev,    AS_HELP_STRING([--enable-udev],
index 532ca13..8e1c0ee 100644 (file)
@@ -26,8 +26,8 @@ libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined
 
 AM_CFLAGS = -I$(top_srcdir)/shared-core
 libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \
-       xf86drmMode.c
-libdrm_la_LIBADD = intel/libdrm_intel.la
+       xf86drmMode.c libdrm_lists.h
+libdrm_la_LIBADD = intel/libdrm_intel.la @PTHREADSTUBS_LIBS@
 
 libdrmincludedir = ${includedir}
 libdrminclude_HEADERS = xf86drm.h xf86drmMode.h
index 607c476..92388c2 100644 (file)
@@ -26,6 +26,7 @@ AM_CFLAGS = \
        $(WARN_CFLAGS) \
        -I$(top_srcdir)/libdrm \
        -I$(top_srcdir)/libdrm/intel \
+       $(PTHREADSTUBS_CFLAGS) \
        -I$(top_srcdir)/shared-core
 
 libdrm_intel_la_LTLIBRARIES = libdrm_intel.la
index c88e1cb..4c28146 100644 (file)
@@ -43,6 +43,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <xf86drm.h>
+#include <pthread.h>
 #include "intel_bufmgr.h"
 #include "intel_bufmgr_priv.h"
 #include "drm.h"
@@ -112,6 +113,8 @@ struct block {
 typedef struct _bufmgr_fake {
    dri_bufmgr bufmgr;
 
+   pthread_mutex_t lock;
+
    unsigned long low_offset;
    unsigned long size;
    void *virtual;
@@ -716,10 +719,16 @@ dri_fake_bo_wait_rendering(dri_bo *bo)
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
 
-   if (bo_fake->block == NULL || !bo_fake->block->fenced)
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
+   if (bo_fake->block == NULL || !bo_fake->block->fenced) {
+      pthread_mutex_unlock(&bufmgr_fake->lock);
       return;
+   }
 
    _fence_wait_internal(bufmgr_fake, bo_fake->block->fence);
+
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
 /* Specifically ignore texture memory sharing.
@@ -732,6 +741,8 @@ intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr)
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
    struct block *block, *tmp;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    bufmgr_fake->need_fence = 1;
    bufmgr_fake->fail = 0;
 
@@ -751,6 +762,8 @@ intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr)
       assert(_fence_test(bufmgr_fake, block->fence));
       set_dirty(block->bo);
    }
+
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
 static dri_bo *
@@ -825,21 +838,29 @@ intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name,
 static void
 dri_fake_bo_reference(dri_bo *bo)
 {
+   dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
    bo_fake->refcount++;
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
 static void
-dri_fake_bo_unreference(dri_bo *bo)
+dri_fake_bo_reference_locked(dri_bo *bo)
+{
+   dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
+
+   bo_fake->refcount++;
+}
+
+static void
+dri_fake_bo_unreference_locked(dri_bo *bo)
 {
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
    int i;
 
-   if (!bo)
-      return;
-
    if (--bo_fake->refcount == 0) {
       assert(bo_fake->map_count == 0);
       /* No remaining references, so free it */
@@ -848,17 +869,25 @@ dri_fake_bo_unreference(dri_bo *bo)
       free_backing_store(bo);
 
       for (i = 0; i < bo_fake->nr_relocs; i++)
-        dri_bo_unreference(bo_fake->relocs[i].target_buf);
+        dri_fake_bo_unreference_locked(bo_fake->relocs[i].target_buf);
 
       DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, bo_fake->name);
 
       free(bo_fake->relocs);
       free(bo);
-
-      return;
    }
 }
 
+static void
+dri_fake_bo_unreference(dri_bo *bo)
+{
+   dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
+
+   pthread_mutex_lock(&bufmgr_fake->lock);
+   dri_fake_bo_unreference_locked(bo);
+   pthread_mutex_unlock(&bufmgr_fake->lock);
+}
+
 /**
  * Set the buffer as not requiring backing store, and instead get the callback
  * invoked whenever it would be set dirty.
@@ -871,6 +900,8 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo,
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    if (bo_fake->backing_store)
       free_backing_store(bo);
 
@@ -887,6 +918,8 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo,
     */
    if (invalidate_cb != NULL)
       invalidate_cb(bo, ptr);
+
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
 /**
@@ -894,7 +927,7 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo,
  * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary.
  */
 static int
-dri_fake_bo_map(dri_bo *bo, int write_enable)
+dri_fake_bo_map_locked(dri_bo *bo, int write_enable)
 {
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
@@ -952,7 +985,20 @@ dri_fake_bo_map(dri_bo *bo, int write_enable)
 }
 
 static int
-dri_fake_bo_unmap(dri_bo *bo)
+dri_fake_bo_map(dri_bo *bo, int write_enable)
+{
+   dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
+   int ret;
+
+   pthread_mutex_lock(&bufmgr_fake->lock);
+   ret = dri_fake_bo_map_locked(bo, write_enable);
+   pthread_mutex_unlock(&bufmgr_fake->lock);
+
+   return ret;
+}
+
+static int
+dri_fake_bo_unmap_locked(dri_bo *bo)
 {
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
@@ -973,11 +1019,26 @@ dri_fake_bo_unmap(dri_bo *bo)
    return 0;
 }
 
+static int
+dri_fake_bo_unmap(dri_bo *bo)
+{
+   dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
+   int ret;
+
+   pthread_mutex_lock(&bufmgr_fake->lock);
+   ret = dri_fake_bo_unmap_locked(bo);
+   pthread_mutex_unlock(&bufmgr_fake->lock);
+
+   return ret;
+}
+
 static void
 dri_fake_kick_all(dri_bufmgr_fake *bufmgr_fake)
 {
    struct block *block, *tmp;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    bufmgr_fake->performed_rendering = 0;
    /* okay for ever BO that is on the HW kick it off.
       seriously not afraid of the POLICE right now */
@@ -991,6 +1052,8 @@ dri_fake_kick_all(dri_bufmgr_fake *bufmgr_fake)
       if (!(bo_fake->flags & BM_NO_BACKING_STORE))
          bo_fake->dirty = 1;
    }
+
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 
 static int
@@ -999,9 +1062,6 @@ dri_fake_bo_validate(dri_bo *bo)
    dri_bufmgr_fake *bufmgr_fake;
    dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
 
-   /* XXX: Sanity-check whether we've already validated this one under
-    * different flags.  See drmAddValidateItem().
-    */
    bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
 
    DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
@@ -1084,6 +1144,7 @@ dri_fake_destroy(dri_bufmgr *bufmgr)
 {
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
 
+   pthread_mutex_destroy(&bufmgr_fake->lock);
    mmDestroy(bufmgr_fake->heap);
    free(bufmgr);
 }
@@ -1099,6 +1160,8 @@ dri_fake_emit_reloc(dri_bo *reloc_buf,
    dri_bo_fake *target_fake = (dri_bo_fake *)target_buf;
    int i;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    assert(reloc_buf);
    assert(target_buf);
 
@@ -1111,7 +1174,7 @@ dri_fake_emit_reloc(dri_bo *reloc_buf,
 
    assert(reloc_fake->nr_relocs <= MAX_RELOCS);
 
-   dri_bo_reference(target_buf);
+   dri_fake_bo_reference_locked(target_buf);
 
    if (!target_fake->is_static)
       reloc_fake->child_size += ALIGN(target_buf->size, target_fake->alignment);
@@ -1132,6 +1195,8 @@ dri_fake_emit_reloc(dri_bo *reloc_buf,
       }
    }
 
+   pthread_mutex_unlock(&bufmgr_fake->lock);
+
    return 0;
 }
 
@@ -1178,7 +1243,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo)
          ret = dri_fake_reloc_and_validate_buffer(r->target_buf);
          if (ret != 0) {
             if (bo->virtual != NULL)
-                dri_bo_unmap(bo);
+                dri_fake_bo_unmap_locked(bo);
             return ret;
          }
       }
@@ -1188,7 +1253,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo)
         reloc_data = r->target_buf->offset + r->delta;
 
         if (bo->virtual == NULL)
-           dri_bo_map(bo, 1);
+           dri_fake_bo_map_locked(bo, 1);
 
         *(uint32_t *)((uint8_t *)bo->virtual + r->offset) = reloc_data;
 
@@ -1197,7 +1262,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo)
    }
 
    if (bo->virtual != NULL)
-      dri_bo_unmap(bo);
+      dri_fake_bo_unmap_locked(bo);
 
    if (bo_fake->write_domain != 0) {
       if (!(bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED))) {
@@ -1261,6 +1326,8 @@ dri_fake_bo_exec(dri_bo *bo, int used,
    int ret;
    int retry_count = 0;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    bufmgr_fake->performed_rendering = 0;
 
    dri_fake_calculate_domains(bo);
@@ -1305,6 +1372,8 @@ dri_fake_bo_exec(dri_bo *bo, int used,
 
    dri_bo_fake_post_submit(bo);
 
+   pthread_mutex_unlock(&bufmgr_fake->lock);
+
    return 0;
 }
 
@@ -1357,6 +1426,8 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr)
    dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
    struct block *block, *tmp;
 
+   pthread_mutex_lock(&bufmgr_fake->lock);
+
    bufmgr_fake->need_fence = 1;
    bufmgr_fake->fail = 0;
 
@@ -1376,6 +1447,8 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr)
       /* Releases the memory, and memcpys dirty contents out if necessary. */
       free_block(bufmgr_fake, block);
    }
+
+   pthread_mutex_unlock(&bufmgr_fake->lock);
 }
 void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr,
                                         volatile unsigned int *last_dispatch)
@@ -1395,6 +1468,11 @@ intel_bufmgr_fake_init(int fd,
 
    bufmgr_fake = calloc(1, sizeof(*bufmgr_fake));
 
+   if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) {
+      free(bufmgr_fake);
+      return NULL;
+   }
+
    /* Initialize allocator */
    DRMINITLISTHEAD(&bufmgr_fake->fenced);
    DRMINITLISTHEAD(&bufmgr_fake->on_hardware);
index 70cdca7..af58ad8 100644 (file)
@@ -44,6 +44,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <assert.h>
+#include <pthread.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 
@@ -84,6 +85,8 @@ typedef struct _dri_bufmgr_gem {
 
     int max_relocs;
 
+    pthread_mutex_t lock;
+
     struct drm_i915_gem_exec_object *exec_objects;
     dri_bo **exec_bos;
     int exec_size;
@@ -133,6 +136,8 @@ struct _dri_bo_gem {
     dri_bo_gem *next;
 };
 
+static void dri_gem_bo_reference_locked(dri_bo *bo);
+
 static int
 logbase2(int n)
 {
@@ -237,7 +242,7 @@ intel_add_validate_buffer(dri_bo *bo)
     bufmgr_gem->exec_objects[index].alignment = 0;
     bufmgr_gem->exec_objects[index].offset = 0;
     bufmgr_gem->exec_bos[index] = bo;
-    dri_bo_reference(bo);
+    dri_gem_bo_reference_locked(bo);
     bufmgr_gem->exec_count++;
 }
 
@@ -285,6 +290,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name,
            bo_size = page_size;
     }
 
+    pthread_mutex_lock(&bufmgr_gem->lock);
     /* Get a buffer out of the cache if available */
     if (bucket != NULL && bucket->num_entries > 0) {
        struct drm_i915_gem_busy busy;
@@ -302,6 +308,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name,
            bucket->num_entries--;
        }
     }
+    pthread_mutex_unlock(&bufmgr_gem->lock);
 
     if (!alloc_from_cache) {
        struct drm_i915_gem_create create;
@@ -380,6 +387,17 @@ intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name,
 static void
 dri_gem_bo_reference(dri_bo *bo)
 {
+    dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
+    dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
+
+    pthread_mutex_lock(&bufmgr_gem->lock);
+    bo_gem->refcount++;
+    pthread_mutex_unlock(&bufmgr_gem->lock);
+}
+
+static void
+dri_gem_bo_reference_locked(dri_bo *bo)
+{
     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
 
     bo_gem->refcount++;
@@ -408,14 +426,11 @@ dri_gem_bo_free(dri_bo *bo)
 }
 
 static void
-dri_gem_bo_unreference(dri_bo *bo)
+dri_gem_bo_unreference_locked(dri_bo *bo)
 {
     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
 
-    if (!bo)
-       return;
-
     if (--bo_gem->refcount == 0) {
        struct dri_gem_bo_bucket *bucket;
 
@@ -424,7 +439,7 @@ dri_gem_bo_unreference(dri_bo *bo)
 
            /* Unreference all the target buffers */
            for (i = 0; i < bo_gem->reloc_count; i++)
-                dri_bo_unreference(bo_gem->reloc_target_bo[i]);
+                dri_gem_bo_unreference_locked(bo_gem->reloc_target_bo[i]);
            free(bo_gem->reloc_target_bo);
            free(bo_gem->relocs);
        }
@@ -452,20 +467,28 @@ dri_gem_bo_unreference(dri_bo *bo)
        } else {
            dri_gem_bo_free(bo);
        }
-
-       return;
     }
 }
 
+static void
+dri_gem_bo_unreference(dri_bo *bo)
+{
+    dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
+
+    pthread_mutex_lock(&bufmgr_gem->lock);
+    dri_gem_bo_unreference_locked(bo);
+    pthread_mutex_unlock(&bufmgr_gem->lock);
+}
+
 static int
 dri_gem_bo_map(dri_bo *bo, int write_enable)
 {
-    dri_bufmgr_gem *bufmgr_gem;
+    dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
     struct drm_i915_gem_set_domain set_domain;
     int ret;
 
-    bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
+    pthread_mutex_lock(&bufmgr_gem->lock);
 
     /* Allow recursive mapping. Mesa may recursively map buffers with
      * nested display loops.
@@ -515,6 +538,8 @@ dri_gem_bo_map(dri_bo *bo, int write_enable)
        bo_gem->swrast = 1;
     }
 
+    pthread_mutex_unlock(&bufmgr_gem->lock);
+
     return 0;
 }
 
@@ -531,6 +556,7 @@ dri_gem_bo_unmap(dri_bo *bo)
 
     assert(bo_gem->mapped);
 
+    pthread_mutex_lock(&bufmgr_gem->lock);
     if (bo_gem->swrast) {
        sw_finish.handle = bo_gem->gem_handle;
        do {
@@ -539,6 +565,7 @@ dri_gem_bo_unmap(dri_bo *bo)
        } while (ret == -1 && errno == EINTR);
        bo_gem->swrast = 0;
     }
+    pthread_mutex_unlock(&bufmgr_gem->lock);
     return 0;
 }
 
@@ -623,6 +650,8 @@ dri_bufmgr_gem_destroy(dri_bufmgr *bufmgr)
     free(bufmgr_gem->exec_objects);
     free(bufmgr_gem->exec_bos);
 
+    pthread_mutex_destroy(&bufmgr_gem->lock);
+
     /* Free any cached buffer objects we were going to reuse */
     for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) {
        struct dri_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i];
@@ -658,6 +687,8 @@ dri_gem_bo_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain,
     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
     dri_bo_gem *target_bo_gem = (dri_bo_gem *)target_bo;
 
+    pthread_mutex_lock(&bufmgr_gem->lock);
+
     /* Create a new relocation list if needed */
     if (bo_gem->relocs == NULL)
        intel_setup_reloc_list(bo);
@@ -678,9 +709,12 @@ dri_gem_bo_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain,
     bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset;
 
     bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo;
-    dri_bo_reference(target_bo);
+    dri_gem_bo_reference_locked(target_bo);
 
     bo_gem->reloc_count++;
+
+    pthread_mutex_unlock(&bufmgr_gem->lock);
+
     return 0;
 }
 
@@ -737,6 +771,7 @@ dri_gem_bo_exec(dri_bo *bo, int used,
     struct drm_i915_gem_execbuffer execbuf;
     int ret, i;
 
+    pthread_mutex_lock(&bufmgr_gem->lock);
     /* Update indices and set up the validate list. */
     dri_gem_bo_process_reloc(bo);
 
@@ -772,10 +807,11 @@ dri_gem_bo_exec(dri_bo *bo, int used,
 
        /* Disconnect the buffer from the validate list */
        bo_gem->validate_index = -1;
-       dri_bo_unreference(bo);
+       dri_gem_bo_unreference_locked(bo);
        bufmgr_gem->exec_bos[i] = NULL;
     }
     bufmgr_gem->exec_count = 0;
+    pthread_mutex_unlock(&bufmgr_gem->lock);
 
     return 0;
 }
@@ -900,6 +936,11 @@ intel_bufmgr_gem_init(int fd, int batch_size)
     bufmgr_gem = calloc(1, sizeof(*bufmgr_gem));
     bufmgr_gem->fd = fd;
 
+    if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) {
+      free(bufmgr_gem);
+      return NULL;
+   }
+
     /* Let's go with one relocation per every 2 dwords (but round down a bit
      * since a power of two will mean an extra page allocation for the reloc
      * buffer).