Annotation of qemu/qom/object.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU Object Model
        !             3:  *
        !             4:  * Copyright IBM, Corp. 2011
        !             5:  *
        !             6:  * Authors:
        !             7:  *  Anthony Liguori   <[email protected]>
        !             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 "qemu/object.h"
        !            14: #include "qemu-common.h"
        !            15: #include "qapi/qapi-visit-core.h"
        !            16: #include "qapi/string-input-visitor.h"
        !            17: #include "qapi/string-output-visitor.h"
        !            18: 
        !            19: /* TODO: replace QObject with a simpler visitor to avoid a dependency
        !            20:  * of the QOM core on QObject?  */
        !            21: #include "qemu/qom-qobject.h"
        !            22: #include "qobject.h"
        !            23: #include "qbool.h"
        !            24: #include "qint.h"
        !            25: #include "qstring.h"
        !            26: 
        !            27: #define MAX_INTERFACES 32
        !            28: 
        !            29: typedef struct InterfaceImpl InterfaceImpl;
        !            30: typedef struct TypeImpl TypeImpl;
        !            31: 
        !            32: struct InterfaceImpl
        !            33: {
        !            34:     const char *parent;
        !            35:     void (*interface_initfn)(ObjectClass *class, void *data);
        !            36:     TypeImpl *type;
        !            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_finalize)(ObjectClass *klass, void *data);
        !            49: 
        !            50:     void *class_data;
        !            51: 
        !            52:     void (*instance_init)(Object *obj);
        !            53:     void (*instance_finalize)(Object *obj);
        !            54: 
        !            55:     bool abstract;
        !            56: 
        !            57:     const char *parent;
        !            58:     TypeImpl *parent_type;
        !            59: 
        !            60:     ObjectClass *class;
        !            61: 
        !            62:     int num_interfaces;
        !            63:     InterfaceImpl interfaces[MAX_INTERFACES];
        !            64: };
        !            65: 
        !            66: typedef struct Interface
        !            67: {
        !            68:     Object parent;
        !            69:     Object *obj;
        !            70: } Interface;
        !            71: 
        !            72: #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
        !            73: 
        !            74: static Type type_interface;
        !            75: 
        !            76: static GHashTable *type_table_get(void)
        !            77: {
        !            78:     static GHashTable *type_table;
        !            79: 
        !            80:     if (type_table == NULL) {
        !            81:         type_table = g_hash_table_new(g_str_hash, g_str_equal);
        !            82:     }
        !            83: 
        !            84:     return type_table;
        !            85: }
        !            86: 
        !            87: static void type_table_add(TypeImpl *ti)
        !            88: {
        !            89:     g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
        !            90: }
        !            91: 
        !            92: static TypeImpl *type_table_lookup(const char *name)
        !            93: {
        !            94:     return g_hash_table_lookup(type_table_get(), name);
        !            95: }
        !            96: 
        !            97: TypeImpl *type_register(const TypeInfo *info)
        !            98: {
        !            99:     TypeImpl *ti = g_malloc0(sizeof(*ti));
        !           100: 
        !           101:     g_assert(info->name != NULL);
        !           102: 
        !           103:     if (type_table_lookup(info->name) != NULL) {
        !           104:         fprintf(stderr, "Registering `%s' which already exists\n", info->name);
        !           105:         abort();
        !           106:     }
        !           107: 
        !           108:     ti->name = g_strdup(info->name);
        !           109:     ti->parent = g_strdup(info->parent);
        !           110: 
        !           111:     ti->class_size = info->class_size;
        !           112:     ti->instance_size = info->instance_size;
        !           113: 
        !           114:     ti->class_init = info->class_init;
        !           115:     ti->class_finalize = info->class_finalize;
        !           116:     ti->class_data = info->class_data;
        !           117: 
        !           118:     ti->instance_init = info->instance_init;
        !           119:     ti->instance_finalize = info->instance_finalize;
        !           120: 
        !           121:     ti->abstract = info->abstract;
        !           122: 
        !           123:     if (info->interfaces) {
        !           124:         int i;
        !           125: 
        !           126:         for (i = 0; info->interfaces[i].type; i++) {
        !           127:             ti->interfaces[i].parent = info->interfaces[i].type;
        !           128:             ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
        !           129:             ti->num_interfaces++;
        !           130:         }
        !           131:     }
        !           132: 
        !           133:     type_table_add(ti);
        !           134: 
        !           135:     return ti;
        !           136: }
        !           137: 
        !           138: TypeImpl *type_register_static(const TypeInfo *info)
        !           139: {
        !           140:     return type_register(info);
        !           141: }
        !           142: 
        !           143: static TypeImpl *type_get_by_name(const char *name)
        !           144: {
        !           145:     if (name == NULL) {
        !           146:         return NULL;
        !           147:     }
        !           148: 
        !           149:     return type_table_lookup(name);
        !           150: }
        !           151: 
        !           152: static TypeImpl *type_get_parent(TypeImpl *type)
        !           153: {
        !           154:     if (!type->parent_type && type->parent) {
        !           155:         type->parent_type = type_get_by_name(type->parent);
        !           156:         g_assert(type->parent_type != NULL);
        !           157:     }
        !           158: 
        !           159:     return type->parent_type;
        !           160: }
        !           161: 
        !           162: static bool type_has_parent(TypeImpl *type)
        !           163: {
        !           164:     return (type->parent != NULL);
        !           165: }
        !           166: 
        !           167: static size_t type_class_get_size(TypeImpl *ti)
        !           168: {
        !           169:     if (ti->class_size) {
        !           170:         return ti->class_size;
        !           171:     }
        !           172: 
        !           173:     if (type_has_parent(ti)) {
        !           174:         return type_class_get_size(type_get_parent(ti));
        !           175:     }
        !           176: 
        !           177:     return sizeof(ObjectClass);
        !           178: }
        !           179: 
        !           180: static size_t type_object_get_size(TypeImpl *ti)
        !           181: {
        !           182:     if (ti->instance_size) {
        !           183:         return ti->instance_size;
        !           184:     }
        !           185: 
        !           186:     if (type_has_parent(ti)) {
        !           187:         return type_object_get_size(type_get_parent(ti));
        !           188:     }
        !           189: 
        !           190:     return 0;
        !           191: }
        !           192: 
        !           193: static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
        !           194: {
        !           195:     TypeInfo info = {
        !           196:         .instance_size = sizeof(Interface),
        !           197:         .parent = iface->parent,
        !           198:         .class_size = sizeof(InterfaceClass),
        !           199:         .class_init = iface->interface_initfn,
        !           200:         .abstract = true,
        !           201:     };
        !           202:     char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
        !           203: 
        !           204:     info.name = name;
        !           205:     iface->type = type_register(&info);
        !           206:     g_free(name);
        !           207: }
        !           208: 
        !           209: static void type_initialize(TypeImpl *ti)
        !           210: {
        !           211:     size_t class_size = sizeof(ObjectClass);
        !           212:     int i;
        !           213: 
        !           214:     if (ti->class) {
        !           215:         return;
        !           216:     }
        !           217: 
        !           218:     ti->class_size = type_class_get_size(ti);
        !           219:     ti->instance_size = type_object_get_size(ti);
        !           220: 
        !           221:     ti->class = g_malloc0(ti->class_size);
        !           222:     ti->class->type = ti;
        !           223: 
        !           224:     if (type_has_parent(ti)) {
        !           225:         TypeImpl *parent = type_get_parent(ti);
        !           226: 
        !           227:         type_initialize(parent);
        !           228: 
        !           229:         class_size = parent->class_size;
        !           230:         g_assert(parent->class_size <= ti->class_size);
        !           231: 
        !           232:         memcpy((void *)ti->class + sizeof(ObjectClass),
        !           233:                (void *)parent->class + sizeof(ObjectClass),
        !           234:                parent->class_size - sizeof(ObjectClass));
        !           235:     }
        !           236: 
        !           237:     memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
        !           238: 
        !           239:     for (i = 0; i < ti->num_interfaces; i++) {
        !           240:         type_class_interface_init(ti, &ti->interfaces[i]);
        !           241:     }
        !           242: 
        !           243:     if (ti->class_init) {
        !           244:         ti->class_init(ti->class, ti->class_data);
        !           245:     }
        !           246: }
        !           247: 
        !           248: static void object_interface_init(Object *obj, InterfaceImpl *iface)
        !           249: {
        !           250:     TypeImpl *ti = iface->type;
        !           251:     Interface *iface_obj;
        !           252: 
        !           253:     iface_obj = INTERFACE(object_new(ti->name));
        !           254:     iface_obj->obj = obj;
        !           255: 
        !           256:     obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
        !           257: }
        !           258: 
        !           259: static void object_init_with_type(Object *obj, TypeImpl *ti)
        !           260: {
        !           261:     int i;
        !           262: 
        !           263:     if (type_has_parent(ti)) {
        !           264:         object_init_with_type(obj, type_get_parent(ti));
        !           265:     }
        !           266: 
        !           267:     for (i = 0; i < ti->num_interfaces; i++) {
        !           268:         object_interface_init(obj, &ti->interfaces[i]);
        !           269:     }
        !           270: 
        !           271:     if (ti->instance_init) {
        !           272:         ti->instance_init(obj);
        !           273:     }
        !           274: }
        !           275: 
        !           276: void object_initialize_with_type(void *data, TypeImpl *type)
        !           277: {
        !           278:     Object *obj = data;
        !           279: 
        !           280:     g_assert(type != NULL);
        !           281:     type_initialize(type);
        !           282: 
        !           283:     g_assert(type->instance_size >= sizeof(Object));
        !           284:     g_assert(type->abstract == false);
        !           285: 
        !           286:     memset(obj, 0, type->instance_size);
        !           287:     obj->class = type->class;
        !           288:     QTAILQ_INIT(&obj->properties);
        !           289:     object_init_with_type(obj, type);
        !           290: }
        !           291: 
        !           292: void object_initialize(void *data, const char *typename)
        !           293: {
        !           294:     TypeImpl *type = type_get_by_name(typename);
        !           295: 
        !           296:     object_initialize_with_type(data, type);
        !           297: }
        !           298: 
        !           299: static void object_property_del_all(Object *obj)
        !           300: {
        !           301:     while (!QTAILQ_EMPTY(&obj->properties)) {
        !           302:         ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
        !           303: 
        !           304:         QTAILQ_REMOVE(&obj->properties, prop, node);
        !           305: 
        !           306:         if (prop->release) {
        !           307:             prop->release(obj, prop->name, prop->opaque);
        !           308:         }
        !           309: 
        !           310:         g_free(prop->name);
        !           311:         g_free(prop->type);
        !           312:         g_free(prop);
        !           313:     }
        !           314: }
        !           315: 
        !           316: static void object_property_del_child(Object *obj, Object *child, Error **errp)
        !           317: {
        !           318:     ObjectProperty *prop;
        !           319: 
        !           320:     QTAILQ_FOREACH(prop, &obj->properties, node) {
        !           321:         if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
        !           322:             object_property_del(obj, prop->name, errp);
        !           323:             break;
        !           324:         }
        !           325:     }
        !           326: }
        !           327: 
        !           328: void object_unparent(Object *obj)
        !           329: {
        !           330:     if (obj->parent) {
        !           331:         object_property_del_child(obj->parent, obj, NULL);
        !           332:     }
        !           333: }
        !           334: 
        !           335: static void object_deinit(Object *obj, TypeImpl *type)
        !           336: {
        !           337:     if (type->instance_finalize) {
        !           338:         type->instance_finalize(obj);
        !           339:     }
        !           340: 
        !           341:     while (obj->interfaces) {
        !           342:         Interface *iface_obj = obj->interfaces->data;
        !           343:         obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
        !           344:         object_delete(OBJECT(iface_obj));
        !           345:     }
        !           346: 
        !           347:     if (type_has_parent(type)) {
        !           348:         object_deinit(obj, type_get_parent(type));
        !           349:     }
        !           350: 
        !           351:     object_unparent(obj);
        !           352: }
        !           353: 
        !           354: void object_finalize(void *data)
        !           355: {
        !           356:     Object *obj = data;
        !           357:     TypeImpl *ti = obj->class->type;
        !           358: 
        !           359:     object_deinit(obj, ti);
        !           360:     object_property_del_all(obj);
        !           361: 
        !           362:     g_assert(obj->ref == 0);
        !           363: }
        !           364: 
        !           365: Object *object_new_with_type(Type type)
        !           366: {
        !           367:     Object *obj;
        !           368: 
        !           369:     g_assert(type != NULL);
        !           370:     type_initialize(type);
        !           371: 
        !           372:     obj = g_malloc(type->instance_size);
        !           373:     object_initialize_with_type(obj, type);
        !           374:     object_ref(obj);
        !           375: 
        !           376:     return obj;
        !           377: }
        !           378: 
        !           379: Object *object_new(const char *typename)
        !           380: {
        !           381:     TypeImpl *ti = type_get_by_name(typename);
        !           382: 
        !           383:     return object_new_with_type(ti);
        !           384: }
        !           385: 
        !           386: void object_delete(Object *obj)
        !           387: {
        !           388:     object_unref(obj);
        !           389:     g_assert(obj->ref == 0);
        !           390:     g_free(obj);
        !           391: }
        !           392: 
        !           393: static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
        !           394: {
        !           395:     assert(target_type);
        !           396: 
        !           397:     /* Check if typename is a direct ancestor of type */
        !           398:     while (type) {
        !           399:         if (type == target_type) {
        !           400:             return true;
        !           401:         }
        !           402: 
        !           403:         type = type_get_parent(type);
        !           404:     }
        !           405: 
        !           406:     return false;
        !           407: }
        !           408: 
        !           409: static bool object_is_type(Object *obj, TypeImpl *target_type)
        !           410: {
        !           411:     return !target_type || type_is_ancestor(obj->class->type, target_type);
        !           412: }
        !           413: 
        !           414: Object *object_dynamic_cast(Object *obj, const char *typename)
        !           415: {
        !           416:     TypeImpl *target_type = type_get_by_name(typename);
        !           417:     GSList *i;
        !           418: 
        !           419:     /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
        !           420:      * we want to go back from interfaces to the parent.
        !           421:     */
        !           422:     if (target_type && object_is_type(obj, target_type)) {
        !           423:         return obj;
        !           424:     }
        !           425: 
        !           426:     /* Check if obj is an interface and its containing object is a direct
        !           427:      * ancestor of typename.  In principle we could do this test at the very
        !           428:      * beginning of object_dynamic_cast, avoiding a second call to
        !           429:      * object_is_type.  However, casting between interfaces is relatively
        !           430:      * rare, and object_is_type(obj, type_interface) would fail almost always.
        !           431:      *
        !           432:      * Perhaps we could add a magic value to the object header for increased
        !           433:      * (run-time) type safety and to speed up tests like this one.  If we ever
        !           434:      * do that we can revisit the order here.
        !           435:      */
        !           436:     if (object_is_type(obj, type_interface)) {
        !           437:         assert(!obj->interfaces);
        !           438:         obj = INTERFACE(obj)->obj;
        !           439:         if (object_is_type(obj, target_type)) {
        !           440:             return obj;
        !           441:         }
        !           442:     }
        !           443: 
        !           444:     if (!target_type) {
        !           445:         return obj;
        !           446:     }
        !           447: 
        !           448:     /* Check if obj has an interface of typename */
        !           449:     for (i = obj->interfaces; i; i = i->next) {
        !           450:         Interface *iface = i->data;
        !           451: 
        !           452:         if (object_is_type(OBJECT(iface), target_type)) {
        !           453:             return OBJECT(iface);
        !           454:         }
        !           455:     }
        !           456: 
        !           457:     return NULL;
        !           458: }
        !           459: 
        !           460: 
        !           461: static void register_types(void)
        !           462: {
        !           463:     static TypeInfo interface_info = {
        !           464:         .name = TYPE_INTERFACE,
        !           465:         .instance_size = sizeof(Interface),
        !           466:         .abstract = true,
        !           467:     };
        !           468: 
        !           469:     type_interface = type_register_static(&interface_info);
        !           470: }
        !           471: 
        !           472: type_init(register_types)
        !           473: 
        !           474: Object *object_dynamic_cast_assert(Object *obj, const char *typename)
        !           475: {
        !           476:     Object *inst;
        !           477: 
        !           478:     inst = object_dynamic_cast(obj, typename);
        !           479: 
        !           480:     if (!inst) {
        !           481:         fprintf(stderr, "Object %p is not an instance of type %s\n",
        !           482:                 obj, typename);
        !           483:         abort();
        !           484:     }
        !           485: 
        !           486:     return inst;
        !           487: }
        !           488: 
        !           489: ObjectClass *object_class_dynamic_cast(ObjectClass *class,
        !           490:                                        const char *typename)
        !           491: {
        !           492:     TypeImpl *target_type = type_get_by_name(typename);
        !           493:     TypeImpl *type = class->type;
        !           494: 
        !           495:     while (type) {
        !           496:         if (type == target_type) {
        !           497:             return class;
        !           498:         }
        !           499: 
        !           500:         type = type_get_parent(type);
        !           501:     }
        !           502: 
        !           503:     return NULL;
        !           504: }
        !           505: 
        !           506: ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
        !           507:                                               const char *typename)
        !           508: {
        !           509:     ObjectClass *ret = object_class_dynamic_cast(class, typename);
        !           510: 
        !           511:     if (!ret) {
        !           512:         fprintf(stderr, "Object %p is not an instance of type %s\n",
        !           513:                 class, typename);
        !           514:         abort();
        !           515:     }
        !           516: 
        !           517:     return ret;
        !           518: }
        !           519: 
        !           520: const char *object_get_typename(Object *obj)
        !           521: {
        !           522:     return obj->class->type->name;
        !           523: }
        !           524: 
        !           525: ObjectClass *object_get_class(Object *obj)
        !           526: {
        !           527:     return obj->class;
        !           528: }
        !           529: 
        !           530: const char *object_class_get_name(ObjectClass *klass)
        !           531: {
        !           532:     return klass->type->name;
        !           533: }
        !           534: 
        !           535: ObjectClass *object_class_by_name(const char *typename)
        !           536: {
        !           537:     TypeImpl *type = type_get_by_name(typename);
        !           538: 
        !           539:     if (!type) {
        !           540:         return NULL;
        !           541:     }
        !           542: 
        !           543:     type_initialize(type);
        !           544: 
        !           545:     return type->class;
        !           546: }
        !           547: 
        !           548: typedef struct OCFData
        !           549: {
        !           550:     void (*fn)(ObjectClass *klass, void *opaque);
        !           551:     const char *implements_type;
        !           552:     bool include_abstract;
        !           553:     void *opaque;
        !           554: } OCFData;
        !           555: 
        !           556: static void object_class_foreach_tramp(gpointer key, gpointer value,
        !           557:                                        gpointer opaque)
        !           558: {
        !           559:     OCFData *data = opaque;
        !           560:     TypeImpl *type = value;
        !           561:     ObjectClass *k;
        !           562: 
        !           563:     type_initialize(type);
        !           564:     k = type->class;
        !           565: 
        !           566:     if (!data->include_abstract && type->abstract) {
        !           567:         return;
        !           568:     }
        !           569: 
        !           570:     if (data->implements_type && 
        !           571:         !object_class_dynamic_cast(k, data->implements_type)) {
        !           572:         return;
        !           573:     }
        !           574: 
        !           575:     data->fn(k, data->opaque);
        !           576: }
        !           577: 
        !           578: void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
        !           579:                           const char *implements_type, bool include_abstract,
        !           580:                           void *opaque)
        !           581: {
        !           582:     OCFData data = { fn, implements_type, include_abstract, opaque };
        !           583: 
        !           584:     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
        !           585: }
        !           586: 
        !           587: static void object_class_get_list_tramp(ObjectClass *klass, void *opaque)
        !           588: {
        !           589:     GSList **list = opaque;
        !           590: 
        !           591:     *list = g_slist_prepend(*list, klass);
        !           592: }
        !           593: 
        !           594: GSList *object_class_get_list(const char *implements_type,
        !           595:                               bool include_abstract)
        !           596: {
        !           597:     GSList *list = NULL;
        !           598: 
        !           599:     object_class_foreach(object_class_get_list_tramp,
        !           600:                          implements_type, include_abstract, &list);
        !           601:     return list;
        !           602: }
        !           603: 
        !           604: void object_ref(Object *obj)
        !           605: {
        !           606:     obj->ref++;
        !           607: }
        !           608: 
        !           609: void object_unref(Object *obj)
        !           610: {
        !           611:     g_assert(obj->ref > 0);
        !           612:     obj->ref--;
        !           613: 
        !           614:     /* parent always holds a reference to its children */
        !           615:     if (obj->ref == 0) {
        !           616:         object_finalize(obj);
        !           617:     }
        !           618: }
        !           619: 
        !           620: void object_property_add(Object *obj, const char *name, const char *type,
        !           621:                          ObjectPropertyAccessor *get,
        !           622:                          ObjectPropertyAccessor *set,
        !           623:                          ObjectPropertyRelease *release,
        !           624:                          void *opaque, Error **errp)
        !           625: {
        !           626:     ObjectProperty *prop = g_malloc0(sizeof(*prop));
        !           627: 
        !           628:     prop->name = g_strdup(name);
        !           629:     prop->type = g_strdup(type);
        !           630: 
        !           631:     prop->get = get;
        !           632:     prop->set = set;
        !           633:     prop->release = release;
        !           634:     prop->opaque = opaque;
        !           635: 
        !           636:     QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
        !           637: }
        !           638: 
        !           639: static ObjectProperty *object_property_find(Object *obj, const char *name)
        !           640: {
        !           641:     ObjectProperty *prop;
        !           642: 
        !           643:     QTAILQ_FOREACH(prop, &obj->properties, node) {
        !           644:         if (strcmp(prop->name, name) == 0) {
        !           645:             return prop;
        !           646:         }
        !           647:     }
        !           648: 
        !           649:     return NULL;
        !           650: }
        !           651: 
        !           652: void object_property_del(Object *obj, const char *name, Error **errp)
        !           653: {
        !           654:     ObjectProperty *prop = object_property_find(obj, name);
        !           655: 
        !           656:     QTAILQ_REMOVE(&obj->properties, prop, node);
        !           657: 
        !           658:     prop->release(obj, prop->name, prop->opaque);
        !           659: 
        !           660:     g_free(prop->name);
        !           661:     g_free(prop->type);
        !           662:     g_free(prop);
        !           663: }
        !           664: 
        !           665: void object_property_get(Object *obj, Visitor *v, const char *name,
        !           666:                          Error **errp)
        !           667: {
        !           668:     ObjectProperty *prop = object_property_find(obj, name);
        !           669: 
        !           670:     if (prop == NULL) {
        !           671:         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
        !           672:         return;
        !           673:     }
        !           674: 
        !           675:     if (!prop->get) {
        !           676:         error_set(errp, QERR_PERMISSION_DENIED);
        !           677:     } else {
        !           678:         prop->get(obj, v, prop->opaque, name, errp);
        !           679:     }
        !           680: }
        !           681: 
        !           682: void object_property_set(Object *obj, Visitor *v, const char *name,
        !           683:                          Error **errp)
        !           684: {
        !           685:     ObjectProperty *prop = object_property_find(obj, name);
        !           686: 
        !           687:     if (prop == NULL) {
        !           688:         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
        !           689:         return;
        !           690:     }
        !           691: 
        !           692:     if (!prop->set) {
        !           693:         error_set(errp, QERR_PERMISSION_DENIED);
        !           694:     } else {
        !           695:         prop->set(obj, v, prop->opaque, name, errp);
        !           696:     }
        !           697: }
        !           698: 
        !           699: void object_property_set_str(Object *obj, const char *value,
        !           700:                              const char *name, Error **errp)
        !           701: {
        !           702:     QString *qstr = qstring_from_str(value);
        !           703:     object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
        !           704: 
        !           705:     QDECREF(qstr);
        !           706: }
        !           707: 
        !           708: char *object_property_get_str(Object *obj, const char *name,
        !           709:                               Error **errp)
        !           710: {
        !           711:     QObject *ret = object_property_get_qobject(obj, name, errp);
        !           712:     QString *qstring;
        !           713:     char *retval;
        !           714: 
        !           715:     if (!ret) {
        !           716:         return NULL;
        !           717:     }
        !           718:     qstring = qobject_to_qstring(ret);
        !           719:     if (!qstring) {
        !           720:         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
        !           721:         retval = NULL;
        !           722:     } else {
        !           723:         retval = g_strdup(qstring_get_str(qstring));
        !           724:     }
        !           725: 
        !           726:     QDECREF(qstring);
        !           727:     return retval;
        !           728: }
        !           729: 
        !           730: void object_property_set_link(Object *obj, Object *value,
        !           731:                               const char *name, Error **errp)
        !           732: {
        !           733:     object_property_set_str(obj, object_get_canonical_path(value),
        !           734:                             name, errp);
        !           735: }
        !           736: 
        !           737: Object *object_property_get_link(Object *obj, const char *name,
        !           738:                                  Error **errp)
        !           739: {
        !           740:     char *str = object_property_get_str(obj, name, errp);
        !           741:     Object *target = NULL;
        !           742: 
        !           743:     if (str && *str) {
        !           744:         target = object_resolve_path(str, NULL);
        !           745:         if (!target) {
        !           746:             error_set(errp, QERR_DEVICE_NOT_FOUND, str);
        !           747:         }
        !           748:     }
        !           749: 
        !           750:     g_free(str);
        !           751:     return target;
        !           752: }
        !           753: 
        !           754: void object_property_set_bool(Object *obj, bool value,
        !           755:                               const char *name, Error **errp)
        !           756: {
        !           757:     QBool *qbool = qbool_from_int(value);
        !           758:     object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
        !           759: 
        !           760:     QDECREF(qbool);
        !           761: }
        !           762: 
        !           763: bool object_property_get_bool(Object *obj, const char *name,
        !           764:                               Error **errp)
        !           765: {
        !           766:     QObject *ret = object_property_get_qobject(obj, name, errp);
        !           767:     QBool *qbool;
        !           768:     bool retval;
        !           769: 
        !           770:     if (!ret) {
        !           771:         return false;
        !           772:     }
        !           773:     qbool = qobject_to_qbool(ret);
        !           774:     if (!qbool) {
        !           775:         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
        !           776:         retval = false;
        !           777:     } else {
        !           778:         retval = qbool_get_int(qbool);
        !           779:     }
        !           780: 
        !           781:     QDECREF(qbool);
        !           782:     return retval;
        !           783: }
        !           784: 
        !           785: void object_property_set_int(Object *obj, int64_t value,
        !           786:                              const char *name, Error **errp)
        !           787: {
        !           788:     QInt *qint = qint_from_int(value);
        !           789:     object_property_set_qobject(obj, QOBJECT(qint), name, errp);
        !           790: 
        !           791:     QDECREF(qint);
        !           792: }
        !           793: 
        !           794: int64_t object_property_get_int(Object *obj, const char *name,
        !           795:                                 Error **errp)
        !           796: {
        !           797:     QObject *ret = object_property_get_qobject(obj, name, errp);
        !           798:     QInt *qint;
        !           799:     int64_t retval;
        !           800: 
        !           801:     if (!ret) {
        !           802:         return -1;
        !           803:     }
        !           804:     qint = qobject_to_qint(ret);
        !           805:     if (!qint) {
        !           806:         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
        !           807:         retval = -1;
        !           808:     } else {
        !           809:         retval = qint_get_int(qint);
        !           810:     }
        !           811: 
        !           812:     QDECREF(qint);
        !           813:     return retval;
        !           814: }
        !           815: 
        !           816: void object_property_parse(Object *obj, const char *string,
        !           817:                            const char *name, Error **errp)
        !           818: {
        !           819:     StringInputVisitor *mi;
        !           820:     mi = string_input_visitor_new(string);
        !           821:     object_property_set(obj, string_input_get_visitor(mi), name, errp);
        !           822: 
        !           823:     string_input_visitor_cleanup(mi);
        !           824: }
        !           825: 
        !           826: char *object_property_print(Object *obj, const char *name,
        !           827:                             Error **errp)
        !           828: {
        !           829:     StringOutputVisitor *mo;
        !           830:     char *string;
        !           831: 
        !           832:     mo = string_output_visitor_new();
        !           833:     object_property_get(obj, string_output_get_visitor(mo), name, errp);
        !           834:     string = string_output_get_string(mo);
        !           835:     string_output_visitor_cleanup(mo);
        !           836:     return string;
        !           837: }
        !           838: 
        !           839: const char *object_property_get_type(Object *obj, const char *name, Error **errp)
        !           840: {
        !           841:     ObjectProperty *prop = object_property_find(obj, name);
        !           842: 
        !           843:     if (prop == NULL) {
        !           844:         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
        !           845:         return NULL;
        !           846:     }
        !           847: 
        !           848:     return prop->type;
        !           849: }
        !           850: 
        !           851: Object *object_get_root(void)
        !           852: {
        !           853:     static Object *root;
        !           854: 
        !           855:     if (!root) {
        !           856:         root = object_new("container");
        !           857:     }
        !           858: 
        !           859:     return root;
        !           860: }
        !           861: 
        !           862: static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
        !           863:                                       const char *name, Error **errp)
        !           864: {
        !           865:     Object *child = opaque;
        !           866:     gchar *path;
        !           867: 
        !           868:     path = object_get_canonical_path(child);
        !           869:     visit_type_str(v, &path, name, errp);
        !           870:     g_free(path);
        !           871: }
        !           872: 
        !           873: static void object_finalize_child_property(Object *obj, const char *name,
        !           874:                                            void *opaque)
        !           875: {
        !           876:     Object *child = opaque;
        !           877: 
        !           878:     object_unref(child);
        !           879: }
        !           880: 
        !           881: void object_property_add_child(Object *obj, const char *name,
        !           882:                                Object *child, Error **errp)
        !           883: {
        !           884:     gchar *type;
        !           885: 
        !           886:     /* Registering an interface object in the composition tree will mightily
        !           887:      * confuse object_get_canonical_path (which, on the other hand, knows how
        !           888:      * to get the canonical path of an interface object).
        !           889:      */
        !           890:     assert(!object_is_type(obj, type_interface));
        !           891: 
        !           892:     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
        !           893: 
        !           894:     object_property_add(obj, name, type, object_get_child_property,
        !           895:                         NULL, object_finalize_child_property, child, errp);
        !           896: 
        !           897:     object_ref(child);
        !           898:     g_assert(child->parent == NULL);
        !           899:     child->parent = obj;
        !           900: 
        !           901:     g_free(type);
        !           902: }
        !           903: 
        !           904: static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
        !           905:                                      const char *name, Error **errp)
        !           906: {
        !           907:     Object **child = opaque;
        !           908:     gchar *path;
        !           909: 
        !           910:     if (*child) {
        !           911:         path = object_get_canonical_path(*child);
        !           912:         visit_type_str(v, &path, name, errp);
        !           913:         g_free(path);
        !           914:     } else {
        !           915:         path = (gchar *)"";
        !           916:         visit_type_str(v, &path, name, errp);
        !           917:     }
        !           918: }
        !           919: 
        !           920: static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
        !           921:                                      const char *name, Error **errp)
        !           922: {
        !           923:     Object **child = opaque;
        !           924:     Object *old_target;
        !           925:     bool ambiguous = false;
        !           926:     const char *type;
        !           927:     char *path;
        !           928:     gchar *target_type;
        !           929: 
        !           930:     type = object_property_get_type(obj, name, NULL);
        !           931: 
        !           932:     visit_type_str(v, &path, name, errp);
        !           933: 
        !           934:     old_target = *child;
        !           935:     *child = NULL;
        !           936: 
        !           937:     if (strcmp(path, "") != 0) {
        !           938:         Object *target;
        !           939: 
        !           940:         /* Go from link<FOO> to FOO.  */
        !           941:         target_type = g_strndup(&type[5], strlen(type) - 6);
        !           942:         target = object_resolve_path_type(path, target_type, &ambiguous);
        !           943: 
        !           944:         if (ambiguous) {
        !           945:             error_set(errp, QERR_AMBIGUOUS_PATH, path);
        !           946:         } else if (target) {
        !           947:             object_ref(target);
        !           948:             *child = target;
        !           949:         } else {
        !           950:             target = object_resolve_path(path, &ambiguous);
        !           951:             if (target || ambiguous) {
        !           952:                 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
        !           953:             } else {
        !           954:                 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
        !           955:             }
        !           956:         }
        !           957:         g_free(target_type);
        !           958:     }
        !           959: 
        !           960:     g_free(path);
        !           961: 
        !           962:     if (old_target != NULL) {
        !           963:         object_unref(old_target);
        !           964:     }
        !           965: }
        !           966: 
        !           967: void object_property_add_link(Object *obj, const char *name,
        !           968:                               const char *type, Object **child,
        !           969:                               Error **errp)
        !           970: {
        !           971:     gchar *full_type;
        !           972: 
        !           973:     full_type = g_strdup_printf("link<%s>", type);
        !           974: 
        !           975:     object_property_add(obj, name, full_type,
        !           976:                         object_get_link_property,
        !           977:                         object_set_link_property,
        !           978:                         NULL, child, errp);
        !           979: 
        !           980:     g_free(full_type);
        !           981: }
        !           982: 
        !           983: gchar *object_get_canonical_path(Object *obj)
        !           984: {
        !           985:     Object *root = object_get_root();
        !           986:     char *newpath = NULL, *path = NULL;
        !           987: 
        !           988:     if (object_is_type(obj, type_interface)) {
        !           989:         obj = INTERFACE(obj)->obj;
        !           990:     }
        !           991: 
        !           992:     while (obj != root) {
        !           993:         ObjectProperty *prop = NULL;
        !           994: 
        !           995:         g_assert(obj->parent != NULL);
        !           996: 
        !           997:         QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
        !           998:             if (!strstart(prop->type, "child<", NULL)) {
        !           999:                 continue;
        !          1000:             }
        !          1001: 
        !          1002:             if (prop->opaque == obj) {
        !          1003:                 if (path) {
        !          1004:                     newpath = g_strdup_printf("%s/%s", prop->name, path);
        !          1005:                     g_free(path);
        !          1006:                     path = newpath;
        !          1007:                 } else {
        !          1008:                     path = g_strdup(prop->name);
        !          1009:                 }
        !          1010:                 break;
        !          1011:             }
        !          1012:         }
        !          1013: 
        !          1014:         g_assert(prop != NULL);
        !          1015: 
        !          1016:         obj = obj->parent;
        !          1017:     }
        !          1018: 
        !          1019:     newpath = g_strdup_printf("/%s", path);
        !          1020:     g_free(path);
        !          1021: 
        !          1022:     return newpath;
        !          1023: }
        !          1024: 
        !          1025: Object *object_resolve_path_component(Object *parent, gchar *part)
        !          1026: {
        !          1027:     ObjectProperty *prop = object_property_find(parent, part);
        !          1028:     if (prop == NULL) {
        !          1029:         return NULL;
        !          1030:     }
        !          1031: 
        !          1032:     if (strstart(prop->type, "link<", NULL)) {
        !          1033:         return *(Object **)prop->opaque;
        !          1034:     } else if (strstart(prop->type, "child<", NULL)) {
        !          1035:         return prop->opaque;
        !          1036:     } else {
        !          1037:         return NULL;
        !          1038:     }
        !          1039: }
        !          1040: 
        !          1041: static Object *object_resolve_abs_path(Object *parent,
        !          1042:                                           gchar **parts,
        !          1043:                                           const char *typename,
        !          1044:                                           int index)
        !          1045: {
        !          1046:     Object *child;
        !          1047: 
        !          1048:     if (parts[index] == NULL) {
        !          1049:         return object_dynamic_cast(parent, typename);
        !          1050:     }
        !          1051: 
        !          1052:     if (strcmp(parts[index], "") == 0) {
        !          1053:         return object_resolve_abs_path(parent, parts, typename, index + 1);
        !          1054:     }
        !          1055: 
        !          1056:     child = object_resolve_path_component(parent, parts[index]);
        !          1057:     if (!child) {
        !          1058:         return NULL;
        !          1059:     }
        !          1060: 
        !          1061:     return object_resolve_abs_path(child, parts, typename, index + 1);
        !          1062: }
        !          1063: 
        !          1064: static Object *object_resolve_partial_path(Object *parent,
        !          1065:                                               gchar **parts,
        !          1066:                                               const char *typename,
        !          1067:                                               bool *ambiguous)
        !          1068: {
        !          1069:     Object *obj;
        !          1070:     ObjectProperty *prop;
        !          1071: 
        !          1072:     obj = object_resolve_abs_path(parent, parts, typename, 0);
        !          1073: 
        !          1074:     QTAILQ_FOREACH(prop, &parent->properties, node) {
        !          1075:         Object *found;
        !          1076: 
        !          1077:         if (!strstart(prop->type, "child<", NULL)) {
        !          1078:             continue;
        !          1079:         }
        !          1080: 
        !          1081:         found = object_resolve_partial_path(prop->opaque, parts,
        !          1082:                                             typename, ambiguous);
        !          1083:         if (found) {
        !          1084:             if (obj) {
        !          1085:                 if (ambiguous) {
        !          1086:                     *ambiguous = true;
        !          1087:                 }
        !          1088:                 return NULL;
        !          1089:             }
        !          1090:             obj = found;
        !          1091:         }
        !          1092: 
        !          1093:         if (ambiguous && *ambiguous) {
        !          1094:             return NULL;
        !          1095:         }
        !          1096:     }
        !          1097: 
        !          1098:     return obj;
        !          1099: }
        !          1100: 
        !          1101: Object *object_resolve_path_type(const char *path, const char *typename,
        !          1102:                                  bool *ambiguous)
        !          1103: {
        !          1104:     bool partial_path = true;
        !          1105:     Object *obj;
        !          1106:     gchar **parts;
        !          1107: 
        !          1108:     parts = g_strsplit(path, "/", 0);
        !          1109:     if (parts == NULL || parts[0] == NULL) {
        !          1110:         g_strfreev(parts);
        !          1111:         return object_get_root();
        !          1112:     }
        !          1113: 
        !          1114:     if (strcmp(parts[0], "") == 0) {
        !          1115:         partial_path = false;
        !          1116:     }
        !          1117: 
        !          1118:     if (partial_path) {
        !          1119:         if (ambiguous) {
        !          1120:             *ambiguous = false;
        !          1121:         }
        !          1122:         obj = object_resolve_partial_path(object_get_root(), parts,
        !          1123:                                           typename, ambiguous);
        !          1124:     } else {
        !          1125:         obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
        !          1126:     }
        !          1127: 
        !          1128:     g_strfreev(parts);
        !          1129: 
        !          1130:     return obj;
        !          1131: }
        !          1132: 
        !          1133: Object *object_resolve_path(const char *path, bool *ambiguous)
        !          1134: {
        !          1135:     return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
        !          1136: }
        !          1137: 
        !          1138: typedef struct StringProperty
        !          1139: {
        !          1140:     char *(*get)(Object *, Error **);
        !          1141:     void (*set)(Object *, const char *, Error **);
        !          1142: } StringProperty;
        !          1143: 
        !          1144: static void property_get_str(Object *obj, Visitor *v, void *opaque,
        !          1145:                              const char *name, Error **errp)
        !          1146: {
        !          1147:     StringProperty *prop = opaque;
        !          1148:     char *value;
        !          1149: 
        !          1150:     value = prop->get(obj, errp);
        !          1151:     if (value) {
        !          1152:         visit_type_str(v, &value, name, errp);
        !          1153:         g_free(value);
        !          1154:     }
        !          1155: }
        !          1156: 
        !          1157: static void property_set_str(Object *obj, Visitor *v, void *opaque,
        !          1158:                              const char *name, Error **errp)
        !          1159: {
        !          1160:     StringProperty *prop = opaque;
        !          1161:     char *value;
        !          1162:     Error *local_err = NULL;
        !          1163: 
        !          1164:     visit_type_str(v, &value, name, &local_err);
        !          1165:     if (local_err) {
        !          1166:         error_propagate(errp, local_err);
        !          1167:         return;
        !          1168:     }
        !          1169: 
        !          1170:     prop->set(obj, value, errp);
        !          1171:     g_free(value);
        !          1172: }
        !          1173: 
        !          1174: static void property_release_str(Object *obj, const char *name,
        !          1175:                                  void *opaque)
        !          1176: {
        !          1177:     StringProperty *prop = opaque;
        !          1178:     g_free(prop);
        !          1179: }
        !          1180: 
        !          1181: void object_property_add_str(Object *obj, const char *name,
        !          1182:                            char *(*get)(Object *, Error **),
        !          1183:                            void (*set)(Object *, const char *, Error **),
        !          1184:                            Error **errp)
        !          1185: {
        !          1186:     StringProperty *prop = g_malloc0(sizeof(*prop));
        !          1187: 
        !          1188:     prop->get = get;
        !          1189:     prop->set = set;
        !          1190: 
        !          1191:     object_property_add(obj, name, "string",
        !          1192:                         get ? property_get_str : NULL,
        !          1193:                         set ? property_set_str : NULL,
        !          1194:                         property_release_str,
        !          1195:                         prop, errp);
        !          1196: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.