QEMU網絡虛擬化(三):面向對象的模型QOM

qemu面向對象的模型:QOM

qemu用結構體實現了一套面向對象的機制,用於實現類和對象的概念,也實現了面向對象的封裝、繼承、多態。大部分設備模擬代碼都會基於這個qom模型。

相關數據結構:

類定義:

struct ObjectClass
{
    /*< private >*/
    Type type;  /* typedef struct TypeImpl *Type  */
    GSList *interfaces;
    const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
    const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];
    ObjectUnparent *unparent;
    GHashTable *properties;
};

對象定義:

struct Object
{
    /*< private >*/
    ObjectClass *class;
    ObjectFree *free; /* 當引用技術爲0時,清理垃圾的回調函數 */
    GHashTable *properties; /* 屬性的Hash表*/
    uint32_t ref; /* 對象引用計數 */
    Object *parent;
};

屬性定義:

typedef struct ObjectProperty
{
    gchar *name;
    gchar *type;
    gchar *description;
    ObjectPropertyAccessor *get; 
    ObjectPropertyAccessor *set;
    ObjectPropertyResolve *resolve;
    ObjectPropertyRelease *release;
    void *opaque;
} ObjectProperty;

每個object對象會有上述對應的屬性結構,並用哈希表組織了起來。當需要增加或者刪除屬性時,可調用object_property_add或object_property_del函數。

定義一個類型:

struct TypeInfo
{   
    const char *name;
    const char *parent;
    
    size_t instance_size; 
    void (*instance_init)(Object *obj); /* 實例初始化 */
    void (*instance_post_init)(Object *obj); 
    void (*instance_finalize)(Object *obj); /* 實例析構 */

    bool abstract;
    size_t class_size;

    void (*class_init)(ObjectClass *klass, void *data); /* 類初始化 */
    void (*class_base_init)(ObjectClass *klass, void *data);
    void (*class_finalize)(ObjectClass *klass, void *data); /* 類析構 */
    void *class_data;               
                                    
    InterfaceInfo *interfaces; 
};
#define type_init(function) module_init(function, MODULE_INIT_QOM) 

type_register函數會根據TypeInfo結構體生成TypeImpl結構體,並將name作爲key,創建全局hash表:

struct TypeImpl
{
    const char *name; 
    size_t class_size;
    size_t instance_size;
    void (*class_init)(ObjectClass *klass, void *data); /* 類初始化 */
    void (*class_base_init)(ObjectClass *klass, void *data);
    void *class_data;
    void (*instance_init)(Object *obj); /* 實例初始化 */
    void (*instance_post_init)(Object *obj);
    void (*instance_finalize)(Object *obj);
    bool abstract;
    const char *parent;
    TypeImpl *parent_type; /* 指向父類型 */
    ObjectClass *class;
    int num_interfaces;
    InterfaceImpl interfaces[MAX_INTERFACES];
};

類的基本信息是通過這個TypeImpl體現的

類的數據結構一般包含大量的函數指針,用於對對象進行操作。class對應的init函數可以將這些函數指針初始化。然後所有含有這個類數據結構指針的對象,都可以調用這些函數。 — 共性東西拿出來搞成Class,泛化

對象的數據結構一般包含了大量變量,是對象的一些屬性,很明顯這些是每個實例特有的,各自不盡相同。instance對應的init函數可以把這些屬性初始化,相當於C++中的構造函數。 — 特化的東西構成實例

初始化相關:

已virtio-net-pci爲例:

  1. type_init(virtio_net_pci_register) -> register_module_init : 會將virtio_net_pci_register放到全局二維數組中init_type_list,數組成員爲ModuleEntry類型,內部有init函數指針,virtio_net_pci_register會賦值給init

  2. main() -> module_call_init(MODULE_INIT_QOM) : 會遍歷init_type_list[MODULE_INIT_QOM]中的所有元素,並調用init]
    -> virtio_net_pci_register -> type_register -> type_register_internal -> type_table_add [通過該調用鏈,對應TypeImpl結構被加入到全局hash表中

  3. main -> select_machine -> object_class_get_list -> object_class_foreach ->object_class_get_list_tramp -> type_initialize

    static void type_initialize(TypeImpl *ti)
    {
    	....
        if (ti->class) { /* 非空,已經初始化過,直接退出 */
            return;
        }
        ...
         if (parent) {
            type_initialize(parent); /* 遞歸調用,回溯到根節點 */
            ...
            memcpy(ti->class,parent->class,parent->class_size);/* 複製父節點的class結構體,繼承的實現本質 */
            ... 
         }
        ...
        if (ti->class_init) {
            ti->class_init(ti->class, ti->class_data); /* 類初始化函數 */
        }
    }
    

    【TypeImpl是一種輔助數據結構,類的創建以及初始化會基於該結構體】

  4. main -> qemu_opts_foreach -> device_init_func -> device_init_func -> qdev_device_add -> object_new : 該調用鏈會遍歷全局保存的QemuOptsList數組(vm_config_groups),找到類型爲device的單元,例如對應下面的命令行選項:

    -netdev tap,id=hostnet0,ifname=vnet2,downscript=no
    -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:6b:0d:a1,bus=pci.0,addr=0x3
    
    DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
    {	
    	DeviceClass *dc;
        const char *driver, *path;
        DeviceState *dev;
        BusState *bus = NULL;
        ...
     	driver = qemu_opt_get(opts, "driver"); /* 此處對應virtio-net-pci */
        ...
        dc = qdev_get_device_class(&driver, errp);
        ...
        path = qemu_opt_get(opts, "bus"); /* 尋找對應總線路徑,此處對應pci.0 */
        if (path != NULL) {
            bus = qbus_find(path, errp); /* 根據path尋找對應的bus實例 */
            if (!bus) {
                return NULL;
            }
            if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
                error_setg(errp, "Device '%s' can't go on %s bus",
                           driver, object_get_typename(OBJECT(bus)));
                return NULL;
            } /* 總線不匹配 */
        }
        ...
        dev = DEVICE(object_new(driver));  /* 創建設備實例 */
        if (bus) {
            qdev_set_parent_bus(dev, bus); /* 設備與總線關聯 */
        }
        ...
        if (qemu_opt_foreach(opts, set_property, dev, &err)) {
            goto err_del_dev;
        } /* 根據opts設置屬性,上例會設置的屬性有:netdev、mac、addr */
         /* 對於netdev屬性,後面會調用set_netdev函數,使得device和netdev發生關聯,前面已經具體介紹過 */
    	dev->opts = opts;
        object_property_set_bool(OBJECT(dev), true, "realized", &err); /* 觸發realize回調 */
    }
    

    object_new -> object_new_with_type -> object_initialize_with_type -> object_initialize_with_type -> object_init_with_type

    static void object_init_with_type(Object *obj, TypeImpl *ti)
    {
        if (type_has_parent(ti)) {
            object_init_with_type(obj, type_get_parent(ti));/* 回溯到根節點,遞歸調用 */
        }
        if (ti->instance_init) {
            ti->instance_init(obj); /* 實例初始化函數 */
        }
    }
    
  5. 另外關注一下DeviceClass這個結構體,其中有個realize回調,設備的許多初始化操作是在這個函數中進行的。

    typedef struct DeviceClass {
        /*< private >*/
        ObjectClass parent_class;
        /*< public >*/
        DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
        const char *fw_name;
        const char *desc;
        Property *props;
        bool user_creatable;
        bool hotpluggable;
        /* callbacks */
        DeviceReset reset;
        DeviceRealize realize; /* 更具體的初始化操作 */
        DeviceUnrealize unrealize;
        /* device state */
        const struct VMStateDescription *vmsd;
        /* Private to qdev / bus.  */
        const char *bus_type;
    };
    

    以virtio_net_device_realize爲例:

    main -> qemu_opts_foreach -> device_init_func -> qdev_device_add -> object_property_set_bool -> property_set_bool -> device_set_realized -> pci_qdev_realize -> virtio_pci_realize -> object_property_set_qobject -> property_set_bool -> device_set_realized -> virtio_net_device_realize

​ realize這個屬性是在object_init_with_type回溯到DeciceClass節點調用對應的instance_init實現的,對應的函數爲:

static void device_initfn(Object *obj)
{
 	....
	object_property_add_bool(obj, "realized",
                         device_get_realized, device_set_realized, NULL);
	....
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章