r300g: make accessing map_list and buffer_handles thread-safe
authorMarek Olšák <maraeo@gmail.com>
Thu, 23 Sep 2010 12:24:52 +0000 (14:24 +0200)
committerMarek Olšák <maraeo@gmail.com>
Fri, 24 Sep 2010 00:29:05 +0000 (02:29 +0200)
NOTE: This is a candidate for the 7.9 branch.

src/gallium/winsys/radeon/drm/radeon_drm_buffer.c

index 075ab5cb324bf810e5dc62ce99d18fd33ef1bd42..78723948d41fbdd1509cee863112f1ebc00df17a 100644 (file)
 #include "util/u_simple_list.h"
 #include "pipebuffer/pb_buffer.h"
 #include "pipebuffer/pb_bufmgr.h"
+#include "os/os_thread.h"
 
 #include "radeon_winsys.h"
+
 struct radeon_drm_bufmgr;
 
 struct radeon_drm_buffer {
@@ -39,10 +41,19 @@ radeon_drm_buffer(struct pb_buffer *buf)
 }
 
 struct radeon_drm_bufmgr {
+    /* Base class. */
     struct pb_manager base;
+
+    /* Winsys. */
     struct radeon_libdrm_winsys *rws;
+
+    /* List of mapped buffers and its mutex. */
     struct radeon_drm_buffer buffer_map_list;
+    pipe_mutex buffer_map_list_mutex;
+
+    /* List of buffer handles and its mutex. */
     struct util_hash_table *buffer_handles;
+    pipe_mutex buffer_handles_mutex;
 };
 
 static INLINE struct radeon_drm_bufmgr *
@@ -59,14 +70,21 @@ radeon_drm_buffer_destroy(struct pb_buffer *_buf)
     int name;
 
     if (buf->bo->ptr != NULL) {
-       remove_from_list(buf);
-       radeon_bo_unmap(buf->bo);
-       buf->bo->ptr = NULL;
+        pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
+        /* Now test it again inside the mutex. */
+        if (buf->bo->ptr != NULL) {
+            remove_from_list(buf);
+            radeon_bo_unmap(buf->bo);
+            buf->bo->ptr = NULL;
+        }
+        pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
     }
     name = radeon_gem_name_bo(buf->bo);
     if (name) {
+        pipe_mutex_lock(buf->mgr->buffer_handles_mutex);
        util_hash_table_remove(buf->mgr->buffer_handles,
                               (void*)(uintptr_t)name);
+        pipe_mutex_unlock(buf->mgr->buffer_handles_mutex);
     }
     radeon_bo_unref(buf->bo);
 
@@ -119,7 +137,13 @@ radeon_drm_buffer_map_internal(struct pb_buffer *_buf,
     }
 
     if (buf->bo->ptr != NULL) {
-        remove_from_list(buf);
+        pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
+        /* Now test ptr again inside the mutex. We might have gotten a race
+         * during the first test. */
+        if (buf->bo->ptr != NULL) {
+            remove_from_list(buf);
+        }
+        pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
        return buf->bo->ptr;
     }
 
@@ -145,7 +169,9 @@ radeon_drm_buffer_map_internal(struct pb_buffer *_buf,
         return NULL;
     }
 
+    pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
     remove_from_list(buf);
+    pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
     return buf->bo->ptr;
 }
 
@@ -153,9 +179,11 @@ static void
 radeon_drm_buffer_unmap_internal(struct pb_buffer *_buf)
 {
     struct radeon_drm_buffer *buf = radeon_drm_buffer(_buf);
+    pipe_mutex_lock(buf->mgr->buffer_map_list_mutex);
     if (is_empty_list(buf)) { /* = is not inserted... */
         insert_at_tail(&buf->mgr->buffer_map_list, buf);
     }
+    pipe_mutex_unlock(buf->mgr->buffer_map_list_mutex);
 }
 
 static void
@@ -192,8 +220,9 @@ const struct pb_vtbl radeon_drm_buffer_vtbl = {
     radeon_drm_buffer_get_base_buffer,
 };
 
-struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr,
-                                                             uint32_t handle)
+static struct pb_buffer *
+radeon_drm_bufmgr_create_buffer_from_handle_unsafe(struct pb_manager *_mgr,
+                                                   uint32_t handle)
 {
     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
     struct radeon_libdrm_winsys *rws = mgr->rws;
@@ -201,6 +230,7 @@ struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager
     struct radeon_bo *bo;
 
     buf = util_hash_table_get(mgr->buffer_handles, (void*)(uintptr_t)handle);
+
     if (buf) {
         struct pb_buffer *b = NULL;
         pb_reference(&b, &buf->base);
@@ -234,6 +264,20 @@ struct pb_buffer *radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager
     return &buf->base;
 }
 
+struct pb_buffer *
+radeon_drm_bufmgr_create_buffer_from_handle(struct pb_manager *_mgr,
+                                            uint32_t handle)
+{
+    struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
+    struct pb_buffer *pb;
+
+    pipe_mutex_lock(mgr->buffer_handles_mutex);
+    pb = radeon_drm_bufmgr_create_buffer_from_handle_unsafe(_mgr, handle);
+    pipe_mutex_unlock(mgr->buffer_handles_mutex);
+
+    return pb;
+}
+
 static struct pb_buffer *
 radeon_drm_bufmgr_create_buffer(struct pb_manager *_mgr,
                                pb_size size,
@@ -285,6 +329,8 @@ radeon_drm_bufmgr_destroy(struct pb_manager *_mgr)
 {
     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
     util_hash_table_destroy(mgr->buffer_handles);
+    pipe_mutex_destroy(mgr->buffer_map_list_mutex);
+    pipe_mutex_destroy(mgr->buffer_handles_mutex);
     FREE(mgr);
 }
 
@@ -314,6 +360,8 @@ radeon_drm_bufmgr_create(struct radeon_libdrm_winsys *rws)
     mgr->rws = rws;
     make_empty_list(&mgr->buffer_map_list);
     mgr->buffer_handles = util_hash_table_create(handle_hash, handle_compare);
+    pipe_mutex_init(mgr->buffer_map_list_mutex);
+    pipe_mutex_init(mgr->buffer_handles_mutex);
     return &mgr->base;
 }
 
@@ -489,6 +537,8 @@ void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr)
     struct radeon_drm_bufmgr *mgr = radeon_drm_bufmgr(_mgr);
     struct radeon_drm_buffer *rpb, *t_rpb;
 
+    pipe_mutex_lock(mgr->buffer_map_list_mutex);
+
     foreach_s(rpb, t_rpb, &mgr->buffer_map_list) {
        radeon_bo_unmap(rpb->bo);
        rpb->bo->ptr = NULL;
@@ -496,6 +546,8 @@ void radeon_drm_bufmgr_flush_maps(struct pb_manager *_mgr)
     }
 
     make_empty_list(&mgr->buffer_map_list);
+
+    pipe_mutex_unlock(mgr->buffer_map_list_mutex);
 }
 
 void radeon_drm_bufmgr_wait(struct r300_winsys_screen *ws,