【QEMU系统分析之实例篇(十七)】

系列文章目录

第十七章 QEMU系统仿真的机器创建分析实例


文章目录

  • 系列文章目录
    • 第十七章 QEMU系统仿真的机器创建分析实例
  • 前言
  • 一、QEMU是什么?
  • 二、QEMU系统仿真的机器创建分析实例
    • 1.系统仿真的命令行参数
    • 2.配置加速器
      • configure_accelerators()
        • do_configure_icount()
        • 设置加速器顺序
        • do_configure_accelerator()
    • 3.调试输出
  • 总结


前言

本文以 QEMU 8.2.2 为例,分析其作为系统仿真工具的工作过程,并为读者展示各种 QEMU 系统仿真的启动配置实例。
本文读者需要具备一定的 QEMU 系统仿真使用经验,并对 C 语言编程有一定了解。


一、QEMU是什么?

QEMU 是一个通用且开源的机器模拟器和虚拟机。
其官方主页是:https://www.qemu.org/


二、QEMU系统仿真的机器创建分析实例

1.系统仿真的命令行参数

QEMU 作为系统仿真工具,其入口代码在 system/main.c 文件中,初始化函数 qemu_init() 的实现在 system/vl.c 文件中。
前文完成创建目标机器的过程分析,本文将继续后续运行过程的分析,读者需要对 QEMU 系统启动过程的程序代码有所了解,相关内容可以参考《QEMU系统分析之启动篇》系列文章。

..\qemu\8.2.2-qkd\qemu-system-x86_64.exe -cpu "Penryn" -M  "q35,accel=whpx,smm=off" -m "6G" -display "sdl" -audio "sdl,model=hda" -vga "std" -L "data"

2.配置加速器

这部分代码在 system/vl.c 文件中,实现如下:

int qemu_init(int argc, char **argv)
{
...configure_accelerators(argv[0]);
...
}

前文分析了应用当前机器设置项的过程,本文继续完成加速器的配置过程。


configure_accelerators()

函数 configure_accelerators() 代码如下:

static void configure_accelerators(const char *progname)
{bool init_failed = false;qemu_opts_foreach(qemu_find_opts("icount"),do_configure_icount, NULL, &error_fatal);if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {char **accel_list, **tmp;if (accelerators == NULL) {/* Select the default accelerator */bool have_tcg = accel_find("tcg");bool have_kvm = accel_find("kvm");if (have_tcg && have_kvm) {if (g_str_has_suffix(progname, "kvm")) {/* If the program name ends with "kvm", we prefer KVM */accelerators = "kvm:tcg";} else {accelerators = "tcg:kvm";}} else if (have_kvm) {accelerators = "kvm";} else if (have_tcg) {accelerators = "tcg";} else {error_report("No accelerator selected and"" no default accelerator available");exit(1);}}accel_list = g_strsplit(accelerators, ":", 0);for (tmp = accel_list; *tmp; tmp++) {/** Filter invalid accelerators here, to prevent obscenities* such as "-machine accel=tcg,,thread=single".*/if (accel_find(*tmp)) {qemu_opts_parse_noisily(qemu_find_opts("accel"), *tmp, true);} else {init_failed = true;error_report("invalid accelerator %s", *tmp);}}g_strfreev(accel_list);} else {if (accelerators != NULL) {error_report("The -accel and \"-machine accel=\" options are incompatible");exit(1);}}if (!qemu_opts_foreach(qemu_find_opts("accel"),do_configure_accelerator, &init_failed, &error_fatal)) {if (!init_failed) {error_report("no accelerator found");}exit(1);}if (init_failed && !qtest_chrdev) {error_report("falling back to %s", current_accel_name());}if (icount_enabled() && !tcg_enabled()) {error_report("-icount is not allowed with hardware virtualization");exit(1);}
}

首先,如果命令行参数中有 “icount” 则调用函数 do_configure_icount() 做配置。


do_configure_icount()

代码如下:

void icount_configure(QemuOpts *opts, Error **errp)
{const char *option = qemu_opt_get(opts, "shift");bool sleep = qemu_opt_get_bool(opts, "sleep", true);bool align = qemu_opt_get_bool(opts, "align", false);long time_shift = -1;if (!option) {if (qemu_opt_get(opts, "align") != NULL) {error_setg(errp, "Please specify shift option when using align");}return;}if (align && !sleep) {error_setg(errp, "align=on and sleep=off are incompatible");return;}if (strcmp(option, "auto") != 0) {if (qemu_strtol(option, NULL, 0, &time_shift) < 0|| time_shift < 0 || time_shift > MAX_ICOUNT_SHIFT) {error_setg(errp, "icount: Invalid shift value");return;}} else if (icount_align_option) {error_setg(errp, "shift=auto and align=on are incompatible");return;} else if (!icount_sleep) {error_setg(errp, "shift=auto and sleep=off are incompatible");return;}icount_sleep = sleep;if (icount_sleep) {timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,icount_timer_cb, NULL);}icount_align_option = align;if (time_shift >= 0) {timers_state.icount_time_shift = time_shift;icount_enable_precise();return;}icount_enable_adaptive();/** 125MIPS seems a reasonable initial guess at the guest speed.* It will be corrected fairly quickly anyway.*/timers_state.icount_time_shift = 3;/** Have both realtime and virtual time triggers for speed adjustment.* The realtime trigger catches emulated time passing too slowly,* the virtual time trigger catches emulated time passing too fast.* Realtime triggers occur even when idle, so use them less frequently* than VM triggers.*/timers_state.vm_clock_warp_start = -1;timers_state.icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT,icount_adjust_rt, NULL);timer_mod(timers_state.icount_rt_timer,qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000);timers_state.icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,icount_adjust_vm, NULL);timer_mod(timers_state.icount_vm_timer,qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +NANOSECONDS_PER_SECOND / 10);
}static int do_configure_icount(void *opaque, QemuOpts *opts, Error **errp)
{icount_configure(opts, errp);return 0;
}

设置加速器顺序

代码如下:

static void configure_accelerators(const char *progname)
{
...if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {char **accel_list, **tmp;if (accelerators == NULL) {/* Select the default accelerator */bool have_tcg = accel_find("tcg");bool have_kvm = accel_find("kvm");if (have_tcg && have_kvm) {if (g_str_has_suffix(progname, "kvm")) {/* If the program name ends with "kvm", we prefer KVM */accelerators = "kvm:tcg";} else {accelerators = "tcg:kvm";}} else if (have_kvm) {accelerators = "kvm";} else if (have_tcg) {accelerators = "tcg";} else {error_report("No accelerator selected and"" no default accelerator available");exit(1);}}accel_list = g_strsplit(accelerators, ":", 0);for (tmp = accel_list; *tmp; tmp++) {/** Filter invalid accelerators here, to prevent obscenities* such as "-machine accel=tcg,,thread=single".*/if (accel_find(*tmp)) {qemu_opts_parse_noisily(qemu_find_opts("accel"), *tmp, true);} else {init_failed = true;error_report("invalid accelerator %s", *tmp);}}g_strfreev(accel_list);} else {if (accelerators != NULL) {error_report("The -accel and \"-machine accel=\" options are incompatible");exit(1);}}
...
}

如果程序名后缀是 kvm 则设置 KVM 加速器优先,设置完加速器顺序后完成加速器的配置。
加速器配置通过函数 do_configure_accelerator() 来完成。


do_configure_accelerator()

代码如下:

static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp)
{bool *p_init_failed = opaque;const char *acc = qemu_opt_get(opts, "accel");AccelClass *ac = accel_find(acc);AccelState *accel;int ret;bool qtest_with_kvm;if (!acc) {error_setg(errp, QERR_MISSING_PARAMETER, "accel");goto bad;}qtest_with_kvm = g_str_equal(acc, "kvm") && qtest_chrdev != NULL;if (!ac) {if (!qtest_with_kvm) {error_report("invalid accelerator %s", acc);}goto bad;}accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac)));object_apply_compat_props(OBJECT(accel));qemu_opt_foreach(opts, accelerator_set_property,accel,&error_fatal);/** If legacy -singlestep option is set, honour it for TCG and* silently ignore for any other accelerator (which is how this* option has always behaved).*/if (opt_one_insn_per_tb) {/** This will always succeed for TCG, and we want to ignore* the error from trying to set a nonexistent property* on any other accelerator.*/object_property_set_bool(OBJECT(accel), "one-insn-per-tb", true, NULL);}ret = accel_init_machine(accel, current_machine);if (ret < 0) {if (!qtest_with_kvm || ret != -ENOENT) {error_report("failed to initialize %s: %s", acc, strerror(-ret));}goto bad;}return 1;bad:*p_init_failed = true;return 0;
}

3.调试输出

首先,添加跟踪调试信息,修改后的代码如下:

static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp)
{
...accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac)));HUEDBG("accel=0x%llx\n", (unsigned long long int)accel);huedbg_dump_AccelClass(ac, 9);
...
}static void configure_accelerators(const char *progname)
{
...HUEDBG("accelerators=[%s]\n", accelerators);accel_list = g_strsplit(accelerators, ":", 0);
...
}int accel_init_machine(AccelState *accel, MachineState *ms)
{AccelClass *acc = ACCEL_GET_CLASS(accel);int ret;HUEDBG("accel=0x%llx\n", (unsigned long long int)accel);ms->accelerator = accel;*(acc->allowed) = true;ret = acc->init_machine(ms);if (ret < 0) {HUEDBG("\n");ms->accelerator = NULL;*(acc->allowed) = false;object_unref(OBJECT(accel));} else {HUEDBG("\n");object_set_accelerator_compat_props(acc->compat_props);}huedbg_dump_AccelClass(acc, 9);return ret;
}int qemu_init(int argc, char **argv)
{
.../** Note: uses machine properties such as kernel-irqchip, must run* after qemu_apply_machine_options.*/huedbg_flag = 1;HUEDBG("\n");configure_accelerators(argv[0]);HUEDBG("\n");huedbg_flag = 0;phase_advance(PHASE_ACCEL_CREATED);
...
}

运行后,输出信息如下:

[21096]../system/vl.c/qemu_init(2849):
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(183):<<<deep>>>=[9] list=[00007ff7ee3825c0]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(185):name=[drive]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(186):implied_opt_name=[(null)]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(187):merge_lists=[0]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(188):head=[00007ff7ee3825d8]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptsList(192):desc=[00007ff7ee3825e8]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptDesc(160):<<<deep>>>=[8] desc=[00007ff7ee3825e8]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptDesc(162):name=[(null)]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptDesc(163):type=[0]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptType(116):<<<deep>>>=[7] idx=[0]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptType(127):[0]=QEMU_OPT_STRING
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptDesc(167):help=[(null)]
[21096]../util/huedbg-option.c/huedbg_dump_QemuOptDesc(168):def_value_str=[(null)]
[21096]../system/vl.c/qemu_init(2851):
[21096]../system/vl.c/qemu_init(3824):
[21096]../system/vl.c/configure_accelerators(2419):accelerators=[whpx]
[21096]../qom/object.c/object_class_by_name(1095):enter
[21096]../qom/object.c/type_table_lookup(103):lookup type(whpx-accel) in hash table
[21096]../qom/object.c/object_class_by_name(1105):class(whpx-accel) return
[21096]../qom/object.c/type_table_lookup(103):lookup type(accel) in hash table
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../qom/object.c/object_class_by_name(1095):enter
[21096]../qom/object.c/type_table_lookup(103):lookup type(whpx-accel) in hash table
[21096]../qom/object.c/object_class_by_name(1105):class(whpx-accel) return
[21096]../qom/object.c/object_new_with_class(818):klass->type->name=[whpx-accel]
[21096]../qom/object.c/object_new_with_type(789):try type_initialize(whpx-accel)
[21096]../qom/object.c/object_new_with_type(799):obj(whpx-accel) alloc
[21096]../qom/object.c/object_new_with_type(808):try object_initialize_with_type(whpx-accel)
[21096]../qom/object.c/object_initialize_with_type(568):obj with type(whpx-accel) enter
[21096]../qom/object.c/object_initialize_with_type(576):mapping obj(whpx-accel).class with type(whpx-accel).class
[21096]../qom/object.c/object_initialize_with_type(579):try object_class_property_init_all(whpx-accel)
[21096]../qom/object.c/object_class_property_init_all(552):obj(whpx-accel) enter
[21096]../qom/object.c/object_class_property_iter_init(1440):objclass{whpx-accel} enter
[21096]../qom/object.c/object_class_get_parent(1130):enter
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../qom/object.c/object_class_get_parent(1138):objclass(whpx-accel) has parent(accel)
[21096]../qom/object.c/object_class_get_parent(1141):objclass(whpx-accel) return
[21096]../qom/object.c/object_class_property_iter_init(1443):objclass{whpx-accel} return
[21096]../qom/object.c/object_class_property_init_all(555):prop name=[kernel-irqchip] type=[on|off|split] desc=[Configure WHPX in-kernel irqchip] init=[0000000000000000]
[21096]../qom/object.c/object_class_get_parent(1130):enter
[21096]../qom/object.c/type_get_parent(194):parent_type(object)
[21096]../qom/object.c/object_class_get_parent(1138):objclass(accel) has parent(object)
[21096]../qom/object.c/object_class_get_parent(1141):objclass(accel) return
[21096]../qom/object.c/object_class_get_parent(1130):enter
[21096]../qom/object.c/type_get_parent(196):no parent_type
[21096]../qom/object.c/object_class_get_parent(1134):objclass(object) has no parent return
[21096]../qom/object.c/object_class_property_init_all(555):prop name=[type] type=[string] desc=[(null)] init=[0000000000000000]
[21096]../qom/object.c/object_class_property_init_all(563):obj(whpx-accel) return
[21096]../qom/object.c/object_initialize_with_type(583):try object_init_with_type(whpx-accel)
[21096]../qom/object.c/object_init_with_type(416):obj->class->type->name=[whpx-accel] ti->name=[whpx-accel] enter
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../qom/object.c/object_init_with_type(416):obj->class->type->name=[whpx-accel] ti->name=[accel] enter
[21096]../qom/object.c/type_get_parent(194):parent_type(object)
[21096]../qom/object.c/object_init_with_type(416):obj->class->type->name=[whpx-accel] ti->name=[object] enter
[21096]../qom/object.c/object_init_with_type(427):obj->class->type->name=[whpx-accel] ti->name=[object] return
[21096]../qom/object.c/object_init_with_type(427):obj->class->type->name=[whpx-accel] ti->name=[accel] return
[21096]../qom/object.c/object_init_with_type(423):name=[whpx-accel] ti->instance_init() before
[21096]../qom/object.c/object_init_with_type(425):name=[whpx-accel] ti->instance_init() after
[21096]../qom/object.c/object_init_with_type(427):obj->class->type->name=[whpx-accel] ti->name=[whpx-accel] return
[21096]../qom/object.c/object_initialize_with_type(585):try object_post_init_with_type(whpx-accel)
[21096]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[whpx-accel] ti->name=[whpx-accel] enter
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[whpx-accel] ti->name=[accel] enter
[21096]../qom/object.c/type_get_parent(194):parent_type(object)
[21096]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[whpx-accel] ti->name=[object] enter
[21096]../qom/object.c/object_post_init_with_type(444):return
[21096]../qom/object.c/object_post_init_with_type(444):return
[21096]../qom/object.c/object_post_init_with_type(444):return
[21096]../qom/object.c/object_initialize_with_type(587):obj(whpx-accel) return
[21096]../qom/object.c/object_new_with_type(812):obj(whpx-accel) return
[21096]../qom/object.c/type_table_lookup(103):lookup type(accel) in hash table
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../system/vl.c/do_configure_accelerator(2353):accel=0x1dc0cf9d320
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(76):<<<deep>>>=[9] ac=[000001dc0cf6d2e0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(79):name=[WHPX]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(80):init_machine=[00007ff7edfa3d60]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(82):setup_post=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(83):has_memory=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(85):cpu_common_realize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(86):cpu_common_unrealize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(88):gdbstub_supported_sstep_flags=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(89):allowed=[00007ff7eefb19e9]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(91):*allowed=[0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(93):compat_props=[0000000000000000]
[21096]../qom/object.c/type_table_lookup(103):lookup type(accel) in hash table
[21096]../qom/object.c/type_get_parent(194):parent_type(accel)
[21096]../accel/accel-system.c/accel_init_machine(40):accel=0x1dc0cf9d320
[21096]../qom/object.c/type_table_lookup(103):lookup type(machine) in hash table
[21096]../qom/object.c/type_get_parent(194):parent_type(object)
[21096]../qom/object.c/type_get_parent(196):no parent_type
[21096]../qom/object.c/type_get_parent(194):parent_type(generic-pc-machine)
[21096]../qom/object.c/type_get_parent(194):parent_type(x86-machine)
[21096]../qom/object.c/type_get_parent(194):parent_type(machine)
[21096]../target/i386/whpx/whpx-all.c/whpx_accel_init_machine(2778):mc=0x1dc0cf8b9f0,s=0x1dc0cf9d320,whpx=0x7ff7eefb1980
WHPX: setting APIC emulation mode in the hypervisor
Windows Hypervisor Platform accelerator is operational
[21096]../accel/accel-system.c/accel_init_machine(50):
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(76):<<<deep>>>=[9] ac=[000001dc0cf6d2e0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(79):name=[WHPX]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(80):init_machine=[00007ff7edfa3d60]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(82):setup_post=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(83):has_memory=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(85):cpu_common_realize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(86):cpu_common_unrealize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(88):gdbstub_supported_sstep_flags=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(89):allowed=[00007ff7eefb19e9]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(91):*allowed=[1]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(93):compat_props=[0000000000000000]
[21096]../system/vl.c/qemu_init(3826):

注意 AccelClass 信息变化如下:

...
[21096]../system/vl.c/do_configure_accelerator(2353):accel=0x1dc0cf9d320
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(76):<<<deep>>>=[9] ac=[000001dc0cf6d2e0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(79):name=[WHPX]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(80):init_machine=[00007ff7edfa3d60]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(82):setup_post=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(83):has_memory=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(85):cpu_common_realize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(86):cpu_common_unrealize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(88):gdbstub_supported_sstep_flags=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(89):allowed=[00007ff7eefb19e9]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(91):*allowed=[0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(93):compat_props=[0000000000000000]
...
[21096]../accel/accel-system.c/accel_init_machine(50):
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(76):<<<deep>>>=[9] ac=[000001dc0cf6d2e0]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(79):name=[WHPX]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(80):init_machine=[00007ff7edfa3d60]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(82):setup_post=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(83):has_memory=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(85):cpu_common_realize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(86):cpu_common_unrealize=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(88):gdbstub_supported_sstep_flags=[0000000000000000]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(89):allowed=[00007ff7eefb19e9]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(91):*allowed=[1]
[21096]../util/huedbg-accel.c/huedbg_dump_AccelClass(93):compat_props=[0000000000000000]
[21096]../system/vl.c/qemu_init(3826):

未调用 accel_init_machine() 前 *allowed = 0,调用后 *allowed = 1


总结

以上分析了系统初始化过程中加速器的配置过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯13届JAVA A组 国赛

​​​​​​​ package 蓝桥杯国赛; // 贪心选个数最少的进行摆 // 2:1 ,3:1, 4:1,5 : 3,6:3,7:1 // 选 1&#xff0c;7&#xff0c;4&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;9 // 然后都选满10个 public class 火彩棒数字 {public static void main(String[] a…

【CTFHub】HTTP 请求方式 302跳转 cookie WP

1.请求方式 打开给出的URL进入一个页面&#xff0c;提示原方法是GET&#xff0c;用CTFHUB方法就能获得flag 思路&#xff1a;抓包&#xff0c;将GET方法改成CTFHUB方法进行重新发送请求&#xff0c;查看响应情况 1.打开代理服务器 2.打开BurpSuite 刷新页面获得拦截 3.发送…

【Excel VBA】深入理解 VBA 中的 CallByName 函数

动态调用方法与属性&#xff1a;深入理解 VBA 中的 CallByName 函数 昨天在介绍Choose函数在复杂的VBA应用程序开发中&#xff0c;有时我们需要根据运行时的情况来决定调用哪个对象的哪个方法或属性。这种灵活性可以通过 CallByName 函数实现。在本篇博客中&#xff0c;田辛老…

网络Http和Socket通讯(基于面试)

每日一句&#xff1a;想得到世上最好的东西&#xff0c;先得让世界看到最好的你 目录 面试问OSI或TCP/IP,怎么回答&#xff1f; 面试问HTTP&#xff1f; 面试问Get类型&#xff0c;Pot类型区别&#xff1f; 面试什么是Socket套接字&#xff1f; 面试问什么是数据粘包&…

qt for android 的架构原理

qt for android实现架构&#xff0c;分享这几幅很不错图。来自于 《Qt 林斌&#xff1a;整合Android IVI平台打造统一的Qt数字座舱体验》 1.实现架构图 2.qt for android能力 3.java 和 qt混合开发 4. AutoMotive

46寸硅片为什么要留平边(flat)?

知 识星球&#xff08;星球名&#xff1a; 芯片制造与封测社区&#xff0c;星球号&#xff1a; 63559049&#xff09;里的学员问&#xff1a; 2&#xff0c; 4&#xff0c; 6寸硅片都有 平 边&#xff0c;它们有什么作用 &#xff1f; 硅片的平边&#xff08;Flat&…

经典权限五张表案例分析

文章目录 模块分析模块分析 描述五张表的关系重要知识讲解抽取成一个BaseServletSpringIOC思想(底层)实现代码IOC概述 SPI机制(为学习框架做思想和技术铺垫)SPI引入1. 标准/规范2. 具体的实现3. 调用 SPI介绍SPI练习JDBC4.0免注册驱动原理Servlet实现方式三 ServletContainerIn…

idea使用前的全局配置,一次配置,多次使用

前提&#xff1a;每次导入一个新的项目&#xff0c;就需要重新设置编码、maven、jdk、git版本等信息。实际每个项目所用到的配置信息是一致的&#xff0c;除非换一家公司&#xff0c;不然不会改动到这些内容。 idea版本&#xff1a;2024.1.1 1.1、全局Maven配置 IDEA启动页面…

微火一文盘点:为何全域运营系统会成为创业新风口?

当前&#xff0c;微火全域运营已经成为创业的新风口&#xff0c;想要做微火全域运营服务商的创业者数量日益增多。据目前了解到的最新消息&#xff0c;微火全域运营系统的市场占有率已经超过了48%&#xff0c;并且还在持续不断地上涨中。 所谓微火全域运营系统&#xff0c;就是…

InLine Chat功能优化对标Github Copilot,CodeGeeX带来更高效、更直观的编程体验!

VSCode中的CodeGeeX 插件上线InLine Chat功能后&#xff0c;收到不少用户的反馈&#xff0c;大家对行内交互编程这一功能非常感兴趣。近期我们针对这个功能再次进行了深度优化&#xff0c;今天详细介绍已经在VSCode插件v2.8.0版本上线的 CodeGeeX InLine Chat功能&#xff0c;以…

蓝桥杯成绩已出

蓝桥杯的成绩早就已经出来了&#xff0c;虽然没有十分惊艳 &#xff0c;但是对于最终的结果我是心满意足的&#xff0c;感谢各位的陪伴&#xff0c;关于蓝桥杯的刷题笔记我已经坚持更新了49篇&#xff0c;但是现在即将会告别一段落&#xff0c;人生即将进入下一个规划。我们一起…

Spring框架学习笔记(一):Spring基本介绍(包含IOC容器底层结构)

1 官方资料 1.1 官网 https://spring.io/ 1.2 进入 Spring5 下拉 projects, 进入 Spring Framework 进入 Spring5 的 github 1.3 在maven项目中导入依赖 <dependencies><!--加入spring开发的基本包--><dependency><groupId>org.springframework<…

jni 返回二维byte数组

在JNI中返回二维byte数组&#xff0c;你需要在Java中准备一个相应的二维数组来接收这个返回值。在JNI层面&#xff0c;你可以创建一个二维的byte数组&#xff0c;并使用GetByteArrayRegion和SetByteArrayRegion来操作它。 以下是一个简单的例子&#xff1a; public class Jni…

基于STC12C5A60S2系列1T 8051单片机实现一主单片机与一从单片机进行双向串口通信功能

基于STC12C5A60S2系列1T 8051单片机实现一主单片机与一从单片机进行双向串口通信功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串口通信的特殊功能寄存器…

QT---day5,通信

1、思维导图 2、TCp 服务器 #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include <QTcpServer> #include <QList> #include <QTcpSocket> #include <QMessageBox> #include <QDebug> #include <QTcpServer> QT_B…

镭速实现利用Libarchive实现高效、智能的文件传输和管理

在前一篇报道中&#xff0c;我们阐述了Libarchive这一开源库的强大功能&#xff0c;它专门用于处理归档文件。通过整合Libarchive&#xff0c;镭速在包括Windows和Linux在内的多个操作系统上提供了在线解压缩服务&#xff0c;为企业构建了一个既强大又安全的文件传输系统&#…

【代码分享】使用HTML5的Canvas绘制编码说明图片

最急在工作中遇到一个需求&#xff0c;根据给定的编码生成编码说明&#xff0c;像下面这样的效果。 不同含义的编码用横杠分割&#xff0c;然后每个编码下面用箭头指明具体的含义。下面是我使用canvas实现的代码。具体的编码宽度大家可以根据实际情况进行调整&#xff0c;目前…

Ranger 面试题及答案整理,最新面试题

Ranger 的安全模型是如何设计的&#xff1f; Ranger的安全模型设计主要基于访问控制和安全策略的管理&#xff0c;它通过以下几个关键组件实现&#xff1a; 1、策略管理&#xff1a; Ranger 提供了一个中央管理平台&#xff0c;用于定义、更新和管理安全策略。这些策略根据资…

基于RT-Thread的HC-SR04超声波驱动

前言 本次驱动用的是这款超声波&#xff0c;超声波的驱动大同小异&#xff0c;均可参考 一、引脚定义 引脚功能VCC接直流5V电TRIG接外部电路的TRIG端&#xff0c;向此引脚输入10us以上的高电平可触发超声波测距ECHO接外部电路的ECHO端&#xff0c;测距结束时该引脚会输出一…