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