qom/object: update class cache atomically

The idiom CPU_GET_CLASS(cpu) is fairly extensively used in various
threads and trips of ThreadSanitizer due to the fact it updates
obj->class->object_cast_cache behind the scenes. As this is just a
fast-path cache there is no need to lock updates.

However to ensure defined C11 behaviour across threads we need to use
the plain atomic_read/set primitives and keep the sanitizer happy.

Backports commit b6b3ccfda015dcd5ab50f70c189ee5cc6c622e91 from qemu
This commit is contained in:
Alex Bennée 2018-02-26 05:06:37 -05:00 committed by Lioncash
parent bf72733576
commit 12d7e946a1
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -498,7 +498,7 @@ Object *object_dynamic_cast_assert(struct uc_struct *uc, Object *obj, const char
Object *inst; Object *inst;
for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
if (obj->class->object_cast_cache[i] == typename) { if (atomic_read(&obj->class->object_cast_cache[i]) == typename) {
goto out; goto out;
} }
} }
@ -515,10 +515,10 @@ Object *object_dynamic_cast_assert(struct uc_struct *uc, Object *obj, const char
if (obj && obj == inst) { if (obj && obj == inst) {
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
obj->class->object_cast_cache[i - 1] = atomic_set(&obj->class->object_cast_cache[i - 1],
obj->class->object_cast_cache[i]; atomic_read(&obj->class->object_cast_cache[i]));
} }
obj->class->object_cast_cache[i - 1] = typename; atomic_set(&obj->class->object_cast_cache[i - 1], typename);
} }
out: out:
@ -585,7 +585,7 @@ ObjectClass *object_class_dynamic_cast_assert(struct uc_struct *uc, ObjectClass
int i; int i;
for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) {
if (class->class_cast_cache[i] == typename) { if (atomic_read(&class->class_cast_cache[i]) == typename) {
ret = class; ret = class;
goto out; goto out;
} }
@ -606,9 +606,10 @@ ObjectClass *object_class_dynamic_cast_assert(struct uc_struct *uc, ObjectClass
#ifdef CONFIG_QOM_CAST_DEBUG #ifdef CONFIG_QOM_CAST_DEBUG
if (class && ret == class) { if (class && ret == class) {
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
class->class_cast_cache[i - 1] = class->class_cast_cache[i]; atomic_set(&class->class_cast_cache[i - 1],
atomic_read(&class->class_cast_cache[i]));
} }
class->class_cast_cache[i - 1] = typename; atomic_set(&class->class_cast_cache[i - 1], typename);
} }
out: out:
#endif #endif