[API] Make set_user_data() functions take a replace parameter

We need this to set data on objects safely without worrying that some
other thread unsets it by setting it at the same time.
This commit is contained in:
Behdad Esfahbod 2011-08-09 00:43:24 +02:00
parent 944b2ba1ce
commit 33ccc77902
14 changed files with 89 additions and 54 deletions

View File

@ -165,9 +165,10 @@ hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (blob, key, data, destroy);
return hb_object_set_user_data (blob, key, data, destroy, replace);
}
void *

View File

@ -66,7 +66,8 @@ hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *

View File

@ -532,9 +532,10 @@ hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (buffer, key, data, destroy);
return hb_object_set_user_data (buffer, key, data, destroy, replace);
}
void *

View File

@ -75,7 +75,8 @@ hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *
hb_buffer_get_user_data (hb_buffer_t *buffer,

View File

@ -301,17 +301,20 @@ static hb_static_mutex_t user_data_lock;
bool
hb_user_data_array_t::set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
if (!key)
return false;
if (!data && !destroy) {
items.remove (key, user_data_lock);
return true;
if (replace) {
if (!data && !destroy) {
items.remove (key, user_data_lock);
return true;
}
}
hb_user_data_item_t item = {key, data, destroy};
bool ret = !!items.replace_or_insert (item, user_data_lock);
bool ret = !!items.replace_or_insert (item, user_data_lock, replace);
return ret;
}

View File

@ -248,9 +248,10 @@ hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (ffuncs, key, data, destroy);
return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
}
void *
@ -667,9 +668,10 @@ hb_bool_t
hb_face_set_user_data (hb_face_t *face,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (face, key, data, destroy);
return hb_object_set_user_data (face, key, data, destroy, replace);
}
void *
@ -852,9 +854,10 @@ hb_bool_t
hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (font, key, data, destroy);
return hb_object_set_user_data (font, key, data, destroy, replace);
}
void *

View File

@ -65,7 +65,8 @@ hb_bool_t
hb_face_set_user_data (hb_face_t *face,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *
@ -123,7 +124,8 @@ hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *
@ -338,7 +340,8 @@ hb_bool_t
hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *

View File

@ -122,7 +122,8 @@ struct hb_user_data_array_t {
HB_INTERNAL bool set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_INTERNAL void *get (hb_user_data_key_t *key);
@ -178,11 +179,12 @@ struct _hb_object_header_t {
inline bool set_user_data (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy_func) {
hb_destroy_func_t destroy_func,
hb_bool_t replace) {
if (unlikely (!this || this->is_inert ()))
return false;
return user_data.set (key, data, destroy_func);
return user_data.set (key, data, destroy_func, replace);
}
inline void *get_user_data (hb_user_data_key_t *key) {
@ -237,9 +239,10 @@ template <typename Type>
static inline bool hb_object_set_user_data (Type *obj,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return obj->header.set_user_data (key, data, destroy);
return obj->header.set_user_data (key, data, destroy, replace);
}
template <typename Type>

View File

@ -343,15 +343,21 @@ struct hb_lockable_set_t
hb_array_t <item_t> items;
template <typename T>
inline item_t *replace_or_insert (T v, lock_t &l)
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
{
l.lock ();
item_t *item = items.find (v);
if (item) {
item_t old = *item;
*item = v;
l.unlock ();
old.finish ();
if (replace) {
item_t old = *item;
*item = v;
l.unlock ();
old.finish ();
}
else {
item = NULL;
l.unlock ();
}
} else {
item = items.push ();
if (likely (item))

View File

@ -76,7 +76,7 @@ static struct static_shaper_list_t
end = p + strlen (p);
for (unsigned int j = i; j < ARRAY_LENGTH (shapers); j++)
if (end - p == strlen (shapers[j].name) &&
if (end - p == (int) strlen (shapers[j].name) &&
0 == strncmp (shapers[j].name, p, end - p))
{
/* Reorder this shaper to position i */

View File

@ -175,9 +175,10 @@ hb_bool_t
hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy)
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (ufuncs, key, data, destroy);
return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
}
void *

View File

@ -66,7 +66,8 @@ hb_bool_t
hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy);
hb_destroy_func_t destroy,
hb_bool_t replace);
void *

View File

@ -129,10 +129,15 @@ _hb_uniscribe_face_get_data (hb_face_t *face)
DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
if (unlikely (!hb_face_set_user_data (face, &uniscribe_face_data_key, data,
(hb_destroy_func_t) _hb_uniscribe_face_data_destroy)))
(hb_destroy_func_t) _hb_uniscribe_face_data_destroy,
FALSE)))
{
_hb_uniscribe_face_data_destroy (data);
return &_hb_uniscribe_face_data_nil;
data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &uniscribe_face_data_key);
if (data)
return data;
else
return &_hb_uniscribe_face_data_nil;
}
return data;
@ -183,10 +188,15 @@ _hb_uniscribe_font_get_data (hb_font_t *font)
}
if (unlikely (!hb_font_set_user_data (font, &uniscribe_font_data_key, data,
(hb_destroy_func_t) _hb_uniscribe_font_data_destroy)))
(hb_destroy_func_t) _hb_uniscribe_font_data_destroy,
FALSE)))
{
_hb_uniscribe_font_data_destroy (data);
return &_hb_uniscribe_font_data_nil;
data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &uniscribe_font_data_key);
if (data)
return data;
else
return &_hb_uniscribe_font_data_nil;
}
return data;

View File

@ -116,7 +116,7 @@ create_unicode_funcs_inert (void)
typedef void *(*create_func_t) (void);
typedef void *(*reference_func_t) (void *obj);
typedef void (*destroy_func_t) (void *obj);
typedef hb_bool_t (*set_user_data_func_t) (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy);
typedef hb_bool_t (*set_user_data_func_t) (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
typedef void * (*get_user_data_func_t) (void *obj, hb_user_data_key_t *key);
typedef void (*make_immutable_func_t) (void *obj);
typedef hb_bool_t (*is_immutable_func_t) (void *obj);
@ -247,7 +247,7 @@ test_object (void)
if (o->is_immutable)
g_assert (!o->is_immutable (obj));
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
if (o->is_immutable) {
@ -256,38 +256,39 @@ test_object (void)
}
/* Should still work even if object is made immutable */
g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1));
g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1, TRUE));
g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0));
g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0, TRUE));
g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
g_assert (o->set_user_data (obj, &key[0], &data[1], NULL));
g_assert (o->set_user_data (obj, &key[0], &data[1], NULL, TRUE));
g_assert (data[0].freed);
g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
g_assert (!data[1].freed);
data[0].freed = FALSE;
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
g_assert (!data[0].freed);
g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
g_assert (data[0].freed);
data[0].freed = FALSE;
global_data = 0;
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0));
g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, FALSE));
g_assert_cmpuint (global_data, ==, 0);
g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up));
g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up, TRUE));
g_assert_cmpuint (global_data, ==, 0);
g_assert (o->set_user_data (obj, &key[0], NULL, NULL));
g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
g_assert_cmpuint (global_data, ==, 1);
global_data = 0;
for (j = 2; j < 1000; j++)
g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up));
g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up, TRUE));
for (j = 2; j < 1000; j++)
g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
for (j = 100; j < 1000; j++)
g_assert (o->set_user_data (obj, &key[j], NULL, NULL));
g_assert (o->set_user_data (obj, &key[j], NULL, NULL, TRUE));
for (j = 2; j < 100; j++)
g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
for (j = 100; j < 1000; j++)
@ -298,8 +299,8 @@ test_object (void)
* Make sure it doesn't deadlock or corrupt memory. */
deadlock_test.klass = o;
deadlock_test.object = obj;
g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test));
g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL));
g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test, TRUE));
g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL, TRUE));
g_assert (!data[1].freed);
o->destroy (obj);
@ -321,7 +322,7 @@ test_object (void)
if (o->is_immutable)
g_assert (o->is_immutable (obj));
g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0));
g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
g_assert (!o->get_user_data (obj, &key[0]));
o->destroy (obj);
@ -349,7 +350,7 @@ test_object (void)
if (o->is_immutable)
g_assert (o->is_immutable (obj));
g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0));
g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
g_assert (!o->get_user_data (obj, &key[0]));
o->destroy (obj);