summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2011-02-15 02:34:05 +0100
committerMarek Olšák <[email protected]>2011-02-15 04:00:47 +0100
commit8decb0a96de0accfc8361890cbcf9db89f8fe8ba (patch)
treecd722e882196f558cfafe52563fcbe74428fa890 /src
parent18b4978ac8d2fb9b4f0830f33267e36ffc67b89c (diff)
r300g: fix a possible race condition when mapping a buffer
This is the last one I think.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_bo.c54
-rw-r--r--src/gallium/winsys/radeon/drm/radeon_drm_bo.h3
2 files changed, 34 insertions, 23 deletions
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c
index 027e9d3f47a..6de1ff7745d 100644
--- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c
@@ -107,6 +107,7 @@ void radeon_bo_unref(struct radeon_bo *bo)
/* Close object. */
args.handle = bo->handle;
drmIoctl(bo->rws->fd, DRM_IOCTL_GEM_CLOSE, &args);
+ pipe_mutex_destroy(bo->map_mutex);
FREE(bo);
}
@@ -156,6 +157,7 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
struct radeon_bo *bo = radeon_bo(_buf);
struct radeon_drm_cs *cs = flush_ctx;
struct drm_radeon_gem_mmap args = {};
+ void *ptr;
/* prevents a call to radeon_bo_wait if (usage & DONTBLOCK) and
* radeon_is_busy returns FALSE. */
boolean may_be_busy = TRUE;
@@ -182,30 +184,34 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
radeon_bo_wait((struct r300_winsys_bo*)bo);
}
- /* Map buffer if it's not already mapped. */
- /* XXX We may get a race in bo->ptr. */
- if (!bo->ptr) {
- void *ptr;
-
- args.handle = bo->handle;
- args.offset = 0;
- args.size = (uint64_t)bo->size;
- if (drmCommandWriteRead(bo->rws->fd,
- DRM_RADEON_GEM_MMAP,
- &args,
- sizeof(args))) {
- fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
- bo, bo->handle);
- return NULL;
- }
- ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
- bo->rws->fd, args.addr_ptr);
- if (ptr == MAP_FAILED) {
- fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
- return NULL;
- }
- bo->ptr = ptr;
+ /* Return the pointer if it's already mapped. */
+ if (bo->ptr)
+ return bo->ptr;
+
+ /* Map the buffer. */
+ pipe_mutex_lock(bo->map_mutex);
+ args.handle = bo->handle;
+ args.offset = 0;
+ args.size = (uint64_t)bo->size;
+ if (drmCommandWriteRead(bo->rws->fd,
+ DRM_RADEON_GEM_MMAP,
+ &args,
+ sizeof(args))) {
+ pipe_mutex_unlock(bo->map_mutex);
+ fprintf(stderr, "radeon: gem_mmap failed: %p 0x%08X\n",
+ bo, bo->handle);
+ return NULL;
+ }
+
+ ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ bo->rws->fd, args.addr_ptr);
+ if (ptr == MAP_FAILED) {
+ pipe_mutex_unlock(bo->map_mutex);
+ fprintf(stderr, "radeon: mmap failed, errno: %i\n", errno);
+ return NULL;
}
+ bo->ptr = ptr;
+ pipe_mutex_unlock(bo->map_mutex);
return bo->ptr;
}
@@ -284,6 +290,7 @@ static struct pb_buffer *radeon_bomgr_create_bo(struct pb_manager *_mgr,
bo->rws = mgr->rws;
bo->handle = args.handle;
bo->size = size;
+ pipe_mutex_init(bo->map_mutex);
radeon_bo_ref(bo);
return &bo->base;
@@ -514,6 +521,7 @@ static struct r300_winsys_bo *radeon_winsys_bo_from_handle(struct r300_winsys_sc
bo->base.vtbl = &radeon_bo_vtbl;
bo->mgr = mgr;
bo->rws = mgr->rws;
+ pipe_mutex_init(bo->map_mutex);
util_hash_table_set(mgr->bo_handles, (void*)(uintptr_t)whandle->handle, bo);
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h
index cb1afd62578..d877512be58 100644
--- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h
@@ -34,6 +34,7 @@
#include "radeon_winsys.h"
#include "pipebuffer/pb_bufmgr.h"
+#include "os/os_thread.h"
#define RADEON_PB_USAGE_CACHE (1 << 28)
#define RADEON_PB_USAGE_DOMAIN_GTT (1 << 29)
@@ -47,6 +48,8 @@ struct radeon_bo {
struct radeon_drm_winsys *rws;
void *ptr;
+ pipe_mutex map_mutex;
+
uint32_t size;
uint32_t handle;
uint32_t name;