summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/util
diff options
context:
space:
mode:
authorJosé Fonseca <jrfonseca@tungstengraphics.com>2008-11-11 23:27:27 +0900
committerJosé Fonseca <jrfonseca@tungstengraphics.com>2008-11-17 12:36:02 +0900
commitee172bf067d9a66faa9d57980970326b680df839 (patch)
tree2cbaa3adfc0216f09737bb5c73091a3becbe7a16 /src/gallium/auxiliary/util
parent40b3bb0407b6833a06e0a3a2e859cfac75b9100b (diff)
gallium: Make handle_table reentrant.
Ensure that the object has consistent state also when calling the destroy callback. Namely, ensure the object passed to the callback is removed from the table prior to calling the destroy callback to avoid a infinite loop or double free.
Diffstat (limited to 'src/gallium/auxiliary/util')
-rw-r--r--src/gallium/auxiliary/util/u_handle_table.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/src/gallium/auxiliary/util/u_handle_table.c b/src/gallium/auxiliary/util/u_handle_table.c
index 2c40011923..2d15932ce3 100644
--- a/src/gallium/auxiliary/util/u_handle_table.c
+++ b/src/gallium/auxiliary/util/u_handle_table.c
@@ -124,6 +124,28 @@ handle_table_resize(struct handle_table *ht,
}
+static INLINE void
+handle_table_clear(struct handle_table *ht,
+ unsigned index)
+{
+ void *object;
+
+ /* The order here is important so that the object being destroyed is not
+ * present in the table when seen by the destroy callback, because the
+ * destroy callback may directly or indirectly call the other functions in
+ * this module.
+ */
+
+ object = ht->objects[index];
+ if(object) {
+ ht->objects[index] = NULL;
+
+ if(ht->destroy)
+ ht->destroy(object);
+ }
+}
+
+
unsigned
handle_table_add(struct handle_table *ht,
void *object)
@@ -184,9 +206,8 @@ handle_table_set(struct handle_table *ht,
if(!handle_table_resize(ht, index))
return 0;
- if(ht->objects[index] && ht->destroy)
- ht->destroy(ht->objects[index]);
-
+ handle_table_clear(ht, index);
+
ht->objects[index] = object;
return handle;
@@ -227,10 +248,8 @@ handle_table_remove(struct handle_table *ht,
if(!object)
return;
- if(ht->destroy)
- ht->destroy(object);
+ handle_table_clear(ht, index);
- ht->objects[index] = NULL;
if(index < ht->filled)
ht->filled = index;
}
@@ -266,8 +285,7 @@ handle_table_destroy(struct handle_table *ht)
if(ht->destroy)
for(index = 0; index < ht->size; ++index)
- if(ht->objects[index])
- ht->destroy(ht->objects[index]);
+ handle_table_clear(ht, index);
FREE(ht->objects);
FREE(ht);