zoukankan      html  css  js  c++  java
  • QEMU VCPU热插特性

    最近学习QEMU中VCPU热插特性,需要了解QEMU中VCPU热插的整个流程,VCPU热插是QEMU主板的一个feature。

    1:这里先分析一下QEMU的主板模拟,主板在QEMU的设备模型中对应的是一个MachineClass的结构体,其内容如下:

    struct MachineClass {
        /*< private >*/
        ObjectClass parent_class;
        /*< public >*/
    
        const char *family; /* NULL iff @name identifies a standalone machtype */
        const char *name;
        const char *alias;
        const char *desc;
    
        void (*init)(MachineState *state);            /* 主板的初始化入口函数 */
        void (*reset)(void);
        void (*hot_add_cpu)(const int64_t id, Error **errp);  /* VCPU 热插的调用入口 */
        int (*kvm_type)(const char *arg);
    
        BlockInterfaceType block_default_type;
        int units_per_default_bus;
        int max_cpus;
        unsigned int no_serial:1,
            no_parallel:1,
            use_virtcon:1,
            use_sclp:1,
            no_floppy:1,
            no_cdrom:1,
            no_sdcard:1,
            has_dynamic_sysbus:1,
            pci_allow_0_address:1,
            legacy_fw_cfg_order:1;
        int is_default;
        const char *default_machine_opts;
        const char *default_boot_order;
        const char *default_display;
        GlobalProperty *compat_props;
        const char *hw_version;
        ram_addr_t default_ram_size;
        bool option_rom_has_mr;
        bool rom_file_has_mr;
    
        HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
                                               DeviceState *dev);
        unsigned (*cpu_index_to_socket_id)(unsigned cpu_index);
        CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
    };
    

       在qemu源码vl.c中,做完参数解析之后调用select_machine()获取默认的主板。

    static MachineClass *select_machine(void)
    {
        MachineClass *machine_class = find_default_machine();    /* 寻找默认的主板(qemu有一个支持的主板列表) */
        const char *optarg;
        QemuOpts *opts;
        Location loc;
    
        loc_push_none(&loc);
    
        opts = qemu_get_machine_opts();
        qemu_opts_loc_restore(opts);
    
        optarg = qemu_opt_get(opts, "type");
        if (optarg) {
            machine_class = machine_parse(optarg);              /* 解析命令行传入的machine类型,如果命令行传入的machine解析错误,使用默认的主板类型 */
        }
    
        if (!machine_class) {
            error_report("No machine specified, and there is no default");
            error_printf("Use -machine help to list supported machines
    ");
            exit(1);
        }
    
        loc_pop(&loc);
        return machine_class;
    }
    

      不管是find_default_machine还是machine_parse中,都有一个函数叫做 object_class_get_list(),这个函数的作用查找实现了某个Class的object列表,下面对其进行分析。

    MachineClass *find_default_machine(void)
    {
        GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);    /* 查找 machine 对象的列表 */
        MachineClass *mc = NULL;
    
        for (el = machines; el; el = el->next) {                               /* 遍历列表,找到is_default=true的object对象 */                          
            MachineClass *temp = el->data;
    
            if (temp->is_default) {
                mc = temp;
                break;
            }
        }
    
        g_slist_free(machines);
        return mc;
    }
    

      重点分析object_class_get_list,其入参是指向字符串"machine"的指针 和 false (不查找抽象类的实例)。

    GSList *object_class_get_list(const char *implements_type,
                                  bool include_abstract)
    {
        GSList *list = NULL;
       
        object_class_foreach(object_class_get_list_tramp,                   
                             implements_type, include_abstract, &list);        /* 调用了object_class_foreach方法, 第一个入参是一个函数指针object_class_get_list_tramp,最后一个参数是一个GList指针(默认为NULL)*/
        return list; 
    }

       函数object_class_get_list_tramp的作用是将ObjectClass对象指针klass添加到list当中,并将list的头指针放到opaque里面。用来实现将找到的ObjectClass对象指针串起来。

    static void object_class_get_list_tramp(ObjectClass *klass, void *opaque)
    {
        GSList **list = opaque;
    
        *list = g_slist_prepend(*list, klass);    /* add a new element to the start of the list */
    }

      下面是object_class_foreach的实现。

    typedef struct OCFData
    {
        void (*fn)(ObjectClass *klass, void *opaque);
        const char *implements_type;
        bool include_abstract;
        void *opaque;
    } OCFData;
    
    static void object_class_foreach_tramp(gpointer key, gpointer value,
                                           gpointer opaque)
    {
        OCFData *data = opaque;
        TypeImpl *type = value;
        ObjectClass *k;
    
        type_initialize(type);
        k = type->class;
    
        if (!data->include_abstract && type->abstract) {    /* 抽象类不是查对象 */
            return;
        }
    
        if (data->implements_type &&                        /* 不能动态cast的类对象也不考虑 */
            !object_class_dynamic_cast(k, data->implements_type)) {
            return;
        }
    
        data->fn(k, data->opaque);                          /* 调用object_class_get_list_tramp */
    }
    
    void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
                              const char *implements_type, bool include_abstract,
                              void *opaque)
    {
        OCFData data = { fn, implements_type, include_abstract, opaque };
    
        enumerating_types = true;
        g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
        enumerating_types = false;
    }
    
    
  • 相关阅读:
    MySQL主主同步方案
    Mysql增量备份与恢复
    配置合适的存储引擎
    基于Amoeba读写分离
    部署myaql主从异步复制
    MySQL完全备份操作
    echo 命令详解
    ELK 基本部署
    zabbix 简介
    基于 Git Tag 发布及回滚代码
  • 原文地址:https://www.cnblogs.com/fangying7/p/6001667.html
Copyright © 2011-2022 走看看