File: | qom/object.c |
Location: | line 1187, column 5 |
Description: | Access to field 'tqh_first' results in a dereference of a null pointer |
1 | /* | |||||
2 | * QEMU Object Model | |||||
3 | * | |||||
4 | * Copyright IBM, Corp. 2011 | |||||
5 | * | |||||
6 | * Authors: | |||||
7 | * Anthony Liguori <aliguori@us.ibm.com> | |||||
8 | * | |||||
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |||||
10 | * See the COPYING file in the top-level directory. | |||||
11 | */ | |||||
12 | ||||||
13 | #include "qom/object.h" | |||||
14 | #include "qemu-common.h" | |||||
15 | #include "qapi/visitor.h" | |||||
16 | #include "qapi/string-input-visitor.h" | |||||
17 | #include "qapi/string-output-visitor.h" | |||||
18 | #include "qapi/qmp/qerror.h" | |||||
19 | #include "trace.h" | |||||
20 | ||||||
21 | /* TODO: replace QObject with a simpler visitor to avoid a dependency | |||||
22 | * of the QOM core on QObject? */ | |||||
23 | #include "qom/qom-qobject.h" | |||||
24 | #include "qapi/qmp/qobject.h" | |||||
25 | #include "qapi/qmp/qbool.h" | |||||
26 | #include "qapi/qmp/qint.h" | |||||
27 | #include "qapi/qmp/qstring.h" | |||||
28 | ||||||
29 | #define MAX_INTERFACES32 32 | |||||
30 | ||||||
31 | typedef struct InterfaceImpl InterfaceImpl; | |||||
32 | typedef struct TypeImpl TypeImpl; | |||||
33 | ||||||
34 | struct InterfaceImpl | |||||
35 | { | |||||
36 | const char *typename; | |||||
37 | }; | |||||
38 | ||||||
39 | struct TypeImpl | |||||
40 | { | |||||
41 | const char *name; | |||||
42 | ||||||
43 | size_t class_size; | |||||
44 | ||||||
45 | size_t instance_size; | |||||
46 | ||||||
47 | void (*class_init)(ObjectClass *klass, void *data); | |||||
48 | void (*class_base_init)(ObjectClass *klass, void *data); | |||||
49 | void (*class_finalize)(ObjectClass *klass, void *data); | |||||
50 | ||||||
51 | void *class_data; | |||||
52 | ||||||
53 | void (*instance_init)(Object *obj); | |||||
54 | void (*instance_post_init)(Object *obj); | |||||
55 | void (*instance_finalize)(Object *obj); | |||||
56 | ||||||
57 | bool_Bool abstract; | |||||
58 | ||||||
59 | const char *parent; | |||||
60 | TypeImpl *parent_type; | |||||
61 | ||||||
62 | ObjectClass *class; | |||||
63 | ||||||
64 | int num_interfaces; | |||||
65 | InterfaceImpl interfaces[MAX_INTERFACES32]; | |||||
66 | }; | |||||
67 | ||||||
68 | static Type type_interface; | |||||
69 | ||||||
70 | static GHashTable *type_table_get(void) | |||||
71 | { | |||||
72 | static GHashTable *type_table; | |||||
73 | ||||||
74 | if (type_table == NULL((void*)0)) { | |||||
75 | type_table = g_hash_table_new(g_str_hash, g_str_equal); | |||||
76 | } | |||||
77 | ||||||
78 | return type_table; | |||||
79 | } | |||||
80 | ||||||
81 | static bool_Bool enumerating_types; | |||||
82 | ||||||
83 | static void type_table_add(TypeImpl *ti) | |||||
84 | { | |||||
85 | assert(!enumerating_types)((!enumerating_types) ? (void) (0) : __assert_fail ("!enumerating_types" , "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c", 85, __PRETTY_FUNCTION__ )); | |||||
86 | g_hash_table_insert(type_table_get(), (void *)ti->name, ti); | |||||
87 | } | |||||
88 | ||||||
89 | static TypeImpl *type_table_lookup(const char *name) | |||||
90 | { | |||||
91 | return g_hash_table_lookup(type_table_get(), name); | |||||
92 | } | |||||
93 | ||||||
94 | static TypeImpl *type_new(const TypeInfo *info) | |||||
95 | { | |||||
96 | TypeImpl *ti = g_malloc0(sizeof(*ti)); | |||||
97 | int i; | |||||
98 | ||||||
99 | g_assert(info->name != NULL)do { if (info->name != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 99, ((const char*) (__PRETTY_FUNCTION__)), "info->name != NULL" ); } while (0); | |||||
100 | ||||||
101 | if (type_table_lookup(info->name) != NULL((void*)0)) { | |||||
102 | fprintf(stderrstderr, "Registering `%s' which already exists\n", info->name); | |||||
103 | abort(); | |||||
104 | } | |||||
105 | ||||||
106 | ti->name = g_strdup(info->name); | |||||
107 | ti->parent = g_strdup(info->parent); | |||||
108 | ||||||
109 | ti->class_size = info->class_size; | |||||
110 | ti->instance_size = info->instance_size; | |||||
111 | ||||||
112 | ti->class_init = info->class_init; | |||||
113 | ti->class_base_init = info->class_base_init; | |||||
114 | ti->class_finalize = info->class_finalize; | |||||
115 | ti->class_data = info->class_data; | |||||
116 | ||||||
117 | ti->instance_init = info->instance_init; | |||||
118 | ti->instance_post_init = info->instance_post_init; | |||||
119 | ti->instance_finalize = info->instance_finalize; | |||||
120 | ||||||
121 | ti->abstract = info->abstract; | |||||
122 | ||||||
123 | for (i = 0; info->interfaces && info->interfaces[i].type; i++) { | |||||
124 | ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); | |||||
125 | } | |||||
126 | ti->num_interfaces = i; | |||||
127 | ||||||
128 | return ti; | |||||
129 | } | |||||
130 | ||||||
131 | static TypeImpl *type_register_internal(const TypeInfo *info) | |||||
132 | { | |||||
133 | TypeImpl *ti; | |||||
134 | ti = type_new(info); | |||||
135 | ||||||
136 | type_table_add(ti); | |||||
137 | return ti; | |||||
138 | } | |||||
139 | ||||||
140 | TypeImpl *type_register(const TypeInfo *info) | |||||
141 | { | |||||
142 | assert(info->parent)((info->parent) ? (void) (0) : __assert_fail ("info->parent" , "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c", 142, __PRETTY_FUNCTION__ )); | |||||
143 | return type_register_internal(info); | |||||
144 | } | |||||
145 | ||||||
146 | TypeImpl *type_register_static(const TypeInfo *info) | |||||
147 | { | |||||
148 | return type_register(info); | |||||
149 | } | |||||
150 | ||||||
151 | static TypeImpl *type_get_by_name(const char *name) | |||||
152 | { | |||||
153 | if (name == NULL((void*)0)) { | |||||
154 | return NULL((void*)0); | |||||
155 | } | |||||
156 | ||||||
157 | return type_table_lookup(name); | |||||
158 | } | |||||
159 | ||||||
160 | static TypeImpl *type_get_parent(TypeImpl *type) | |||||
161 | { | |||||
162 | if (!type->parent_type && type->parent) { | |||||
163 | type->parent_type = type_get_by_name(type->parent); | |||||
164 | g_assert(type->parent_type != NULL)do { if (type->parent_type != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 164, ((const char*) (__PRETTY_FUNCTION__)), "type->parent_type != NULL" ); } while (0); | |||||
165 | } | |||||
166 | ||||||
167 | return type->parent_type; | |||||
168 | } | |||||
169 | ||||||
170 | static bool_Bool type_has_parent(TypeImpl *type) | |||||
171 | { | |||||
172 | return (type->parent != NULL((void*)0)); | |||||
173 | } | |||||
174 | ||||||
175 | static size_t type_class_get_size(TypeImpl *ti) | |||||
176 | { | |||||
177 | if (ti->class_size) { | |||||
178 | return ti->class_size; | |||||
179 | } | |||||
180 | ||||||
181 | if (type_has_parent(ti)) { | |||||
182 | return type_class_get_size(type_get_parent(ti)); | |||||
183 | } | |||||
184 | ||||||
185 | return sizeof(ObjectClass); | |||||
186 | } | |||||
187 | ||||||
188 | static size_t type_object_get_size(TypeImpl *ti) | |||||
189 | { | |||||
190 | if (ti->instance_size) { | |||||
191 | return ti->instance_size; | |||||
192 | } | |||||
193 | ||||||
194 | if (type_has_parent(ti)) { | |||||
195 | return type_object_get_size(type_get_parent(ti)); | |||||
196 | } | |||||
197 | ||||||
198 | return 0; | |||||
199 | } | |||||
200 | ||||||
201 | static bool_Bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) | |||||
202 | { | |||||
203 | assert(target_type)((target_type) ? (void) (0) : __assert_fail ("target_type", "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 203, __PRETTY_FUNCTION__)); | |||||
204 | ||||||
205 | /* Check if typename is a direct ancestor of type */ | |||||
206 | while (type) { | |||||
207 | if (type == target_type) { | |||||
208 | return true1; | |||||
209 | } | |||||
210 | ||||||
211 | type = type_get_parent(type); | |||||
212 | } | |||||
213 | ||||||
214 | return false0; | |||||
215 | } | |||||
216 | ||||||
217 | static void type_initialize(TypeImpl *ti); | |||||
218 | ||||||
219 | static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, | |||||
220 | TypeImpl *parent_type) | |||||
221 | { | |||||
222 | InterfaceClass *new_iface; | |||||
223 | TypeInfo info = { }; | |||||
224 | TypeImpl *iface_impl; | |||||
225 | ||||||
226 | info.parent = parent_type->name; | |||||
227 | info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); | |||||
228 | info.abstract = true1; | |||||
229 | ||||||
230 | iface_impl = type_new(&info); | |||||
231 | iface_impl->parent_type = parent_type; | |||||
232 | type_initialize(iface_impl); | |||||
233 | g_free((char *)info.name); | |||||
234 | ||||||
235 | new_iface = (InterfaceClass *)iface_impl->class; | |||||
236 | new_iface->concrete_class = ti->class; | |||||
237 | new_iface->interface_type = interface_type; | |||||
238 | ||||||
239 | ti->class->interfaces = g_slist_append(ti->class->interfaces, | |||||
240 | iface_impl->class); | |||||
241 | } | |||||
242 | ||||||
243 | static void type_initialize(TypeImpl *ti) | |||||
244 | { | |||||
245 | TypeImpl *parent; | |||||
246 | ||||||
247 | if (ti->class) { | |||||
248 | return; | |||||
249 | } | |||||
250 | ||||||
251 | ti->class_size = type_class_get_size(ti); | |||||
252 | ti->instance_size = type_object_get_size(ti); | |||||
253 | ||||||
254 | ti->class = g_malloc0(ti->class_size); | |||||
255 | ||||||
256 | parent = type_get_parent(ti); | |||||
257 | if (parent) { | |||||
258 | type_initialize(parent); | |||||
259 | GSList *e; | |||||
260 | int i; | |||||
261 | ||||||
262 | g_assert(parent->class_size <= ti->class_size)do { if (parent->class_size <= ti->class_size) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 262, ((const char*) (__PRETTY_FUNCTION__)), "parent->class_size <= ti->class_size" ); } while (0); | |||||
263 | memcpy(ti->class, parent->class, parent->class_size); | |||||
264 | ti->class->interfaces = NULL((void*)0); | |||||
265 | ||||||
266 | for (e = parent->class->interfaces; e; e = e->next) { | |||||
267 | InterfaceClass *iface = e->data; | |||||
268 | ObjectClass *klass = OBJECT_CLASS(iface)((ObjectClass *)(iface)); | |||||
269 | ||||||
270 | type_initialize_interface(ti, iface->interface_type, klass->type); | |||||
271 | } | |||||
272 | ||||||
273 | for (i = 0; i < ti->num_interfaces; i++) { | |||||
274 | TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); | |||||
275 | for (e = ti->class->interfaces; e; e = e->next) { | |||||
276 | TypeImpl *target_type = OBJECT_CLASS(e->data)((ObjectClass *)(e->data))->type; | |||||
277 | ||||||
278 | if (type_is_ancestor(target_type, t)) { | |||||
279 | break; | |||||
280 | } | |||||
281 | } | |||||
282 | ||||||
283 | if (e) { | |||||
284 | continue; | |||||
285 | } | |||||
286 | ||||||
287 | type_initialize_interface(ti, t, t); | |||||
288 | } | |||||
289 | } | |||||
290 | ||||||
291 | ti->class->type = ti; | |||||
292 | ||||||
293 | while (parent) { | |||||
294 | if (parent->class_base_init) { | |||||
295 | parent->class_base_init(ti->class, ti->class_data); | |||||
296 | } | |||||
297 | parent = type_get_parent(parent); | |||||
298 | } | |||||
299 | ||||||
300 | if (ti->class_init) { | |||||
301 | ti->class_init(ti->class, ti->class_data); | |||||
302 | } | |||||
303 | } | |||||
304 | ||||||
305 | static void object_init_with_type(Object *obj, TypeImpl *ti) | |||||
306 | { | |||||
307 | if (type_has_parent(ti)) { | |||||
308 | object_init_with_type(obj, type_get_parent(ti)); | |||||
309 | } | |||||
310 | ||||||
311 | if (ti->instance_init) { | |||||
312 | ti->instance_init(obj); | |||||
313 | } | |||||
314 | } | |||||
315 | ||||||
316 | static void object_post_init_with_type(Object *obj, TypeImpl *ti) | |||||
317 | { | |||||
318 | if (ti->instance_post_init) { | |||||
319 | ti->instance_post_init(obj); | |||||
320 | } | |||||
321 | ||||||
322 | if (type_has_parent(ti)) { | |||||
323 | object_post_init_with_type(obj, type_get_parent(ti)); | |||||
324 | } | |||||
325 | } | |||||
326 | ||||||
327 | void object_initialize_with_type(void *data, size_t size, TypeImpl *type) | |||||
328 | { | |||||
329 | Object *obj = data; | |||||
330 | ||||||
331 | g_assert(type != NULL)do { if (type != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 331, ((const char*) (__PRETTY_FUNCTION__)), "type != NULL") ; } while (0); | |||||
332 | type_initialize(type); | |||||
333 | ||||||
334 | g_assert(type->instance_size >= sizeof(Object))do { if (type->instance_size >= sizeof(Object)) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 334, ((const char*) (__PRETTY_FUNCTION__)), "type->instance_size >= sizeof(Object)" ); } while (0); | |||||
335 | g_assert(type->abstract == false)do { if (type->abstract == 0) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 335, ((const char*) (__PRETTY_FUNCTION__)), "type->abstract == false" ); } while (0); | |||||
336 | g_assert(size >= type->instance_size)do { if (size >= type->instance_size) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 336, ((const char*) (__PRETTY_FUNCTION__)), "size >= type->instance_size" ); } while (0); | |||||
337 | ||||||
338 | memset(obj, 0, type->instance_size); | |||||
339 | obj->class = type->class; | |||||
340 | object_ref(obj); | |||||
341 | QTAILQ_INIT(&obj->properties)do { (&obj->properties)->tqh_first = ((void*)0); (& obj->properties)->tqh_last = &(&obj->properties )->tqh_first; } while ( 0); | |||||
342 | object_init_with_type(obj, type); | |||||
343 | object_post_init_with_type(obj, type); | |||||
344 | } | |||||
345 | ||||||
346 | void object_initialize(void *data, size_t size, const char *typename) | |||||
347 | { | |||||
348 | TypeImpl *type = type_get_by_name(typename); | |||||
349 | ||||||
350 | object_initialize_with_type(data, size, type); | |||||
351 | } | |||||
352 | ||||||
353 | static inline bool_Bool object_property_is_child(ObjectProperty *prop) | |||||
354 | { | |||||
355 | return strstart(prop->type, "child<", NULL((void*)0)); | |||||
356 | } | |||||
357 | ||||||
358 | static inline bool_Bool object_property_is_link(ObjectProperty *prop) | |||||
359 | { | |||||
360 | return strstart(prop->type, "link<", NULL((void*)0)); | |||||
361 | } | |||||
362 | ||||||
363 | static void object_property_del_all(Object *obj) | |||||
364 | { | |||||
365 | while (!QTAILQ_EMPTY(&obj->properties)((&obj->properties)->tqh_first == ((void*)0))) { | |||||
366 | ObjectProperty *prop = QTAILQ_FIRST(&obj->properties)((&obj->properties)->tqh_first); | |||||
367 | ||||||
368 | QTAILQ_REMOVE(&obj->properties, prop, node)do { if (((prop)->node.tqe_next) != ((void*)0)) (prop)-> node.tqe_next->node.tqe_prev = (prop)->node.tqe_prev; else (&obj->properties)->tqh_last = (prop)->node.tqe_prev ; *(prop)->node.tqe_prev = (prop)->node.tqe_next; } while ( 0); | |||||
369 | ||||||
370 | if (prop->release) { | |||||
371 | prop->release(obj, prop->name, prop->opaque); | |||||
372 | } | |||||
373 | ||||||
374 | g_free(prop->name); | |||||
375 | g_free(prop->type); | |||||
376 | g_free(prop); | |||||
377 | } | |||||
378 | } | |||||
379 | ||||||
380 | static void object_property_del_child(Object *obj, Object *child, Error **errp) | |||||
381 | { | |||||
382 | ObjectProperty *prop; | |||||
383 | ||||||
384 | QTAILQ_FOREACH(prop, &obj->properties, node)for ((prop) = ((&obj->properties)->tqh_first); (prop ); (prop) = ((prop)->node.tqe_next)) { | |||||
385 | if (object_property_is_child(prop) && prop->opaque == child) { | |||||
386 | object_property_del(obj, prop->name, errp); | |||||
387 | break; | |||||
388 | } | |||||
389 | } | |||||
390 | } | |||||
391 | ||||||
392 | void object_unparent(Object *obj) | |||||
393 | { | |||||
394 | if (!obj->parent) { | |||||
395 | return; | |||||
396 | } | |||||
397 | ||||||
398 | object_ref(obj); | |||||
399 | if (obj->class->unparent) { | |||||
400 | (obj->class->unparent)(obj); | |||||
401 | } | |||||
402 | if (obj->parent) { | |||||
403 | object_property_del_child(obj->parent, obj, NULL((void*)0)); | |||||
404 | } | |||||
405 | object_unref(obj); | |||||
406 | } | |||||
407 | ||||||
408 | static void object_deinit(Object *obj, TypeImpl *type) | |||||
409 | { | |||||
410 | if (type->instance_finalize) { | |||||
411 | type->instance_finalize(obj); | |||||
412 | } | |||||
413 | ||||||
414 | if (type_has_parent(type)) { | |||||
415 | object_deinit(obj, type_get_parent(type)); | |||||
416 | } | |||||
417 | } | |||||
418 | ||||||
419 | static void object_finalize(void *data) | |||||
420 | { | |||||
421 | Object *obj = data; | |||||
422 | TypeImpl *ti = obj->class->type; | |||||
423 | ||||||
424 | object_deinit(obj, ti); | |||||
425 | object_property_del_all(obj); | |||||
426 | ||||||
427 | g_assert(obj->ref == 0)do { if (obj->ref == 0) ; else g_assertion_message_expr (( (gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 427, ((const char*) (__PRETTY_FUNCTION__)), "obj->ref == 0" ); } while (0); | |||||
428 | if (obj->free) { | |||||
429 | obj->free(obj); | |||||
430 | } | |||||
431 | } | |||||
432 | ||||||
433 | Object *object_new_with_type(Type type) | |||||
434 | { | |||||
435 | Object *obj; | |||||
436 | ||||||
437 | g_assert(type != NULL)do { if (type != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 437, ((const char*) (__PRETTY_FUNCTION__)), "type != NULL") ; } while (0); | |||||
438 | type_initialize(type); | |||||
439 | ||||||
440 | obj = g_malloc(type->instance_size); | |||||
441 | object_initialize_with_type(obj, type->instance_size, type); | |||||
442 | obj->free = g_free; | |||||
443 | ||||||
444 | return obj; | |||||
445 | } | |||||
446 | ||||||
447 | Object *object_new(const char *typename) | |||||
448 | { | |||||
449 | TypeImpl *ti = type_get_by_name(typename); | |||||
450 | ||||||
451 | return object_new_with_type(ti); | |||||
452 | } | |||||
453 | ||||||
454 | Object *object_dynamic_cast(Object *obj, const char *typename) | |||||
455 | { | |||||
456 | if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { | |||||
457 | return obj; | |||||
458 | } | |||||
459 | ||||||
460 | return NULL((void*)0); | |||||
461 | } | |||||
462 | ||||||
463 | Object *object_dynamic_cast_assert(Object *obj, const char *typename, | |||||
464 | const char *file, int line, const char *func) | |||||
465 | { | |||||
466 | trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", | |||||
467 | typename, file, line, func); | |||||
468 | ||||||
469 | #ifdef CONFIG_QOM_CAST_DEBUG1 | |||||
470 | int i; | |||||
471 | Object *inst; | |||||
472 | ||||||
473 | for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE4; i++) { | |||||
474 | if (obj->class->object_cast_cache[i] == typename) { | |||||
475 | goto out; | |||||
476 | } | |||||
477 | } | |||||
478 | ||||||
479 | inst = object_dynamic_cast(obj, typename); | |||||
480 | ||||||
481 | if (!inst && obj) { | |||||
482 | fprintf(stderrstderr, "%s:%d:%s: Object %p is not an instance of type %s\n", | |||||
483 | file, line, func, obj, typename); | |||||
484 | abort(); | |||||
485 | } | |||||
486 | ||||||
487 | assert(obj == inst)((obj == inst) ? (void) (0) : __assert_fail ("obj == inst", "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 487, __PRETTY_FUNCTION__)); | |||||
488 | ||||||
489 | if (obj && obj == inst) { | |||||
490 | for (i = 1; i < OBJECT_CLASS_CAST_CACHE4; i++) { | |||||
491 | obj->class->object_cast_cache[i - 1] = | |||||
492 | obj->class->object_cast_cache[i]; | |||||
493 | } | |||||
494 | obj->class->object_cast_cache[i - 1] = typename; | |||||
495 | } | |||||
496 | ||||||
497 | out: | |||||
498 | #endif | |||||
499 | return obj; | |||||
500 | } | |||||
501 | ||||||
502 | ObjectClass *object_class_dynamic_cast(ObjectClass *class, | |||||
503 | const char *typename) | |||||
504 | { | |||||
505 | ObjectClass *ret = NULL((void*)0); | |||||
506 | TypeImpl *target_type; | |||||
507 | TypeImpl *type; | |||||
508 | ||||||
509 | if (!class) { | |||||
510 | return NULL((void*)0); | |||||
511 | } | |||||
512 | ||||||
513 | /* A simple fast path that can trigger a lot for leaf classes. */ | |||||
514 | type = class->type; | |||||
515 | if (type->name == typename) { | |||||
516 | return class; | |||||
517 | } | |||||
518 | ||||||
519 | target_type = type_get_by_name(typename); | |||||
520 | if (!target_type) { | |||||
521 | /* target class type unknown, so fail the cast */ | |||||
522 | return NULL((void*)0); | |||||
523 | } | |||||
524 | ||||||
525 | if (type->class->interfaces && | |||||
526 | type_is_ancestor(target_type, type_interface)) { | |||||
527 | int found = 0; | |||||
528 | GSList *i; | |||||
529 | ||||||
530 | for (i = class->interfaces; i; i = i->next) { | |||||
531 | ObjectClass *target_class = i->data; | |||||
532 | ||||||
533 | if (type_is_ancestor(target_class->type, target_type)) { | |||||
534 | ret = target_class; | |||||
535 | found++; | |||||
536 | } | |||||
537 | } | |||||
538 | ||||||
539 | /* The match was ambiguous, don't allow a cast */ | |||||
540 | if (found > 1) { | |||||
541 | ret = NULL((void*)0); | |||||
542 | } | |||||
543 | } else if (type_is_ancestor(type, target_type)) { | |||||
544 | ret = class; | |||||
545 | } | |||||
546 | ||||||
547 | return ret; | |||||
548 | } | |||||
549 | ||||||
550 | ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, | |||||
551 | const char *typename, | |||||
552 | const char *file, int line, | |||||
553 | const char *func) | |||||
554 | { | |||||
555 | ObjectClass *ret; | |||||
556 | ||||||
557 | trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", | |||||
558 | typename, file, line, func); | |||||
559 | ||||||
560 | #ifdef CONFIG_QOM_CAST_DEBUG1 | |||||
561 | int i; | |||||
562 | ||||||
563 | for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE4; i++) { | |||||
564 | if (class->class_cast_cache[i] == typename) { | |||||
565 | ret = class; | |||||
566 | goto out; | |||||
567 | } | |||||
568 | } | |||||
569 | #else | |||||
570 | if (!class || !class->interfaces) { | |||||
571 | return class; | |||||
572 | } | |||||
573 | #endif | |||||
574 | ||||||
575 | ret = object_class_dynamic_cast(class, typename); | |||||
576 | if (!ret && class) { | |||||
577 | fprintf(stderrstderr, "%s:%d:%s: Object %p is not an instance of type %s\n", | |||||
578 | file, line, func, class, typename); | |||||
579 | abort(); | |||||
580 | } | |||||
581 | ||||||
582 | #ifdef CONFIG_QOM_CAST_DEBUG1 | |||||
583 | if (class && ret == class) { | |||||
584 | for (i = 1; i < OBJECT_CLASS_CAST_CACHE4; i++) { | |||||
585 | class->class_cast_cache[i - 1] = class->class_cast_cache[i]; | |||||
586 | } | |||||
587 | class->class_cast_cache[i - 1] = typename; | |||||
588 | } | |||||
589 | out: | |||||
590 | #endif | |||||
591 | return ret; | |||||
592 | } | |||||
593 | ||||||
594 | const char *object_get_typename(Object *obj) | |||||
595 | { | |||||
596 | return obj->class->type->name; | |||||
597 | } | |||||
598 | ||||||
599 | ObjectClass *object_get_class(Object *obj) | |||||
600 | { | |||||
601 | return obj->class; | |||||
602 | } | |||||
603 | ||||||
604 | bool_Bool object_class_is_abstract(ObjectClass *klass) | |||||
605 | { | |||||
606 | return klass->type->abstract; | |||||
607 | } | |||||
608 | ||||||
609 | const char *object_class_get_name(ObjectClass *klass) | |||||
610 | { | |||||
611 | return klass->type->name; | |||||
612 | } | |||||
613 | ||||||
614 | ObjectClass *object_class_by_name(const char *typename) | |||||
615 | { | |||||
616 | TypeImpl *type = type_get_by_name(typename); | |||||
617 | ||||||
618 | if (!type) { | |||||
619 | return NULL((void*)0); | |||||
620 | } | |||||
621 | ||||||
622 | type_initialize(type); | |||||
623 | ||||||
624 | return type->class; | |||||
625 | } | |||||
626 | ||||||
627 | ObjectClass *object_class_get_parent(ObjectClass *class) | |||||
628 | { | |||||
629 | TypeImpl *type = type_get_parent(class->type); | |||||
630 | ||||||
631 | if (!type) { | |||||
632 | return NULL((void*)0); | |||||
633 | } | |||||
634 | ||||||
635 | type_initialize(type); | |||||
636 | ||||||
637 | return type->class; | |||||
638 | } | |||||
639 | ||||||
640 | typedef struct OCFData | |||||
641 | { | |||||
642 | void (*fn)(ObjectClass *klass, void *opaque); | |||||
643 | const char *implements_type; | |||||
644 | bool_Bool include_abstract; | |||||
645 | void *opaque; | |||||
646 | } OCFData; | |||||
647 | ||||||
648 | static void object_class_foreach_tramp(gpointer key, gpointer value, | |||||
649 | gpointer opaque) | |||||
650 | { | |||||
651 | OCFData *data = opaque; | |||||
652 | TypeImpl *type = value; | |||||
653 | ObjectClass *k; | |||||
654 | ||||||
655 | type_initialize(type); | |||||
656 | k = type->class; | |||||
657 | ||||||
658 | if (!data->include_abstract && type->abstract) { | |||||
659 | return; | |||||
660 | } | |||||
661 | ||||||
662 | if (data->implements_type && | |||||
663 | !object_class_dynamic_cast(k, data->implements_type)) { | |||||
664 | return; | |||||
665 | } | |||||
666 | ||||||
667 | data->fn(k, data->opaque); | |||||
668 | } | |||||
669 | ||||||
670 | void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), | |||||
671 | const char *implements_type, bool_Bool include_abstract, | |||||
672 | void *opaque) | |||||
673 | { | |||||
674 | OCFData data = { fn, implements_type, include_abstract, opaque }; | |||||
675 | ||||||
676 | enumerating_types = true1; | |||||
677 | g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); | |||||
678 | enumerating_types = false0; | |||||
679 | } | |||||
680 | ||||||
681 | int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), | |||||
682 | void *opaque) | |||||
683 | { | |||||
684 | ObjectProperty *prop; | |||||
685 | int ret = 0; | |||||
686 | ||||||
687 | QTAILQ_FOREACH(prop, &obj->properties, node)for ((prop) = ((&obj->properties)->tqh_first); (prop ); (prop) = ((prop)->node.tqe_next)) { | |||||
688 | if (object_property_is_child(prop)) { | |||||
689 | ret = fn(prop->opaque, opaque); | |||||
690 | if (ret != 0) { | |||||
691 | break; | |||||
692 | } | |||||
693 | } | |||||
694 | } | |||||
695 | return ret; | |||||
696 | } | |||||
697 | ||||||
698 | static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) | |||||
699 | { | |||||
700 | GSList **list = opaque; | |||||
701 | ||||||
702 | *list = g_slist_prepend(*list, klass); | |||||
703 | } | |||||
704 | ||||||
705 | GSList *object_class_get_list(const char *implements_type, | |||||
706 | bool_Bool include_abstract) | |||||
707 | { | |||||
708 | GSList *list = NULL((void*)0); | |||||
709 | ||||||
710 | object_class_foreach(object_class_get_list_tramp, | |||||
711 | implements_type, include_abstract, &list); | |||||
712 | return list; | |||||
713 | } | |||||
714 | ||||||
715 | void object_ref(Object *obj) | |||||
716 | { | |||||
717 | atomic_inc(&obj->ref)((void) __sync_fetch_and_add(&obj->ref, 1)); | |||||
718 | } | |||||
719 | ||||||
720 | void object_unref(Object *obj) | |||||
721 | { | |||||
722 | g_assert(obj->ref > 0)do { if (obj->ref > 0) ; else g_assertion_message_expr ( ((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 722, ((const char*) (__PRETTY_FUNCTION__)), "obj->ref > 0" ); } while (0); | |||||
723 | ||||||
724 | /* parent always holds a reference to its children */ | |||||
725 | if (atomic_fetch_dec(&obj->ref)__sync_fetch_and_add(&obj->ref, -1) == 1) { | |||||
726 | object_finalize(obj); | |||||
727 | } | |||||
728 | } | |||||
729 | ||||||
730 | void object_property_add(Object *obj, const char *name, const char *type, | |||||
731 | ObjectPropertyAccessor *get, | |||||
732 | ObjectPropertyAccessor *set, | |||||
733 | ObjectPropertyRelease *release, | |||||
734 | void *opaque, Error **errp) | |||||
735 | { | |||||
736 | ObjectProperty *prop; | |||||
737 | ||||||
738 | QTAILQ_FOREACH(prop, &obj->properties, node)for ((prop) = ((&obj->properties)->tqh_first); (prop ); (prop) = ((prop)->node.tqe_next)) { | |||||
739 | if (strcmp(prop->name, name) == 0) { | |||||
740 | error_setg(errp, "attempt to add duplicate property '%s'"error_set(errp, ERROR_CLASS_GENERIC_ERROR, "attempt to add duplicate property '%s'" " to object (type '%s')", name, object_get_typename(obj)) | |||||
741 | " to object (type '%s')", name,error_set(errp, ERROR_CLASS_GENERIC_ERROR, "attempt to add duplicate property '%s'" " to object (type '%s')", name, object_get_typename(obj)) | |||||
742 | object_get_typename(obj))error_set(errp, ERROR_CLASS_GENERIC_ERROR, "attempt to add duplicate property '%s'" " to object (type '%s')", name, object_get_typename(obj)); | |||||
743 | return; | |||||
744 | } | |||||
745 | } | |||||
746 | ||||||
747 | prop = g_malloc0(sizeof(*prop)); | |||||
748 | ||||||
749 | prop->name = g_strdup(name); | |||||
750 | prop->type = g_strdup(type); | |||||
751 | ||||||
752 | prop->get = get; | |||||
753 | prop->set = set; | |||||
754 | prop->release = release; | |||||
755 | prop->opaque = opaque; | |||||
756 | ||||||
757 | QTAILQ_INSERT_TAIL(&obj->properties, prop, node)do { (prop)->node.tqe_next = ((void*)0); (prop)->node.tqe_prev = (&obj->properties)->tqh_last; *(&obj->properties )->tqh_last = (prop); (&obj->properties)->tqh_last = &(prop)->node.tqe_next; } while ( 0); | |||||
758 | } | |||||
759 | ||||||
760 | ObjectProperty *object_property_find(Object *obj, const char *name, | |||||
761 | Error **errp) | |||||
762 | { | |||||
763 | ObjectProperty *prop; | |||||
764 | ||||||
765 | QTAILQ_FOREACH(prop, &obj->properties, node)for ((prop) = ((&obj->properties)->tqh_first); (prop ); (prop) = ((prop)->node.tqe_next)) { | |||||
766 | if (strcmp(prop->name, name) == 0) { | |||||
767 | return prop; | |||||
768 | } | |||||
769 | } | |||||
770 | ||||||
771 | error_set(errp, QERR_PROPERTY_NOT_FOUNDERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' not found", "", name); | |||||
772 | return NULL((void*)0); | |||||
773 | } | |||||
774 | ||||||
775 | void object_property_del(Object *obj, const char *name, Error **errp) | |||||
776 | { | |||||
777 | ObjectProperty *prop = object_property_find(obj, name, errp); | |||||
778 | if (prop == NULL((void*)0)) { | |||||
779 | return; | |||||
780 | } | |||||
781 | ||||||
782 | if (prop->release) { | |||||
783 | prop->release(obj, name, prop->opaque); | |||||
784 | } | |||||
785 | ||||||
786 | QTAILQ_REMOVE(&obj->properties, prop, node)do { if (((prop)->node.tqe_next) != ((void*)0)) (prop)-> node.tqe_next->node.tqe_prev = (prop)->node.tqe_prev; else (&obj->properties)->tqh_last = (prop)->node.tqe_prev ; *(prop)->node.tqe_prev = (prop)->node.tqe_next; } while ( 0); | |||||
787 | ||||||
788 | g_free(prop->name); | |||||
789 | g_free(prop->type); | |||||
790 | g_free(prop); | |||||
791 | } | |||||
792 | ||||||
793 | void object_property_get(Object *obj, Visitor *v, const char *name, | |||||
794 | Error **errp) | |||||
795 | { | |||||
796 | ObjectProperty *prop = object_property_find(obj, name, errp); | |||||
797 | if (prop == NULL((void*)0)) { | |||||
798 | return; | |||||
799 | } | |||||
800 | ||||||
801 | if (!prop->get) { | |||||
802 | error_set(errp, QERR_PERMISSION_DENIEDERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation"); | |||||
803 | } else { | |||||
804 | prop->get(obj, v, prop->opaque, name, errp); | |||||
805 | } | |||||
806 | } | |||||
807 | ||||||
808 | void object_property_set(Object *obj, Visitor *v, const char *name, | |||||
809 | Error **errp) | |||||
810 | { | |||||
811 | ObjectProperty *prop = object_property_find(obj, name, errp); | |||||
812 | if (prop == NULL((void*)0)) { | |||||
813 | return; | |||||
814 | } | |||||
815 | ||||||
816 | if (!prop->set) { | |||||
817 | error_set(errp, QERR_PERMISSION_DENIEDERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation"); | |||||
818 | } else { | |||||
819 | prop->set(obj, v, prop->opaque, name, errp); | |||||
820 | } | |||||
821 | } | |||||
822 | ||||||
823 | void object_property_set_str(Object *obj, const char *value, | |||||
824 | const char *name, Error **errp) | |||||
825 | { | |||||
826 | QString *qstr = qstring_from_str(value); | |||||
827 | object_property_set_qobject(obj, QOBJECT(qstr)(&(qstr)->base), name, errp); | |||||
828 | ||||||
829 | QDECREF(qstr)qobject_decref(qstr ? (&(qstr)->base) : ((void*)0)); | |||||
830 | } | |||||
831 | ||||||
832 | char *object_property_get_str(Object *obj, const char *name, | |||||
833 | Error **errp) | |||||
834 | { | |||||
835 | QObject *ret = object_property_get_qobject(obj, name, errp); | |||||
836 | QString *qstring; | |||||
837 | char *retval; | |||||
838 | ||||||
839 | if (!ret) { | |||||
840 | return NULL((void*)0); | |||||
841 | } | |||||
842 | qstring = qobject_to_qstring(ret); | |||||
843 | if (!qstring) { | |||||
844 | error_set(errp, QERR_INVALID_PARAMETER_TYPEERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s", name, "string"); | |||||
845 | retval = NULL((void*)0); | |||||
846 | } else { | |||||
847 | retval = g_strdup(qstring_get_str(qstring)); | |||||
848 | } | |||||
849 | ||||||
850 | QDECREF(qstring)qobject_decref(qstring ? (&(qstring)->base) : ((void*) 0)); | |||||
851 | return retval; | |||||
852 | } | |||||
853 | ||||||
854 | void object_property_set_link(Object *obj, Object *value, | |||||
855 | const char *name, Error **errp) | |||||
856 | { | |||||
857 | gchar *path = object_get_canonical_path(value); | |||||
858 | object_property_set_str(obj, path, name, errp); | |||||
859 | g_free(path); | |||||
860 | } | |||||
861 | ||||||
862 | Object *object_property_get_link(Object *obj, const char *name, | |||||
863 | Error **errp) | |||||
864 | { | |||||
865 | char *str = object_property_get_str(obj, name, errp); | |||||
866 | Object *target = NULL((void*)0); | |||||
867 | ||||||
868 | if (str && *str) { | |||||
869 | target = object_resolve_path(str, NULL((void*)0)); | |||||
870 | if (!target) { | |||||
871 | error_set(errp, QERR_DEVICE_NOT_FOUNDERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", str); | |||||
872 | } | |||||
873 | } | |||||
874 | ||||||
875 | g_free(str); | |||||
876 | return target; | |||||
877 | } | |||||
878 | ||||||
879 | void object_property_set_bool(Object *obj, bool_Bool value, | |||||
880 | const char *name, Error **errp) | |||||
881 | { | |||||
882 | QBool *qbool = qbool_from_int(value); | |||||
883 | object_property_set_qobject(obj, QOBJECT(qbool)(&(qbool)->base), name, errp); | |||||
884 | ||||||
885 | QDECREF(qbool)qobject_decref(qbool ? (&(qbool)->base) : ((void*)0)); | |||||
886 | } | |||||
887 | ||||||
888 | bool_Bool object_property_get_bool(Object *obj, const char *name, | |||||
889 | Error **errp) | |||||
890 | { | |||||
891 | QObject *ret = object_property_get_qobject(obj, name, errp); | |||||
892 | QBool *qbool; | |||||
893 | bool_Bool retval; | |||||
894 | ||||||
895 | if (!ret) { | |||||
896 | return false0; | |||||
897 | } | |||||
898 | qbool = qobject_to_qbool(ret); | |||||
899 | if (!qbool) { | |||||
900 | error_set(errp, QERR_INVALID_PARAMETER_TYPEERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s", name, "boolean"); | |||||
901 | retval = false0; | |||||
902 | } else { | |||||
903 | retval = qbool_get_int(qbool); | |||||
904 | } | |||||
905 | ||||||
906 | QDECREF(qbool)qobject_decref(qbool ? (&(qbool)->base) : ((void*)0)); | |||||
907 | return retval; | |||||
908 | } | |||||
909 | ||||||
910 | void object_property_set_int(Object *obj, int64_t value, | |||||
911 | const char *name, Error **errp) | |||||
912 | { | |||||
913 | QInt *qint = qint_from_int(value); | |||||
914 | object_property_set_qobject(obj, QOBJECT(qint)(&(qint)->base), name, errp); | |||||
915 | ||||||
916 | QDECREF(qint)qobject_decref(qint ? (&(qint)->base) : ((void*)0)); | |||||
917 | } | |||||
918 | ||||||
919 | int64_t object_property_get_int(Object *obj, const char *name, | |||||
920 | Error **errp) | |||||
921 | { | |||||
922 | QObject *ret = object_property_get_qobject(obj, name, errp); | |||||
923 | QInt *qint; | |||||
924 | int64_t retval; | |||||
925 | ||||||
926 | if (!ret) { | |||||
927 | return -1; | |||||
928 | } | |||||
929 | qint = qobject_to_qint(ret); | |||||
930 | if (!qint) { | |||||
931 | error_set(errp, QERR_INVALID_PARAMETER_TYPEERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s", name, "int"); | |||||
932 | retval = -1; | |||||
933 | } else { | |||||
934 | retval = qint_get_int(qint); | |||||
935 | } | |||||
936 | ||||||
937 | QDECREF(qint)qobject_decref(qint ? (&(qint)->base) : ((void*)0)); | |||||
938 | return retval; | |||||
939 | } | |||||
940 | ||||||
941 | void object_property_parse(Object *obj, const char *string, | |||||
942 | const char *name, Error **errp) | |||||
943 | { | |||||
944 | StringInputVisitor *mi; | |||||
945 | mi = string_input_visitor_new(string); | |||||
946 | object_property_set(obj, string_input_get_visitor(mi), name, errp); | |||||
947 | ||||||
948 | string_input_visitor_cleanup(mi); | |||||
949 | } | |||||
950 | ||||||
951 | char *object_property_print(Object *obj, const char *name, | |||||
952 | Error **errp) | |||||
953 | { | |||||
954 | StringOutputVisitor *mo; | |||||
955 | char *string; | |||||
956 | ||||||
957 | mo = string_output_visitor_new(); | |||||
958 | object_property_get(obj, string_output_get_visitor(mo), name, errp); | |||||
959 | string = string_output_get_string(mo); | |||||
960 | string_output_visitor_cleanup(mo); | |||||
961 | return string; | |||||
962 | } | |||||
963 | ||||||
964 | const char *object_property_get_type(Object *obj, const char *name, Error **errp) | |||||
965 | { | |||||
966 | ObjectProperty *prop = object_property_find(obj, name, errp); | |||||
967 | if (prop == NULL((void*)0)) { | |||||
968 | return NULL((void*)0); | |||||
969 | } | |||||
970 | ||||||
971 | return prop->type; | |||||
972 | } | |||||
973 | ||||||
974 | Object *object_get_root(void) | |||||
975 | { | |||||
976 | static Object *root; | |||||
977 | ||||||
978 | if (!root) { | |||||
979 | root = object_new("container"); | |||||
980 | } | |||||
981 | ||||||
982 | return root; | |||||
983 | } | |||||
984 | ||||||
985 | static void object_get_child_property(Object *obj, Visitor *v, void *opaque, | |||||
986 | const char *name, Error **errp) | |||||
987 | { | |||||
988 | Object *child = opaque; | |||||
989 | gchar *path; | |||||
990 | ||||||
991 | path = object_get_canonical_path(child); | |||||
992 | visit_type_str(v, &path, name, errp); | |||||
993 | g_free(path); | |||||
994 | } | |||||
995 | ||||||
996 | static void object_finalize_child_property(Object *obj, const char *name, | |||||
997 | void *opaque) | |||||
998 | { | |||||
999 | Object *child = opaque; | |||||
1000 | ||||||
1001 | object_unref(child); | |||||
1002 | } | |||||
1003 | ||||||
1004 | void object_property_add_child(Object *obj, const char *name, | |||||
1005 | Object *child, Error **errp) | |||||
1006 | { | |||||
1007 | gchar *type; | |||||
1008 | ||||||
1009 | type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)((Object *)(child)))); | |||||
1010 | ||||||
1011 | object_property_add(obj, name, type, object_get_child_property, | |||||
1012 | NULL((void*)0), object_finalize_child_property, child, errp); | |||||
1013 | ||||||
1014 | object_ref(child); | |||||
1015 | g_assert(child->parent == NULL)do { if (child->parent == ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 1015, ((const char*) (__PRETTY_FUNCTION__)), "child->parent == NULL" ); } while (0); | |||||
1016 | child->parent = obj; | |||||
1017 | ||||||
1018 | g_free(type); | |||||
1019 | } | |||||
1020 | ||||||
1021 | static void object_get_link_property(Object *obj, Visitor *v, void *opaque, | |||||
1022 | const char *name, Error **errp) | |||||
1023 | { | |||||
1024 | Object **child = opaque; | |||||
1025 | gchar *path; | |||||
1026 | ||||||
1027 | if (*child) { | |||||
1028 | path = object_get_canonical_path(*child); | |||||
1029 | visit_type_str(v, &path, name, errp); | |||||
1030 | g_free(path); | |||||
1031 | } else { | |||||
1032 | path = (gchar *)""; | |||||
1033 | visit_type_str(v, &path, name, errp); | |||||
1034 | } | |||||
1035 | } | |||||
1036 | ||||||
1037 | static void object_set_link_property(Object *obj, Visitor *v, void *opaque, | |||||
1038 | const char *name, Error **errp) | |||||
1039 | { | |||||
1040 | Object **child = opaque; | |||||
1041 | Object *old_target; | |||||
1042 | bool_Bool ambiguous = false0; | |||||
1043 | const char *type; | |||||
1044 | char *path; | |||||
1045 | gchar *target_type; | |||||
1046 | ||||||
1047 | type = object_property_get_type(obj, name, NULL((void*)0)); | |||||
1048 | ||||||
1049 | visit_type_str(v, &path, name, errp); | |||||
1050 | ||||||
1051 | old_target = *child; | |||||
1052 | *child = NULL((void*)0); | |||||
1053 | ||||||
1054 | if (strcmp(path, "") != 0) { | |||||
1055 | Object *target; | |||||
1056 | ||||||
1057 | /* Go from link<FOO> to FOO. */ | |||||
1058 | target_type = g_strndup(&type[5], strlen(type) - 6); | |||||
1059 | target = object_resolve_path_type(path, target_type, &ambiguous); | |||||
1060 | ||||||
1061 | if (ambiguous) { | |||||
1062 | error_set(errp, QERR_AMBIGUOUS_PATHERROR_CLASS_GENERIC_ERROR, "Path '%s' does not uniquely identify an object", path); | |||||
1063 | } else if (target) { | |||||
1064 | object_ref(target); | |||||
1065 | *child = target; | |||||
1066 | } else { | |||||
1067 | target = object_resolve_path(path, &ambiguous); | |||||
1068 | if (target || ambiguous) { | |||||
1069 | error_set(errp, QERR_INVALID_PARAMETER_TYPEERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s", name, target_type); | |||||
1070 | } else { | |||||
1071 | error_set(errp, QERR_DEVICE_NOT_FOUNDERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", path); | |||||
1072 | } | |||||
1073 | } | |||||
1074 | g_free(target_type); | |||||
1075 | } | |||||
1076 | ||||||
1077 | g_free(path); | |||||
1078 | ||||||
1079 | if (old_target != NULL((void*)0)) { | |||||
1080 | object_unref(old_target); | |||||
1081 | } | |||||
1082 | } | |||||
1083 | ||||||
1084 | void object_property_add_link(Object *obj, const char *name, | |||||
1085 | const char *type, Object **child, | |||||
1086 | Error **errp) | |||||
1087 | { | |||||
1088 | gchar *full_type; | |||||
1089 | ||||||
1090 | full_type = g_strdup_printf("link<%s>", type); | |||||
1091 | ||||||
1092 | object_property_add(obj, name, full_type, | |||||
1093 | object_get_link_property, | |||||
1094 | object_set_link_property, | |||||
1095 | NULL((void*)0), child, errp); | |||||
1096 | ||||||
1097 | g_free(full_type); | |||||
1098 | } | |||||
1099 | ||||||
1100 | gchar *object_get_canonical_path(Object *obj) | |||||
1101 | { | |||||
1102 | Object *root = object_get_root(); | |||||
1103 | char *newpath = NULL((void*)0), *path = NULL((void*)0); | |||||
1104 | ||||||
1105 | while (obj != root) { | |||||
1106 | ObjectProperty *prop = NULL((void*)0); | |||||
1107 | ||||||
1108 | g_assert(obj->parent != NULL)do { if (obj->parent != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 1108, ((const char*) (__PRETTY_FUNCTION__)), "obj->parent != NULL" ); } while (0); | |||||
1109 | ||||||
1110 | QTAILQ_FOREACH(prop, &obj->parent->properties, node)for ((prop) = ((&obj->parent->properties)->tqh_first ); (prop); (prop) = ((prop)->node.tqe_next)) { | |||||
1111 | if (!object_property_is_child(prop)) { | |||||
1112 | continue; | |||||
1113 | } | |||||
1114 | ||||||
1115 | if (prop->opaque == obj) { | |||||
1116 | if (path) { | |||||
1117 | newpath = g_strdup_printf("%s/%s", prop->name, path); | |||||
1118 | g_free(path); | |||||
1119 | path = newpath; | |||||
1120 | } else { | |||||
1121 | path = g_strdup(prop->name); | |||||
1122 | } | |||||
1123 | break; | |||||
1124 | } | |||||
1125 | } | |||||
1126 | ||||||
1127 | g_assert(prop != NULL)do { if (prop != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 1127, ((const char*) (__PRETTY_FUNCTION__)), "prop != NULL" ); } while (0); | |||||
1128 | ||||||
1129 | obj = obj->parent; | |||||
1130 | } | |||||
1131 | ||||||
1132 | newpath = g_strdup_printf("/%s", path); | |||||
1133 | g_free(path); | |||||
1134 | ||||||
1135 | return newpath; | |||||
1136 | } | |||||
1137 | ||||||
1138 | Object *object_resolve_path_component(Object *parent, const gchar *part) | |||||
1139 | { | |||||
1140 | ObjectProperty *prop = object_property_find(parent, part, NULL((void*)0)); | |||||
1141 | if (prop == NULL((void*)0)) { | |||||
1142 | return NULL((void*)0); | |||||
1143 | } | |||||
1144 | ||||||
1145 | if (object_property_is_link(prop)) { | |||||
1146 | return *(Object **)prop->opaque; | |||||
1147 | } else if (object_property_is_child(prop)) { | |||||
1148 | return prop->opaque; | |||||
1149 | } else { | |||||
1150 | return NULL((void*)0); | |||||
1151 | } | |||||
1152 | } | |||||
1153 | ||||||
1154 | static Object *object_resolve_abs_path(Object *parent, | |||||
1155 | gchar **parts, | |||||
1156 | const char *typename, | |||||
1157 | int index) | |||||
1158 | { | |||||
1159 | Object *child; | |||||
1160 | ||||||
1161 | if (parts[index] == NULL((void*)0)) { | |||||
1162 | return object_dynamic_cast(parent, typename); | |||||
1163 | } | |||||
1164 | ||||||
1165 | if (strcmp(parts[index], "") == 0) { | |||||
1166 | return object_resolve_abs_path(parent, parts, typename, index + 1); | |||||
1167 | } | |||||
1168 | ||||||
1169 | child = object_resolve_path_component(parent, parts[index]); | |||||
1170 | if (!child) { | |||||
1171 | return NULL((void*)0); | |||||
1172 | } | |||||
1173 | ||||||
1174 | return object_resolve_abs_path(child, parts, typename, index + 1); | |||||
1175 | } | |||||
1176 | ||||||
1177 | static Object *object_resolve_partial_path(Object *parent, | |||||
1178 | gchar **parts, | |||||
1179 | const char *typename, | |||||
1180 | bool_Bool *ambiguous) | |||||
1181 | { | |||||
1182 | Object *obj; | |||||
1183 | ObjectProperty *prop; | |||||
1184 | ||||||
1185 | obj = object_resolve_abs_path(parent, parts, typename, 0); | |||||
1186 | ||||||
1187 | QTAILQ_FOREACH(prop, &parent->properties, node)for ((prop) = ((&parent->properties)->tqh_first); ( prop); (prop) = ((prop)->node.tqe_next)) { | |||||
| ||||||
1188 | Object *found; | |||||
1189 | ||||||
1190 | if (!object_property_is_child(prop)) { | |||||
| ||||||
1191 | continue; | |||||
1192 | } | |||||
1193 | ||||||
1194 | found = object_resolve_partial_path(prop->opaque, parts, | |||||
1195 | typename, ambiguous); | |||||
1196 | if (found) { | |||||
1197 | if (obj) { | |||||
1198 | if (ambiguous) { | |||||
1199 | *ambiguous = true1; | |||||
1200 | } | |||||
1201 | return NULL((void*)0); | |||||
1202 | } | |||||
1203 | obj = found; | |||||
1204 | } | |||||
1205 | ||||||
1206 | if (ambiguous && *ambiguous) { | |||||
1207 | return NULL((void*)0); | |||||
1208 | } | |||||
1209 | } | |||||
1210 | ||||||
1211 | return obj; | |||||
1212 | } | |||||
1213 | ||||||
1214 | Object *object_resolve_path_type(const char *path, const char *typename, | |||||
1215 | bool_Bool *ambiguous) | |||||
1216 | { | |||||
1217 | Object *obj; | |||||
1218 | gchar **parts; | |||||
1219 | ||||||
1220 | parts = g_strsplit(path, "/", 0); | |||||
1221 | assert(parts)((parts) ? (void) (0) : __assert_fail ("parts", "/home/stefan/src/qemu/qemu.org/qemu/qom/object.c" , 1221, __PRETTY_FUNCTION__)); | |||||
1222 | ||||||
1223 | if (parts[0] == NULL((void*)0) || strcmp(parts[0], "") != 0) { | |||||
1224 | if (ambiguous) { | |||||
1225 | *ambiguous = false0; | |||||
1226 | } | |||||
1227 | obj = object_resolve_partial_path(object_get_root(), parts, | |||||
1228 | typename, ambiguous); | |||||
1229 | } else { | |||||
1230 | obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); | |||||
1231 | } | |||||
1232 | ||||||
1233 | g_strfreev(parts); | |||||
1234 | ||||||
1235 | return obj; | |||||
1236 | } | |||||
1237 | ||||||
1238 | Object *object_resolve_path(const char *path, bool_Bool *ambiguous) | |||||
1239 | { | |||||
1240 | return object_resolve_path_type(path, TYPE_OBJECT"object", ambiguous); | |||||
1241 | } | |||||
1242 | ||||||
1243 | typedef struct StringProperty | |||||
1244 | { | |||||
1245 | char *(*get)(Object *, Error **); | |||||
1246 | void (*set)(Object *, const char *, Error **); | |||||
1247 | } StringProperty; | |||||
1248 | ||||||
1249 | static void property_get_str(Object *obj, Visitor *v, void *opaque, | |||||
1250 | const char *name, Error **errp) | |||||
1251 | { | |||||
1252 | StringProperty *prop = opaque; | |||||
1253 | char *value; | |||||
1254 | ||||||
1255 | value = prop->get(obj, errp); | |||||
1256 | if (value) { | |||||
1257 | visit_type_str(v, &value, name, errp); | |||||
1258 | g_free(value); | |||||
1259 | } | |||||
1260 | } | |||||
1261 | ||||||
1262 | static void property_set_str(Object *obj, Visitor *v, void *opaque, | |||||
1263 | const char *name, Error **errp) | |||||
1264 | { | |||||
1265 | StringProperty *prop = opaque; | |||||
1266 | char *value; | |||||
1267 | Error *local_err = NULL((void*)0); | |||||
1268 | ||||||
1269 | visit_type_str(v, &value, name, &local_err); | |||||
1270 | if (local_err) { | |||||
1271 | error_propagate(errp, local_err); | |||||
1272 | return; | |||||
1273 | } | |||||
1274 | ||||||
1275 | prop->set(obj, value, errp); | |||||
1276 | g_free(value); | |||||
1277 | } | |||||
1278 | ||||||
1279 | static void property_release_str(Object *obj, const char *name, | |||||
1280 | void *opaque) | |||||
1281 | { | |||||
1282 | StringProperty *prop = opaque; | |||||
1283 | g_free(prop); | |||||
1284 | } | |||||
1285 | ||||||
1286 | void object_property_add_str(Object *obj, const char *name, | |||||
1287 | char *(*get)(Object *, Error **), | |||||
1288 | void (*set)(Object *, const char *, Error **), | |||||
1289 | Error **errp) | |||||
1290 | { | |||||
1291 | StringProperty *prop = g_malloc0(sizeof(*prop)); | |||||
1292 | ||||||
1293 | prop->get = get; | |||||
1294 | prop->set = set; | |||||
1295 | ||||||
1296 | object_property_add(obj, name, "string", | |||||
1297 | get ? property_get_str : NULL((void*)0), | |||||
1298 | set ? property_set_str : NULL((void*)0), | |||||
1299 | property_release_str, | |||||
1300 | prop, errp); | |||||
1301 | } | |||||
1302 | ||||||
1303 | typedef struct BoolProperty | |||||
1304 | { | |||||
1305 | bool_Bool (*get)(Object *, Error **); | |||||
1306 | void (*set)(Object *, bool_Bool, Error **); | |||||
1307 | } BoolProperty; | |||||
1308 | ||||||
1309 | static void property_get_bool(Object *obj, Visitor *v, void *opaque, | |||||
1310 | const char *name, Error **errp) | |||||
1311 | { | |||||
1312 | BoolProperty *prop = opaque; | |||||
1313 | bool_Bool value; | |||||
1314 | ||||||
1315 | value = prop->get(obj, errp); | |||||
1316 | visit_type_bool(v, &value, name, errp); | |||||
1317 | } | |||||
1318 | ||||||
1319 | static void property_set_bool(Object *obj, Visitor *v, void *opaque, | |||||
1320 | const char *name, Error **errp) | |||||
1321 | { | |||||
1322 | BoolProperty *prop = opaque; | |||||
1323 | bool_Bool value; | |||||
1324 | Error *local_err = NULL((void*)0); | |||||
1325 | ||||||
1326 | visit_type_bool(v, &value, name, &local_err); | |||||
1327 | if (local_err) { | |||||
1328 | error_propagate(errp, local_err); | |||||
1329 | return; | |||||
1330 | } | |||||
1331 | ||||||
1332 | prop->set(obj, value, errp); | |||||
1333 | } | |||||
1334 | ||||||
1335 | static void property_release_bool(Object *obj, const char *name, | |||||
1336 | void *opaque) | |||||
1337 | { | |||||
1338 | BoolProperty *prop = opaque; | |||||
1339 | g_free(prop); | |||||
1340 | } | |||||
1341 | ||||||
1342 | void object_property_add_bool(Object *obj, const char *name, | |||||
1343 | bool_Bool (*get)(Object *, Error **), | |||||
1344 | void (*set)(Object *, bool_Bool, Error **), | |||||
1345 | Error **errp) | |||||
1346 | { | |||||
1347 | BoolProperty *prop = g_malloc0(sizeof(*prop)); | |||||
1348 | ||||||
1349 | prop->get = get; | |||||
1350 | prop->set = set; | |||||
1351 | ||||||
1352 | object_property_add(obj, name, "bool", | |||||
1353 | get ? property_get_bool : NULL((void*)0), | |||||
1354 | set ? property_set_bool : NULL((void*)0), | |||||
1355 | property_release_bool, | |||||
1356 | prop, errp); | |||||
1357 | } | |||||
1358 | ||||||
1359 | static char *qdev_get_type(Object *obj, Error **errp) | |||||
1360 | { | |||||
1361 | return g_strdup(object_get_typename(obj)); | |||||
1362 | } | |||||
1363 | ||||||
1364 | static void property_get_uint8_ptr(Object *obj, Visitor *v, | |||||
1365 | void *opaque, const char *name, | |||||
1366 | Error **errp) | |||||
1367 | { | |||||
1368 | uint8_t value = *(uint8_t *)opaque; | |||||
1369 | visit_type_uint8(v, &value, name, errp); | |||||
1370 | } | |||||
1371 | ||||||
1372 | static void property_get_uint16_ptr(Object *obj, Visitor *v, | |||||
1373 | void *opaque, const char *name, | |||||
1374 | Error **errp) | |||||
1375 | { | |||||
1376 | uint16_t value = *(uint16_t *)opaque; | |||||
1377 | visit_type_uint16(v, &value, name, errp); | |||||
1378 | } | |||||
1379 | ||||||
1380 | static void property_get_uint32_ptr(Object *obj, Visitor *v, | |||||
1381 | void *opaque, const char *name, | |||||
1382 | Error **errp) | |||||
1383 | { | |||||
1384 | uint32_t value = *(uint32_t *)opaque; | |||||
1385 | visit_type_uint32(v, &value, name, errp); | |||||
1386 | } | |||||
1387 | ||||||
1388 | static void property_get_uint64_ptr(Object *obj, Visitor *v, | |||||
1389 | void *opaque, const char *name, | |||||
1390 | Error **errp) | |||||
1391 | { | |||||
1392 | uint64_t value = *(uint64_t *)opaque; | |||||
1393 | visit_type_uint64(v, &value, name, errp); | |||||
1394 | } | |||||
1395 | ||||||
1396 | void object_property_add_uint8_ptr(Object *obj, const char *name, | |||||
1397 | const uint8_t *v, Error **errp) | |||||
1398 | { | |||||
1399 | object_property_add(obj, name, "uint8", property_get_uint8_ptr, | |||||
1400 | NULL((void*)0), NULL((void*)0), (void *)v, errp); | |||||
1401 | } | |||||
1402 | ||||||
1403 | void object_property_add_uint16_ptr(Object *obj, const char *name, | |||||
1404 | const uint16_t *v, Error **errp) | |||||
1405 | { | |||||
1406 | object_property_add(obj, name, "uint16", property_get_uint16_ptr, | |||||
1407 | NULL((void*)0), NULL((void*)0), (void *)v, errp); | |||||
1408 | } | |||||
1409 | ||||||
1410 | void object_property_add_uint32_ptr(Object *obj, const char *name, | |||||
1411 | const uint32_t *v, Error **errp) | |||||
1412 | { | |||||
1413 | object_property_add(obj, name, "uint32", property_get_uint32_ptr, | |||||
1414 | NULL((void*)0), NULL((void*)0), (void *)v, errp); | |||||
1415 | } | |||||
1416 | ||||||
1417 | void object_property_add_uint64_ptr(Object *obj, const char *name, | |||||
1418 | const uint64_t *v, Error **errp) | |||||
1419 | { | |||||
1420 | object_property_add(obj, name, "uint64", property_get_uint64_ptr, | |||||
1421 | NULL((void*)0), NULL((void*)0), (void *)v, errp); | |||||
1422 | } | |||||
1423 | ||||||
1424 | static void object_instance_init(Object *obj) | |||||
1425 | { | |||||
1426 | object_property_add_str(obj, "type", qdev_get_type, NULL((void*)0), NULL((void*)0)); | |||||
1427 | } | |||||
1428 | ||||||
1429 | static void register_types(void) | |||||
1430 | { | |||||
1431 | static TypeInfo interface_info = { | |||||
1432 | .name = TYPE_INTERFACE"interface", | |||||
1433 | .class_size = sizeof(InterfaceClass), | |||||
1434 | .abstract = true1, | |||||
1435 | }; | |||||
1436 | ||||||
1437 | static TypeInfo object_info = { | |||||
1438 | .name = TYPE_OBJECT"object", | |||||
1439 | .instance_size = sizeof(Object), | |||||
1440 | .instance_init = object_instance_init, | |||||
1441 | .abstract = true1, | |||||
1442 | }; | |||||
1443 | ||||||
1444 | type_interface = type_register_internal(&interface_info); | |||||
1445 | type_register_internal(&object_info); | |||||
1446 | } | |||||
1447 | ||||||
1448 | type_init(register_types)static void __attribute__((constructor)) do_qemu_init_register_types (void) { register_module_init(register_types, MODULE_INIT_QOM ); } |