<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>jjl9807</title>
    <link rel="self" type="application/atom+xml" href="https://jjl9807.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://jjl9807.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-08-07T00:00:00+00:00</updated>
    <id>https://jjl9807.com/atom.xml</id>
    <entry xml:lang="en">
        <title>bark-apns</title>
        <published>2026-08-07T00:00:00+00:00</published>
        <updated>2026-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/projects/bark-apns/"/>
        <id>https://jjl9807.com/projects/bark-apns/</id>
        
        <content type="html" xml:base="https://jjl9807.com/projects/bark-apns/"></content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buckal - Seamlessly Scaling Rust Builds</title>
        <published>2026-02-25T00:00:00+00:00</published>
        <updated>2026-02-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/cargo-buckal/"/>
        <id>https://jjl9807.com/posts/cargo-buckal/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/cargo-buckal/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/cargo-buckal/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction&quot; aria-label=&quot;Anchor link for: introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cargo is the standard build tool for Rust, offering simplicity and ease of use for small to medium-sized projects. However, its monolithic build model struggles at scale—particularly in large monorepos where distributed caching, fine-grained parallelism, and cross-language integration are critical.&lt;/p&gt;
&lt;p&gt;To address Cargo&#39;s limitations in building complex projects, we conducted a comprehensive survey of mainstream large-scale build systems, including Bazel, GN, and Buck2. We evaluated each solution based on criteria such as performance, scalability, and specifically the depth of support for the Rust language. After careful comparison, Buck2 emerged as the optimal choice due to its robust architecture and growing ecosystem compatibility.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://buck2.build&quot;&gt;Buck2&lt;/a&gt;, a next-generation build system developed in Rust and open-sourced by Meta, addresses these limitations with a globally optimized action graph, native support for remote execution, and unified multi-language builds. Yet adopting Buck2 traditionally requires significant overhead: writing Starlark rules, managing BUCK files, and understanding Buck2’s configuration model—barriers that deter many Rust teams.&lt;/p&gt;
&lt;p&gt;To bridge this gap, we developed &lt;strong&gt;Buckal&lt;/strong&gt; (also known as &lt;a rel=&quot;external&quot; href=&quot;https://github.com/buck2hub/cargo-buckal&quot;&gt;cargo-buckal&lt;/a&gt;), a Cargo external subcommand that brings seamless Buck2 integration to Rust projects. It automatically generates Buck2 build rules from &lt;code&gt;Cargo.toml&lt;/code&gt;, manages project setup, and provides a familiar cargo-like CLI experience—all without requiring developers to write or maintain &lt;code&gt;BUCK&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;In this article, we discuss the design and implementation of Buckal, its real-world impact in the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/rk8s-dev/rk8s&quot;&gt;rk8s&lt;/a&gt; project, and our vision for making high-performance, scalable builds accessible to the broader Rust ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;limitations-of-cargo-in-large-scale-projects&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#limitations-of-cargo-in-large-scale-projects&quot; aria-label=&quot;Anchor link for: limitations-of-cargo-in-large-scale-projects&quot;&gt;Limitations of Cargo in Large-Scale Projects&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While Cargo works well for standalone crates and small workspaces, it faces fundamental scalability challenges in large-scale development environments. Three key limitations stand out:&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Cargo lacks support for distributed builds&lt;/strong&gt;. Its local-only execution model prevents effective use of remote caching and remote execution, leading to redundant compilation across developers and CI pipelines. This results in longer wait times and higher resource costs.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;build parallelization is coarse-grained and often inefficient&lt;/strong&gt;. Although Cargo can compile multiple crates in parallel, its dependency model does not enable fine-grained task scheduling. As crate graphs grow more complex, CPU utilization drops and end-to-end build times increase disproportionately.&lt;/p&gt;
&lt;p&gt;Third, &lt;strong&gt;Cargo offers no native support for cross-language builds&lt;/strong&gt;. Teams combining Rust with C/C++, Python, or other languages must rely on external tools like Make or CMake, breaking toolchain consistency and increasing maintenance burden.&lt;/p&gt;
&lt;p&gt;These constraints make Cargo a bottleneck for teams building large, polyglot systems—where fast, reproducible, and composable builds are essential.&lt;/p&gt;
&lt;h2 id=&quot;how-buck2-solves-these-problems&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-buck2-solves-these-problems&quot; aria-label=&quot;Anchor link for: how-buck2-solves-these-problems&quot;&gt;How Buck2 Solves These Problems&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Buck2 addresses the scalability limitations of Cargo through three key architectural advantages.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Buck2 natively supports distributed caching and remote execution&lt;/strong&gt; via the Bazel spec of &lt;a rel=&quot;external&quot; href=&quot;https://bazel.build/remote/rbe&quot;&gt;Remote Build Execution&lt;/a&gt;. This enables build actions to be executed remotely on shared worker clusters, with results cached and reused across developers and CI systems. A key enabler of this capability is hermeticity—the principle that builds are isolated from ambient environment state. Buck2 achieves this by declaratively managing toolchains (e.g., rustc, linker) as first-class dependencies, rather than relying on globally installed tools. This ensures that the same input produces bit-for-bit identical outputs across different machines, making builds reproducible and cacheable by default.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;fine-grained parallelism is achieved through a global action graph powered by DICE&lt;/strong&gt; (Dynamic Incremental Computation Engine). Unlike Cargo’s crate-level scheduling, Buck2 breaks builds into individual compilation units, enabling optimal task distribution and incremental rebuilds with minimal rework.&lt;/p&gt;
&lt;p&gt;Third, &lt;strong&gt;Buck2 is inherently multi-language&lt;/strong&gt;. Built in Rust and extended via Starlark—a deterministic, immutable dialect of Python—it allows users to define custom rules for any language. It currently supports C++, Python, Java, Go, Rust, and more, enabling unified builds across polyglot codebases.&lt;/p&gt;
&lt;h2 id=&quot;the-adoption-challenges-of-buck2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-adoption-challenges-of-buck2&quot; aria-label=&quot;Anchor link for: the-adoption-challenges-of-buck2&quot;&gt;The Adoption Challenges of Buck2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite its technical advantages, adopting Buck2 in Rust projects introduces significant practical barriers.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Buck2’s documentation and Cargo compatibility are incomplete&lt;/strong&gt;. The built-in prelude provides essential rules like &lt;code&gt;rust_library&lt;/code&gt; and &lt;code&gt;rust_binary&lt;/code&gt;, but their parameters are poorly documented and often lack full compatibility with Cargo features (e.g., embedded environment variables, &lt;code&gt;cargo::&lt;/code&gt; instructions, or custom profiles). As a result, writing correct &lt;code&gt;BUCK&lt;/code&gt; files requires trial and error, deep Buck2 knowledge, and manual workarounds—making onboarding slow and error-prone.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;Buck2 does not replace Cargo’s package and dependency management&lt;/strong&gt;. While it can build Rust code, it cannot automatically resolve or fetch crates from crates.io. Teams must manually write BUCK files for every third-party dependency—a task that is neither scalable nor maintainable. Unlike Cargo’s declarative &lt;code&gt;Cargo.toml&lt;/code&gt;, this shifts the burden onto developers to replicate dependency metadata in build logic.&lt;/p&gt;
&lt;p&gt;Third, while Meta’s &lt;code&gt;reindeer&lt;/code&gt; tool aims to automate &lt;code&gt;BUCK&lt;/code&gt; file generation from &lt;code&gt;Cargo.toml&lt;/code&gt;, it falls short in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Its zero-configuration mode produces minimal, often incorrect outputs, requiring extensive custom rules.&lt;/li&gt;
&lt;li&gt;It relies on &lt;code&gt;fixup.toml&lt;/code&gt; to patch generated files, effectively replacing &lt;code&gt;BUCK&lt;/code&gt; authoring with &lt;code&gt;fixup.toml&lt;/code&gt; scripting—an unstable format with limited syntax guarantees and few official documentation.&lt;/li&gt;
&lt;li&gt;It introduces auxiliary &lt;code&gt;Cargo.toml&lt;/code&gt; files into the repository, which can interfere with Cargo-based workflows and CI pipelines, while adding new commands (&lt;code&gt;reindeer buckify&lt;/code&gt;) increases operational complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;buckal-seamless-buck2-integration-for-rust&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#buckal-seamless-buck2-integration-for-rust&quot; aria-label=&quot;Anchor link for: buckal-seamless-buck2-integration-for-rust&quot;&gt;Buckal – Seamless Buck2 Integration for Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Buckal is built on a simple idea: &lt;strong&gt;use Buck2 the way you use Cargo&lt;/strong&gt; — without changing your workflow, project layout, or mental model. Instead of forcing developers to learn Buck2 internals or maintain BUCK files, it leverages existing Cargo metadata and conventions to automatically generate and manage Buck2 configurations. The result is &lt;strong&gt;a zero-config, drop-in experience that unlocks Buck2’s performance while preserving Cargo’s ergonomics&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;design-principles&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#design-principles&quot; aria-label=&quot;Anchor link for: design-principles&quot;&gt;Design Principles&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;seamless-integration-with-cargo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#seamless-integration-with-cargo&quot; aria-label=&quot;Anchor link for: seamless-integration-with-cargo&quot;&gt;Seamless integration with Cargo&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Buckal treats &lt;code&gt;Cargo.toml&lt;/code&gt; as the single source of truth. It uses &lt;code&gt;cargo metadata&lt;/code&gt; to extract the full crate graph, including dependencies, features, target configurations, and source paths. Based on this information, it generates precise Buck2 build rules (&lt;code&gt;rust_library&lt;/code&gt;, &lt;code&gt;rust_binary&lt;/code&gt;, etc.) with correct visibility, deps, and attributes. Generated &lt;code&gt;BUCK&lt;/code&gt; files also include standard Cargo environment variables (e.g., &lt;code&gt;CARGO_PKG_NAME&lt;/code&gt;, &lt;code&gt;CARGO_PKG_VERSION&lt;/code&gt;) by default, reducing the need for manual adjustments.&lt;/p&gt;
&lt;h4 id=&quot;non-intrusive-by-design&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#non-intrusive-by-design&quot; aria-label=&quot;Anchor link for: non-intrusive-by-design&quot;&gt;Non-intrusive by design&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The plugin does not modify project structure or introduce auxiliary configuration files (e.g., no extra &lt;code&gt;Cargo.toml&lt;/code&gt;). Aside from local cache directories, it leaves the repository unchanged. When regenerating &lt;code&gt;BUCK&lt;/code&gt; files, it parses existing ones and preserves user-defined modifications (e.g., custom flags or environment variables), ensuring compatibility with manual overrides.&lt;/p&gt;
&lt;h4 id=&quot;consistent-cli-experience&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#consistent-cli-experience&quot; aria-label=&quot;Anchor link for: consistent-cli-experience&quot;&gt;Consistent CLI experience&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Commands like &lt;code&gt;cargo buckal build&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, and &lt;code&gt;update&lt;/code&gt; mirror their Cargo equivalents in both syntax and semantics. Under the hood, Buckal uses snapshotting and caching strategies to align Buck2’s execution model with Cargo’s expectations, so users get predictable outcomes without learning new patterns.&lt;/p&gt;
&lt;h3 id=&quot;implementation-details&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#implementation-details&quot; aria-label=&quot;Anchor link for: implementation-details&quot;&gt;Implementation Details&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;dependency-resolution-and-buck-file-generation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dependency-resolution-and-buck-file-generation&quot; aria-label=&quot;Anchor link for: dependency-resolution-and-buck-file-generation&quot;&gt;Dependency Resolution and BUCK File Generation&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;At the core of Buckal&#39;s automation is a comprehensive dependency analysis phase that leverages Cargo&#39;s own metadata to model the entire build graph. On invocation, Buckal runs &lt;code&gt;cargo metadata&lt;/code&gt; to obtain a structured representation of the workspace, including the full set of packages, their dependencies, target configurations, and the workspace root. It also parses &lt;code&gt;Cargo.lock&lt;/code&gt; to extract version pins and checksums for all dependencies, ensuring deterministic resolution.&lt;/p&gt;
&lt;p&gt;This information is aggregated into an internal context structure that serves as the foundation for generating accurate Buck2 rules. For third-party crates, Buckal adopts a &lt;strong&gt;remote-first strategy&lt;/strong&gt;: instead of vendoring dependencies into the repository (which bloats history and complicates updates), it configures Buck2 to fetch &lt;code&gt;.crate&lt;/code&gt; archives directly from crates.io at build time. For each dependency, it generates a &lt;code&gt;BUCK&lt;/code&gt; file defining an &lt;code&gt;http_archive&lt;/code&gt; rule with verified integrity, followed by a corresponding &lt;code&gt;rust_library&lt;/code&gt; rule that respects the crate&#39;s features, dependencies, and cfg settings. If the crate includes a &lt;code&gt;build.rs&lt;/code&gt; script, Buckal further generates a &lt;code&gt;rust_binary&lt;/code&gt; target to compile the script and a &lt;code&gt;buildscript_run&lt;/code&gt; rule to execute it in a hermetic environment, mimicking Cargo&#39;s build-time behavior.&lt;/p&gt;
&lt;p&gt;Following this, a corresponding &lt;code&gt;rust_library&lt;/code&gt; rule is generated, respecting the crate’s features, dependencies, and cfg settings. If the crate includes a &lt;code&gt;build.rs&lt;/code&gt; script, Buckal further generates a &lt;code&gt;rust_binary&lt;/code&gt; target to compile the script and a &lt;code&gt;buildscript_run&lt;/code&gt; rule to execute it in a hermetic environment, mimicking Cargo’s build-time behavior.&lt;/p&gt;
&lt;p&gt;For first-party crates (workspace members), Buckal inspects each package&#39;s targets and generates native Buck2 rules under their respective directories. Currently, it supports &lt;code&gt;lib&lt;/code&gt;, &lt;code&gt;bin&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; targets, producing &lt;code&gt;rust_library&lt;/code&gt;, &lt;code&gt;rust_binary&lt;/code&gt; and &lt;code&gt;rust_test&lt;/code&gt; rules with appropriate visibility, sources, and integration with the broader action graph. This dual-path generation strategy ensures that both local development and distributed builds remain fast, correct, and consistent — with only minimal manual &lt;code&gt;BUCK&lt;/code&gt; file maintenance required.&lt;/p&gt;
&lt;h4 id=&quot;buck-parse-patch&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#buck-parse-patch&quot; aria-label=&quot;Anchor link for: buck-parse-patch&quot;&gt;BUCK Parse &amp;amp; Patch&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;One of the key challenges in maintaining generated BUCK files is preserving manual modifications without requiring users to annotate or isolate their changes. To achieve this, Buckal implements a &lt;strong&gt;runtime-based rule extraction and patch preservation mechanism&lt;/strong&gt; that avoids the complexity of full Starlark parsing.&lt;/p&gt;
&lt;p&gt;Starlark — being a dialect of Python — allows function calls with rich syntax and arbitrary nesting, making AST-level analysis complex and regex-based approaches fragile. Instead of parsing the code directly, Buckal leverages the Python interpreter itself to extract rule parameters during execution. Using &lt;a rel=&quot;external&quot; href=&quot;https://github.com/PyO3/pyo3&quot;&gt;PyO3&lt;/a&gt;, Buckal interacts with the Python runtime installed on the local machine and dynamically loads each &lt;code&gt;BUCK&lt;/code&gt; file in a sandboxed environment where all Buck2 prelude functions (e.g., &lt;code&gt;http_archive&lt;/code&gt;, &lt;code&gt;rust_library&lt;/code&gt;) are replaced with instrumented versions. When the file executes, every rule invocation is captured, recording both the rule type and its keyword arguments. This approach enables precise, semantics-aware extraction of build rules with minimal overhead.&lt;/p&gt;
&lt;p&gt;After parsing, Buckal performs &lt;strong&gt;patch-aware regeneration&lt;/strong&gt;: when rewriting the BUCK file, it compares newly inferred values against previously captured user-defined fields. Mutable fields such as &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;rust_flags&lt;/code&gt;, &lt;code&gt;features&lt;/code&gt;, and &lt;code&gt;visibility&lt;/code&gt; are stored internally as ordered maps or sets, enabling efficient diffing. Any entry not derived from &lt;code&gt;Cargo.toml&lt;/code&gt; metadata is treated as a user patch and preserved in the next generation cycle. This ensures that developers can customize build behavior (e.g., adding sanitizer flags or test-specific environment variables) while still benefiting from automated synchronization of dependency graphs and target configurations — achieving true non-intrusive automation.&lt;/p&gt;
&lt;h4 id=&quot;cache-and-snapshot-mechanism&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cache-and-snapshot-mechanism&quot; aria-label=&quot;Anchor link for: cache-and-snapshot-mechanism&quot;&gt;Cache and Snapshot Mechanism&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To ensure both efficiency and behavioral consistency with Cargo, Buckal implements a lightweight &lt;strong&gt;fingerprint-based cache system&lt;/strong&gt; that serves two critical purposes: enabling incremental updates by detecting changes in the dependency graph, and acting as a versioned snapshot to preserve command-line semantics across invocations.&lt;/p&gt;
&lt;p&gt;Each fingerprint is a cryptographic hash (computed using &lt;a rel=&quot;external&quot; href=&quot;https://github.com/BLAKE3-team/BLAKE3&quot;&gt;BLAKE3&lt;/a&gt;) over a serialized representation of a package&#39;s relevant metadata — including the &lt;code&gt;PackageId&lt;/code&gt;, resolved dependencies, enabled features, and target configurations. This data is serialized via &lt;a rel=&quot;external&quot; href=&quot;https://crates.io/crates/bincode&quot;&gt;Bincode&lt;/a&gt; before hashing, ensuring deterministic output. Because the fingerprint captures only semantically meaningful inputs, any change in the build graph — such as adding a dependency or toggling a feature — results in a detectable hash difference. The design is intentionally minimal: instead of storing full dependency graphs or rule ASTs, it retains only compact hashes. This reduces disk footprint, speeds up diff computation, and avoids redundancy with Buck2&#39;s own action graph caching.&lt;/p&gt;
&lt;p&gt;On each invocation, Buckal loads the previous cache from disk, computes the current fingerprints for all packages, and compares them to identify modified nodes. For commands that mutate the dependency graph — such as &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, or &lt;code&gt;remove&lt;/code&gt; — Buckal delegates execution to the native &lt;code&gt;cargo&lt;/code&gt; binary. However, before running the command, it takes a pre-execution cache snapshot. After the command completes, it re-computes the cache and performs a diff to determine exactly which crates were added, removed, or updated. This delta informs targeted regeneration of corresponding &lt;code&gt;BUCK&lt;/code&gt; files, ensuring that BUILD file updates are precise, timely, and aligned with actual user actions. For non-mutating commands like &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, or &lt;code&gt;run&lt;/code&gt;, Buckal focuses on CLI compatibility, using the cache to validate the current build state and route targets correctly to Buck2 without altering the snapshot.&lt;/p&gt;
&lt;p&gt;By combining incremental change detection with semantic snapshots, Buckal achieves a key goal: Buck2&#39;s performance with Cargo&#39;s predictable, reproducible UX.&lt;/p&gt;
&lt;h3 id=&quot;cargo-compatibility&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cargo-compatibility&quot; aria-label=&quot;Anchor link for: cargo-compatibility&quot;&gt;Cargo Compatibility&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A critical barrier to adopting Buck2 for Rust projects is the deep reliance many crates have on Cargo’s specific build environment. As illustrated in our technical analysis, a significant portion of the Rust ecosystem depends on intricate mechanisms that go beyond simple compilation: &lt;strong&gt;standard environment variables&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;build.rs&lt;/code&gt; script interactions&lt;/strong&gt;, and &lt;strong&gt;the propagation of metadata through the dependency graph&lt;/strong&gt;. Unfortunately, Buck2’s built-in Rust rules provide insufficient support for these features out of the box. To address this, we developed a &lt;a rel=&quot;external&quot; href=&quot;https://github.com/buck2hub/buckal-bundles&quot;&gt;compatibility layer&lt;/a&gt; that extends Buck2’s native capabilities, &lt;strong&gt;achieving near 100% parity with Cargo’s build environment&lt;/strong&gt;.&lt;/p&gt;
&lt;script src=https://jjl9807.com/js/mermaid.js&gt;&lt;/script&gt;
&lt;pre class=&quot;mermaid&quot;&gt;

sequenceDiagram
    participant C as &quot;Cargo&quot;
    participant B as &quot;Build Script&quot;
    participant R as &quot;Rustc&quot;

    C-&gt;&gt;C: compile build script
    C-&gt;&gt;B: execute with env vars
    B-&gt;&gt;B: custom build logic
    B-&gt;&gt;C: output instructions
    C-&gt;&gt;C: parse BuildOutput
    C-&gt;&gt;R: add flags from BuildOutput
    R-&gt;&gt;C: compile main crate

&lt;/pre&gt;
&lt;h4 id=&quot;comprehensive-environment-variable-injection&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#comprehensive-environment-variable-injection&quot; aria-label=&quot;Anchor link for: comprehensive-environment-variable-injection&quot;&gt;Comprehensive Environment Variable Injection&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Cargo automatically injects a rich set of environment variables into every build process, which crates often rely on for versioning, feature detection, and path resolution. Our analysis revealed that Buck2’s default rules omit many of these standard variables. Buckal bridges this gap by automatically generating and injecting the full suite of &lt;code&gt;CARGO_PKG_*&lt;/code&gt; (e.g., &lt;code&gt;CARGO_PKG_VERSION&lt;/code&gt;, &lt;code&gt;CARGO_PKG_NAME&lt;/code&gt;) and &lt;code&gt;CARGO_MANIFEST_*&lt;/code&gt; variables into every target. Furthermore, for &lt;code&gt;build.rs&lt;/code&gt; scripts, Buckal ensures the execution environment is fully populated with critical context variables that Buck2 lacks, such as &lt;code&gt;OPT_LEVEL&lt;/code&gt;, &lt;code&gt;CARGO_MANIFEST_PATH&lt;/code&gt;, and &lt;code&gt;CARGO_MANIFEST_LINKS&lt;/code&gt;. This ensures that build scripts behave identically whether run under Cargo or Buck2.&lt;/p&gt;
&lt;h4 id=&quot;build-script-output-and-metadata-propagation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#build-script-output-and-metadata-propagation&quot; aria-label=&quot;Anchor link for: build-script-output-and-metadata-propagation&quot;&gt;Build Script Output and Metadata Propagation&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Perhaps the most complex challenge lies in handling the output of &lt;code&gt;build.rs&lt;/code&gt; scripts. Cargo allows scripts to emit instructions (e.g., &lt;code&gt;cargo::rustc-link-lib&lt;/code&gt;, &lt;code&gt;cargo::rustc-cfg&lt;/code&gt;) and custom metadata (&lt;code&gt;cargo::metadata&lt;/code&gt;). While Buck2 supports basic compiler flags, it historically lacked support for the &lt;code&gt;links&lt;/code&gt; manifest key and the associated metadata propagation mechanism. This mechanism is vital for crates like &lt;code&gt;openssl-sys&lt;/code&gt;, which use &lt;code&gt;build.rs&lt;/code&gt; to detect system libraries and pass that information (via &lt;code&gt;DEP_&amp;lt;NAME&amp;gt;_&amp;lt;KEY&amp;gt;&lt;/code&gt; environment variables) to dependent crates.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/cargo-buckal/./build-script.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Buckal implements a robust solution for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Instruction Parsing:&lt;/strong&gt; It parses &lt;code&gt;cargo::&lt;/code&gt; instructions from build script outputs and maps them to corresponding Buck2 rule attributes (e.g., linking flags, cfg settings). For features like &lt;code&gt;rustc-link-lib&lt;/code&gt;, we not only implemented local support but also contributed fixes upstream to the Buck2 repository to improve native handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata Propagation:&lt;/strong&gt; We implemented the logic to capture &lt;code&gt;cargo::metadata&lt;/code&gt; outputs and automatically propagate them as &lt;code&gt;DEP_&lt;/code&gt; environment variables to downstream dependencies. This ensures that the complex dependency chains found in native-binding crates function correctly without manual intervention.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By meticulously reconstructing these environmental nuances, Buckal allows developers to migrate complex, dependency-heavy Rust projects to Buck2 without modifying a single line of source code or build script.&lt;/p&gt;
&lt;h2 id=&quot;practical-experience-in-rk8s&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#practical-experience-in-rk8s&quot; aria-label=&quot;Anchor link for: practical-experience-in-rk8s&quot;&gt;Practical Experience in rk8s&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/rk8s-dev/rk8s&quot;&gt;Rk8s&lt;/a&gt; is a lightweight, Kubernetes-compatible container orchestration system built on &lt;a rel=&quot;external&quot; href=&quot;https://github.com/containers/youki&quot;&gt;Youki&lt;/a&gt;, implementing the Container Runtime Interface (CRI). It supports three primary workload types: standalone containers, Kubernetes-style pods, and Docker Compose-style multi-container applications. The codebase &lt;strong&gt;spans over 240,000 lines of Rust across 20 subprojects&lt;/strong&gt;, organized as a Cargo workspace — making it a representative large-scale Rust monorepo.&lt;/p&gt;
&lt;p&gt;Integrating Buck2 into rk8s was previously attempted using &lt;code&gt;reindeer&lt;/code&gt;, but the workflow proved cumbersome:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;reindeer&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-third-party-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; third-party&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; vendor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;reindeer&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-third-party-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; third-party&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; buckify&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;buck2&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; //project/...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This multi-step process required &lt;code&gt;reindeer&lt;/code&gt; to be installed and configured in both developer and CI environments. Moreover, due to incomplete rule generation, &lt;strong&gt;95 out of 683 crates&lt;/strong&gt; required manual fixes via &lt;code&gt;fixup.toml&lt;/code&gt; — a significant maintenance burden.&lt;/p&gt;
&lt;p&gt;With Buckal, migration became drastically simpler. Developers only need to run:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; buckal&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the project root. Thanks to runtime build-script introspection and comprehensive rule generation, Buckal achieves fully automated BUCK file management: &lt;strong&gt;no manual patching is required&lt;/strong&gt;, even for crates using native libraries or complex FFI setups.&lt;/p&gt;
&lt;p&gt;More importantly, the build workflow is unified:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; buckal&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;  #&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; replaces the entire reindeer + buck2 pipeline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;No auxiliary commands or pre-processing steps are needed.&lt;/strong&gt; The generated &lt;code&gt;BUCK&lt;/code&gt; files are immediately consumable by Buck2, enabling direct integration with remote execution and caching backends.&lt;/p&gt;
&lt;p&gt;As a result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CI pipelines no longer depend on &lt;code&gt;reindeer&lt;/code&gt;, reducing setup complexity.&lt;/li&gt;
&lt;li&gt;Build configuration is consistent and automatically synchronized with &lt;code&gt;Cargo.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Developer experience closely mirrors standard Cargo usage, lowering cognitive load.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most notably, &lt;strong&gt;end-to-end build time dropped from 8m30s to 5m40s — a 33% reduction&lt;/strong&gt; — even before enabling remote execution. This gain comes from better parallelization, more accurate dependency tracking, and reduced overhead in rule evaluation.&lt;/p&gt;
&lt;p&gt;Buckal has thus enabled rk8s to fully leverage Buck2’s performance while maintaining a simple, maintainable, and Cargo-native development experience.&lt;/p&gt;
&lt;h2 id=&quot;future-directions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#future-directions&quot; aria-label=&quot;Anchor link for: future-directions&quot;&gt;Future Directions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While Buckal already enables seamless Buck2 integration for most Rust projects, our roadmap focuses on three key areas to further improve dependency intelligence, structural flexibility, and ecosystem hermeticity.&lt;/p&gt;
&lt;h4 id=&quot;enhanced-dependency-intelligence-security&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#enhanced-dependency-intelligence-security&quot; aria-label=&quot;Anchor link for: enhanced-dependency-intelligence-security&quot;&gt;Enhanced Dependency Intelligence &amp;amp; Security&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Buckal inherently constructs a complete dependency graph of the workspace during rule generation. We plan to leverage this rich data structure to provide advanced analysis tools that go beyond simple build automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Supply Chain Security:&lt;/strong&gt; By integrating vulnerability databases, Buckal will offer built-in CVE scanning directly within the build workflow. Developers can identify security risks in transitive dependencies without needing external tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency Patching &amp;amp; Management:&lt;/strong&gt; We aim to implement fine-grained control over dependency versions. This includes the ability to upgrade or downgrade specific transitive nodes globally, resolving conflicts that are traditionally difficult to manage in Cargo alone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semver Resolution Hints:&lt;/strong&gt; When workspace members depend on different versions of the same crate, Cargo automatically unifies them by selecting a single version that satisfies all Semver constraints. However, this implicit selection may differ from developer expectations or cause compatibility issues. Buckal will detect such cases and prompt developers to verify the resolved version, preventing potential inconsistencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;support-for-complex-workspace-hierarchies&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#support-for-complex-workspace-hierarchies&quot; aria-label=&quot;Anchor link for: support-for-complex-workspace-hierarchies&quot;&gt;Support for Complex Workspace Hierarchies&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Real-world monorepos often exhibit complex structures that exceed the standard single-level Cargo workspace model. Currently, Buckal supports flat workspace layouts, but future versions will introduce robust support for &lt;strong&gt;nested Cargo Workspaces&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This enhancement will allow teams to organize large codebases into hierarchical domains while maintaining a unified Buck2 build graph. Buckal will correctly resolve cross-workspace dependencies and generate appropriate &lt;code&gt;BUCK&lt;/code&gt; files across directory boundaries, ensuring that organizational structure does not compromise build performance or correctness.&lt;/p&gt;
&lt;h4 id=&quot;deep-ecosystem-integration-via-buck2hub&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#deep-ecosystem-integration-via-buck2hub&quot; aria-label=&quot;Anchor link for: deep-ecosystem-integration-via-buck2hub&quot;&gt;Deep Ecosystem Integration via Buck2Hub&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To reduce per-project setup costs and maximize build hermeticity, we are evolving the concept of &lt;strong&gt;Buck2Hub&lt;/strong&gt;—a public registry of pre-generated, verified build configurations. However, our vision extends beyond simply sharing BUCK files.&lt;/p&gt;
&lt;p&gt;Many popular Rust crates rely on FFI or native links (e.g., &lt;code&gt;openssl-sys&lt;/code&gt;, &lt;code&gt;ring&lt;/code&gt;), traditionally requiring system-level dependencies that break reproducibility. Leveraging Buck2’s native multi-language capabilities, Buck2Hub will provide rules to &lt;strong&gt;build these C/C++ dependencies from source&lt;/strong&gt; within the Buck2 action graph.&lt;/p&gt;
&lt;p&gt;Instead of relying on &lt;code&gt;apt-get&lt;/code&gt; or pre-built binaries, Buckal will fetch canonical rules from Buck2Hub to compile native libraries hermetically alongside Rust code. This approach ensures &lt;strong&gt;true reproducibility&lt;/strong&gt;, &lt;strong&gt;reduced external dependencies&lt;/strong&gt; and &lt;strong&gt;unified toolchain&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Rust ecosystem offers several build solutions, each with distinct trade-offs. To help teams choose the right tool for their needs, we summarize the characteristics of mainstream approaches below:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Criteria&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Cargo&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;GN&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Buck2 (reindeer)&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Buck2 (buckal)&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Design Philosophy&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Rust-native tooling &amp;amp; Deep ecosystem integration&lt;/td&gt;&lt;td&gt;Meta-build system &amp;amp; Language-agnostic&lt;/td&gt;&lt;td&gt;Language-agnostic &amp;amp;  Parallelism, high scalability, reproducibility&lt;/td&gt;&lt;td&gt;Language-agnostic &amp;amp;  Parallelism, high scalability, reproducibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Dependency Management&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Declarative &amp;amp; Automatic&lt;/td&gt;&lt;td&gt;Manual &amp;amp; Explicit&lt;/td&gt;&lt;td&gt;Semi-automatic &amp;amp; Manual patches&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Automatic &amp;amp; No manual maintenance&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cross-Language Integration&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Relies on external toolchains&lt;/td&gt;&lt;td&gt;Designed for polyglot projects&lt;/td&gt;&lt;td&gt;Native multi-language support&lt;/td&gt;&lt;td&gt;Native multi-language support&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Version Control &amp;amp; Release&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Semver &amp;amp; Workspace&lt;/td&gt;&lt;td&gt;Highly customizable&lt;/td&gt;&lt;td&gt;Flexible customization and pipeline integration&lt;/td&gt;&lt;td&gt;Flexible customization and pipeline integration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Moderate&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Consistent with Cargo&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ideal Use Cases&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Pure Rust projects&lt;/td&gt;&lt;td&gt;Ultra-large polyglot projects&lt;/td&gt;&lt;td&gt;Ultra-large polyglot projects &amp;amp; Enterprise-grade Monorepo&lt;/td&gt;&lt;td&gt;Ultra-large polyglot projects &amp;amp; Enterprise-grade Monorepo&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Buckal addresses a critical gap in the Rust tooling landscape by making enterprise-grade build infrastructure accessible without sacrificing developer experience. Its core value lies in three pillars: &lt;strong&gt;zero-friction adoption&lt;/strong&gt; by treating &lt;code&gt;Cargo.toml&lt;/code&gt; as the single source of truth and eliminating the need to maintain BUCK files; &lt;strong&gt;near-perfect compatibility&lt;/strong&gt; through comprehensive environment variable injection and build script parsing that ensures existing crates compile without modification; and &lt;strong&gt;scalable performance&lt;/strong&gt; that unlocks Buck2&#39;s distributed caching and fine-grained parallelism.&lt;/p&gt;
&lt;p&gt;Looking ahead, &lt;strong&gt;Buckal aims to become the definitive bridge between the Rust ecosystem and enterprise-grade build infrastructure&lt;/strong&gt;. We envision a future where Rust teams can seamlessly scale from single-developer crates to thousand-contributor monorepos without changing their mental model or workflow. By combining Cargo&#39;s ergonomics with Buck2&#39;s power—and fostering community collaboration through initiatives like Buck2Hub—we are committed to making high-performance, reproducible, and scalable builds the default, not the exception. Whether you are building a pure Rust application or a polyglot system spanning multiple languages, Buckal invites you to experience the best of both worlds: the simplicity of Cargo and the scalability of Buck2.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>qlean</title>
        <published>2025-12-07T00:00:00+00:00</published>
        <updated>2025-12-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/projects/qlean/"/>
        <id>https://jjl9807.com/projects/qlean/</id>
        
        <content type="html" xml:base="https://jjl9807.com/projects/qlean/"></content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buck2 构建 Turso 报错排查</title>
        <published>2025-11-26T00:00:00+00:00</published>
        <updated>2025-11-26T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/why-buck2-build-turso-failed/"/>
        <id>https://jjl9807.com/posts/why-buck2-build-turso-failed/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/why-buck2-build-turso-failed/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;近日，笔者在使用 Buck2 构建 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/web3infra-foundation/libra&quot;&gt;Libra&lt;/a&gt; 项目时遇到了以下问题：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./e0463.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;编译器报告了 &lt;code&gt;E0463&lt;/code&gt; 错误，提示编译器链接时找不到代码里声明的 &lt;code&gt;libra&lt;/code&gt; 包，一般导致此问题的原因有两种：一是 crate 不存在（例如忘记添加依赖），二是“货不对版”（例如依赖名称不匹配或者元数据有误）。&lt;/p&gt;
&lt;h2 id=&quot;pai-cha-guo-cheng&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pai-cha-guo-cheng&quot; aria-label=&quot;Anchor link for: pai-cha-guo-cheng&quot;&gt;排查过程&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;根据编译器报错，笔者初步怀疑 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/buck2hub/cargo-buckal&quot;&gt;Buckal&lt;/a&gt; 工具生成的 BUCK 文件有误，可能没有正确处理 crate 自引用，但是经过反复比对 Buck2 和 Cargo 发射的 rustc 调用参数，最终排除了 Buckal 工具的问题。&lt;/p&gt;
&lt;p&gt;为了进一步探明原因，笔者编写了以下代码来测试中间构建产物的正确性：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;extern&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; crate&lt;/span&gt;&lt;span&gt; libra&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; libra&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span&gt;cli&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在不使用构建系统的情况下，rustc 通过 &lt;code&gt;--extern name[=path]&lt;/code&gt; 和 &lt;code&gt;-L dependency=...&lt;/code&gt; 参数指定当前 crate 所引用的依赖，其中前者主要用于声明直接依赖，后者则负责描述传递依赖的查找范围。&lt;/p&gt;
&lt;p&gt;我们可以通过手动构造参数的方式使用以下命令进行测试，其中 &lt;code&gt;liblibra-606a0e18.rlib&lt;/code&gt; 为 libra 库的中间构建产物，&lt;code&gt;t.rs&lt;/code&gt; 为上述测试代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rustc&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-extern&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libra=buck-out/v2/gen/root/2c621926a02f7469/__liblibra__/LPPL/liblibra-606a0e18.rlib&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;Ldependency=buck-out/v2/gen/root/2c621926a02f7469/__libra__/XIPL-depslink-0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; t.rs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常情况下编译器应该发出 &lt;code&gt;unused import&lt;/code&gt; 警告：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./unused-import.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;但是这里编译器直接报告了 &lt;code&gt;E0460&lt;/code&gt; 错误，可以确定该问题由 turso_core 依赖导致：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./e0460.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然而，该问题在使用 Cargo 构建时无法复现，因此笔者推测其根本原因在于 Buck2 Prelude 对 Rust 编译所采用的底层策略。Buck2 可能会对同一个 target 使用不同的参数和策略进行多次编译，具体的参数组合如下表所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./buck2-subdir.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;对于一般的 Rust 库，Buck2 默认会构建两次，分别编译 metadata-full 和 link 版本。其中，前者不实际生成机器代码，仅包含元数据，主要供其他依赖它的 crate 进行快速构建、依赖解析、类型检查等；后者则包含完整内容，在最后链接时使用。这种策略可以缩短单个 action 编译时间，同时提高整个构建任务的并行化程度。&lt;/p&gt;
&lt;p&gt;正常情况下，rustc 通过 &lt;code&gt;--emit link,metadata&lt;/code&gt; 和 &lt;code&gt;--emit link&lt;/code&gt; 参数产生的 rlib 文件当中的元数据应该保持一致。以 toml 库为例，解包后的 &lt;code&gt;lib.rmeta&lt;/code&gt; 文件哈希值完全相同：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./consistent-rmeta.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然而 turso_core 通过 built 动态注入构建时信息（时间戳），导致每次构建产物的哈希值都不一致，具体如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/why-buck2-build-turso-failed/./inconsistent-rmeta.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;因此，turso_core 在构建时产生的元数据和链接时使用的并不一致，rustc 会拒绝链接。同时，因为这是一个传递依赖，编译器并不会给出明确的报错。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;为快速解决以上问题，我们选择修改 turso 源代码使之产生确定的构建产物。具体地，turso_core 通过 built 动态注入的构建时信息储存在 &lt;code&gt;info::build&lt;/code&gt; 模块中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; core/info.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; mod&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; build&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    include!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;concat!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;env!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;OUT_DIR&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/built.rs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在业务层面，主要是 turso_core 虚拟数据库引擎 (VDBE) 的 &lt;code&gt;ScalarFunc::SqliteSourceId&lt;/code&gt; 函数用到了构建时间戳：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; core/vdbe/execute.rs:5326&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ScalarFunc&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;SqliteSourceId&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; src_id&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; format!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        info&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;BUILT_TIME_SQLITE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        info&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;GIT_COMMIT_HASH&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;unwrap_or&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span&gt;registers&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;dest&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; Register&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Value&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;build_text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src_id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文所述问题具有一定的共性：任何构建产物中包含动态变化内容的 crate 都可能触发类似现象。其根本解决方案在于修改 Buck2 构建策略，在 Rust 构建规则中引入参数配置，支持为特定 target 启用“仅执行一次构建”的行为，从而避免因 rlib 元数据变动而导致构建失败。&lt;/p&gt;
&lt;p&gt;然而，Buck2 Prelude 中涉及编译策略与参数控制的部分较为复杂，相关修改需投入大量时间和精力。为不影响 Libra 项目的当前进度，我们暂时采用了对依赖源码打补丁的临时方案。未来仍计划通过定制 Prelude 实现彻底、可持续的解决。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>远程调试微信内置浏览器并清除网页缓存</title>
        <published>2025-08-17T00:00:00+00:00</published>
        <updated>2025-08-17T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/wechat-xweb-remote-debug/"/>
        <id>https://jjl9807.com/posts/wechat-xweb-remote-debug/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/wechat-xweb-remote-debug/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;微信内置的浏览器并没有提供调试入口，这种情况下如果某些网页的认证信息发生了变化，在微信内访问时常常因为缓存和 cookie 的存在导致这些页面无法顺利切换认证信息，给开发和使用带来了较大的不便。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;微信 8.0.19 以上的版本中内置浏览器由 X5 内核替换成了 XWEB 内核，可以使用 XWEB 内核的调试功能清除对应网页的缓存和 cookie。&lt;/p&gt;
&lt;h3 id=&quot;kai-qi-xweb-diao-shi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#kai-qi-xweb-diao-shi&quot; aria-label=&quot;Anchor link for: kai-qi-xweb-diao-shi&quot;&gt;开启 XWEB 调试&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在微信内访问 http://debugxweb.qq.com/?inspector=true 开启 XWEB 内核的调试功能，如果网页自动跳转微信官网则说明开启成功。&lt;/p&gt;
&lt;h3 id=&quot;lian-jie-shou-ji-dao-dian-nao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lian-jie-shou-ji-dao-dian-nao&quot; aria-label=&quot;Anchor link for: lian-jie-shou-ji-dao-dian-nao&quot;&gt;连接手机到电脑&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;确保手机解锁并通过数据线连接电脑（注意选择传输文件/调试模式），然后打开手机的开发者模式并开启 USB 调试。&lt;/p&gt;
&lt;h3 id=&quot;yuan-cheng-diao-shi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-cheng-diao-shi&quot; aria-label=&quot;Anchor link for: yuan-cheng-diao-shi&quot;&gt;远程调试&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在电脑端使用 Chrome 浏览器打开 &lt;code&gt;chrome://inspect/#devices&lt;/code&gt;（或者使用 Edge 浏览器打开&lt;code&gt;edge://inspect/#devices&lt;/code&gt;），如下图所示，Remote Target 下方会显示正在调试的手机型号，在微信内打开需要的网页，此时选择电脑上对应的网页点击 inspect 即可在弹出的窗口中开始调试。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/wechat-xweb-remote-debug/./remote-target.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;调试窗口与普通的开发者工具无异，我们选择“应用-存储”选项卡，点击“清除网站数据”即可清除该网页存储在微信内置浏览器本地的所有数据，具体如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/wechat-xweb-remote-debug/./devtools.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在微信中关闭网页重新打开后可以发现之前的缓存和 cookie 已经消失，已经正常切换为新的认证信息。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>cargo-buckal</title>
        <published>2025-07-27T00:00:00+00:00</published>
        <updated>2025-07-27T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/projects/buckal/"/>
        <id>https://jjl9807.com/projects/buckal/</id>
        
        <content type="html" xml:base="https://jjl9807.com/projects/buckal/"></content>
        
    </entry>
    <entry xml:lang="en">
        <title>Debian 12 (Wayland) 安装腾讯会议并实现原生屏幕共享</title>
        <published>2025-07-20T00:00:00+00:00</published>
        <updated>2026-04-08T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/wayland-wemeet-screen-sharing/"/>
        <id>https://jjl9807.com/posts/wayland-wemeet-screen-sharing/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/wayland-wemeet-screen-sharing/">&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;腾讯会议在 2025 年 9 月更新了 Linux 版本，已经原生支持 Wayland 桌面环境下的屏幕共享功能，软件界面也更加美观现代，可用性基本追平 Win/Mac 版本，读者直接前往官网下载安装即可（截至本文更新，最新版本为 &lt;code&gt;3.26.10.401 2025-11-05&lt;/code&gt;）。因此，本文介绍的方法已经过时，仅作记录和探索。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;an-zhuang-teng-xun-hui-yi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-teng-xun-hui-yi&quot; aria-label=&quot;Anchor link for: an-zhuang-teng-xun-hui-yi&quot;&gt;安装腾讯会议&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在&lt;a rel=&quot;external&quot; href=&quot;https://meeting.tencent.com/download/&quot;&gt;腾讯会议官网&lt;/a&gt;下载安装包并安装（笔者下载的版本是 3.19.2.400）。&lt;/p&gt;
&lt;p&gt;安装完成后观察 &lt;code&gt;/usr/share/applications/wemeetapp.desktop&lt;/code&gt; 文件发现腾讯会议主程序由 &lt;code&gt;/opt/wemeet/wemeetapp.sh&lt;/code&gt; 脚本启动，但是直接点击程序图标运行会出现以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;检测到窗口系统采用wayland协议，腾讯会议暂不兼容，程序即将退出！&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xiu-gai-qi-dong-jiao-ben&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiu-gai-qi-dong-jiao-ben&quot; aria-label=&quot;Anchor link for: xiu-gai-qi-dong-jiao-ben&quot;&gt;修改启动脚本&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;腾讯会议默认不支持 Wayland 桌面环境，因此需要对启动脚本 &lt;code&gt;/opt/wemeet/wemeetapp.sh&lt;/code&gt; 进行一些修改。具体地，启动脚本通过 &lt;code&gt;if [ &quot;$XDG_SESSION_TYPE&quot; = &quot;wayland&quot; ]&lt;/code&gt; 这一行代码检测机器的桌面环境，我们需要在此之前添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Force x11 instead of Wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; XDG_SESSION_TYPE&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;x11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; EGL_PLATFORM&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;x11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; QT_QPA_PLATFORM&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;xcb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; WAYLAND_DISPLAY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; WAYLAND_DISPLAYCOPY&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再次启动程序，发现能够正常登陆账户并发起/参与会议，声音、画面一切正常，但是无法进行屏幕共享，发起共享后其他与会人员只能看到黑屏。&lt;/p&gt;
&lt;h2 id=&quot;shi-xian-yuan-sheng-ping-mu-gong-xiang&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-xian-yuan-sheng-ping-mu-gong-xiang&quot; aria-label=&quot;Anchor link for: shi-xian-yuan-sheng-ping-mu-gong-xiang&quot;&gt;实现原生屏幕共享&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;针对腾讯会议在 Wayland 桌面环境下无法进行屏幕共享的问题，&lt;a rel=&quot;external&quot; href=&quot;https://github.com/xuwd1/wemeet-wayland-screenshare&quot;&gt;xuwd1/wemeet-wayland-screenshare&lt;/a&gt; 项目 hook 了 X11 的 &lt;code&gt;XShmAttach&lt;/code&gt;, &lt;code&gt;XShmGetImage&lt;/code&gt; 和 &lt;code&gt;XShmDetach&lt;/code&gt; 函数，实现了一个兼容层 (libhook.so)，带来了原生的屏幕共享支持。&lt;/p&gt;
&lt;h3 id=&quot;an-zhuang-yi-lai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-yi-lai&quot; aria-label=&quot;Anchor link for: an-zhuang-yi-lai&quot;&gt;安装依赖&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;首先，安装 libhook 运行所需的系统依赖：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wireplumber&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; xdg-desktop-portal&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; xdg-desktop-portal-gtk&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; xdg-desktop-portal-wlr&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;  libopencv-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libportal-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libpipewire-0.3-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libx11-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libxdamage-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libxcomposite-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libxrandr-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;gou-jian-libhook&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gou-jian-libhook&quot; aria-label=&quot;Anchor link for: gou-jian-libhook&quot;&gt;构建 libhook&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;笔者在本机中安装构建依赖时出现以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;E: 无法定位软件包 xwaylandvideobridge&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过查询 &lt;a rel=&quot;external&quot; href=&quot;https://tracker.debian.org/pkg/xwaylandvideobridge&quot;&gt;Debian Package Tracker&lt;/a&gt; 发现 xwaylandvideobridge 软件包在 2024 年 12 月 4 日才并入 testing 软件源，因此目前在 bookworm(Debian 12) 软件源中不可用，为避免跨发行版更新软件源导致大规模兼容性问题，笔者决定使用 docker 构建 hook library。&lt;/p&gt;
&lt;blockquote class=&quot;markdown-alert-tip&quot;&gt;
&lt;p&gt;笔者通过&lt;a rel=&quot;external&quot; href=&quot;https://aur.archlinux.org/packages/wemeet-wayland-screenshare-git#comment-1032886&quot;&gt;进一步查询&lt;/a&gt;以及后续实际测试发现，xwaylandvideobridge 并非 hook library 运行所必需的依赖（至少在 KDE 和 GNOME 下并不依赖），而项目原作者为了保留不同桌面环境的兼容性，仍然在项目中引用了该库。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;创建 builder 镜像工作目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wemeet-wayland&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编写 builder 镜像 dockerfile，具体内容如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; debian:trixie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;RUN&lt;/span&gt;&lt;span&gt; apt update &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apt install -y build-essential cmake ninja-build pkg-config wireplumber xdg-desktop-portal xdg-desktop-portal-gtk xdg-desktop-portal-wlr xwaylandvideobridge libopencv-dev libportal-dev libpipewire-0.3-dev git libx11-dev libxdamage-dev libxcomposite-dev libxrandr-dev &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apt clean &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rm -rf /var/lib/apt/lists/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;WORKDIR&lt;/span&gt;&lt;span&gt; /app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;CMD&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;bash&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-c&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;git clone --recursive https://github.com/xuwd1/wemeet-wayland-screenshare.git &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    cd wemeet-wayland-screenshare &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    mkdir build &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    cd build &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release &amp;amp;&amp;amp; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    ninja&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建 builder 镜像，整个过程大概需要 4 分钟左右：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wemeet-wayland-screenshare-builder&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行容器，执行构建任务：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; run&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-rm&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ./app:/app&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wemeet-wayland-screenshare-builder&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建任务结束后 builder 容器会自动退出并删除，最终的构建产物为当前目录下的 &lt;code&gt;app/wemeet-wayland-screenshare/build/libhook.so&lt;/code&gt; 文件。&lt;/p&gt;
&lt;h3 id=&quot;yu-jia-zai-libhook&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yu-jia-zai-libhook&quot; aria-label=&quot;Anchor link for: yu-jia-zai-libhook&quot;&gt;预加载 libhook&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;拷贝 libhook.so 到系统目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/lib/wemeet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cp&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; app/wemeet-wayland-screenshare/build/libhook.so&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/lib/wemeet&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用以下命令测试 libhook 是否工作正常：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LD_PRELOAD&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; /opt/wemeet/wemeetapp.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，再次修改腾讯会议启动脚本 &lt;code&gt;/opt/wemeet/wemeetapp.sh&lt;/code&gt;，在最后一行代码 &lt;code&gt;exec wemeetapp $*&lt;/code&gt; 的上方添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; LD_PRELOAD&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;usr&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;wemeet&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;libhook&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;so&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此后再点击桌面图标启动腾讯会议就一切功能正常了！🎉🎉🎉&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;https://icooper.cc/archives/445&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://www.cnblogs.com/yerosius/p/18806551&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://github.com/xuwd1/wemeet-wayland-screenshare&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>计算 rustc 的代码覆盖率</title>
        <published>2025-06-26T00:00:00+00:00</published>
        <updated>2025-06-26T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/rustc-instrument-coverage/"/>
        <id>https://jjl9807.com/posts/rustc-instrument-coverage/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/rustc-instrument-coverage/">&lt;p&gt;最近，笔者需要统计 rustc 在编译特定程序时的代码覆盖率。由于这一过程涉及构建带有插桩（instrumentation）的自定义 rustc，步骤较为繁琐，容易出错。为方便日后回顾，也为了给有类似需求的读者提供参考，特将完整流程整理成文。&lt;/p&gt;
&lt;h2 id=&quot;gou-jian-cha-zhuang-rustc&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gou-jian-cha-zhuang-rustc&quot; aria-label=&quot;Anchor link for: gou-jian-cha-zhuang-rustc&quot;&gt;构建插桩 rustc&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先安装系统依赖：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ninja-build&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libssl-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libzstd-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; llvm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; lld&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; clang&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cmake&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后安装覆盖率插件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; grcov&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着，下载最新版本的 rustc 源代码并解压，笔者这里下载的是 1.87.0 版本：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;wget&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://static.rust-lang.org/dist/rustc-1.87.0-src.tar.xz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;xf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; rustc-1.87.0-src.tar.xz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入源代码目录，运行 &lt;code&gt;./configure&lt;/code&gt; 指令生成默认构建配置 &lt;code&gt;bootstrap.toml&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; rustc-1.87.0-src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;./configure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开 &lt;code&gt;bootstrap.toml&lt;/code&gt; 文件，开启 profiler 选项，其他内容保持默认：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;build&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;profiler&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;x86_64-unknown-linux-gnu&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;profiler&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后需要修改 rustc 的 builder 源码，添加插桩命令。具体地，在 &lt;code&gt;src/bootstrap/src/core/builder/cargo.rs&lt;/code&gt; 文件的 580 行左右（可以全局搜索 &lt;code&gt;rust_new_symbol_mangling&lt;/code&gt; 关键字，就在它附近）添加以下插桩的命令：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;if&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; Mode&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Std&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rustflags&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;arg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-Cinstrument-coverage&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，对于标准库的编译不能插桩，否则会报错提示缺少 profiler 库。&lt;/p&gt;
&lt;p&gt;最后，运行以下命令开始编译：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;./x&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ./x&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据机器配置的不同，编译过程大约耗时 1 小时，最终构建出的 rustc 安装在 &lt;code&gt;/usr/local/bin/rustc&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;h2 id=&quot;ji-suan-dai-ma-fu-gai-lu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-suan-dai-ma-fu-gai-lu&quot; aria-label=&quot;Anchor link for: ji-suan-dai-ma-fu-gai-lu&quot;&gt;计算代码覆盖率&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;bian-yi-cheng-xu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-cheng-xu&quot; aria-label=&quot;Anchor link for: bian-yi-cheng-xu&quot;&gt;编译程序&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用刚才构建的插桩 rustc 编译给定程序：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LLVM_PROFILE_FILE&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;coverage/%p-%m.profraw&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; /usr/local/bin/rustc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; t1.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LLVM_PROFILE_FILE&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;coverage/%p-%m.profraw&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; /usr/local/bin/rustc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; t2.rs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于多个 rust 文件，使用以上命令依次编译即可，所有的结果都会存在 coverage 文件夹中。&lt;/p&gt;
&lt;p&gt;如果是 Cargo 项目，使用我们构建的 cargo 二进制文件即可，它会自动调用插桩的 rustc：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;/usr/local/bin/cargo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;cha-kan-fu-gai-lu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cha-kan-fu-gai-lu&quot; aria-label=&quot;Anchor link for: cha-kan-fu-gai-lu&quot;&gt;查看覆盖率&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;编译完成后可以通过以下命令查看 rustc 的代码覆盖率：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;grcov&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; coverage/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.profraw&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /root/Desktop/rustc-1.87.0-src/build/x86_64-unknown-linux-gnu/stage1&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /root/Desktop/rustc-1.87.0-src/compiler&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; html&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-branch&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-ignore-not-existing&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-llvm-path&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /root/rustc-1.87.0-src/build/x86_64-unknown-linux-gnu/llvm/bin&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; coverage/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于多个 .profraw 文件，也可以使用以下命令合并后再导出覆盖率报告：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;/root/rustc-1.87.0-src/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-profdata&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; merge&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sparse&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.profraw&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; merged.profdata&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;ul&gt;
&lt;li&gt;上述指令中 &lt;code&gt;/root/Desktop/rustc-1.87.0-src&lt;/code&gt; 是构建插桩 rustc 的源码路径，需要根据实际情况修改&lt;/li&gt;
&lt;li&gt;开启 profiler 之后 rustc 的运行效率将受到较大影响，因此不建议在计算覆盖率的同时观测和性能有关的数据&lt;/li&gt;
&lt;li&gt;.profraw 文件体积较大，大规模的任务极易耗尽存储空间，建议另起一个脚本监控 coverage 目录，滚动合并 rustc 生成的 .profraw 文件&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://doc.rust-lang.org/rustc/instrument-coverage.html&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>解决 WSL 更新后无法挂载磁盘的问题</title>
        <published>2025-06-18T00:00:00+00:00</published>
        <updated>2025-06-18T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-wsl2-disk-attach-failure/"/>
        <id>https://jjl9807.com/posts/resolve-wsl2-disk-attach-failure/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-wsl2-disk-attach-failure/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;近日，笔者通过 &lt;code&gt;wsl --update&lt;/code&gt; 命令将 WSL 从 2.4.11 更新至 2.5.9 过程中电脑意外重启，随后启动 WSL 出现以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;无法将磁盘“C:\Program Files\WSL\system.vhd”附加到 WSL2: 系统找不到指定的文件。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;错误代码: Wsl/Service/CreateInstance/CreateVm/MountDisk/HCS/ERROR_FILE_NOT_FOUND&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Press any key to continue...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;从 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/microsoft/WSL&quot;&gt;microsoft/WSL&lt;/a&gt; 仓库下载 2.5.9 版本对应的 .msi 文件，然后右击选择 “修复” 选项，待修复完成后即可正常启动。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://github.com/microsoft/WSL/issues/11288#issuecomment-2914790945&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>解决 libseccomp 构建过程报错 no method named `get_notify_fd` found</title>
        <published>2025-04-08T00:00:00+00:00</published>
        <updated>2025-04-08T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-libseccomp-build-error/"/>
        <id>https://jjl9807.com/posts/resolve-libseccomp-build-error/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-libseccomp-build-error/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上周笔者在使用 &lt;a rel=&quot;external&quot; href=&quot;https://buck2.build/&quot;&gt;Buck2&lt;/a&gt; 构建 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/youki-dev/youki&quot;&gt;youki&lt;/a&gt; 项目下的 libcontainer 时出现了以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error[E0599]: no method named `get_notify_fd` found for struct `ScmpFilterContext` in the current scope&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   --&amp;gt; crates/libcontainer/src/seccomp/mod.rs:268:17&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;268 |             ctx.get_notify_fd()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |                 ^^^^^^^^^^^^^ method not found in `ScmpFilterContext`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For more information about this error, try `rustc --explain E0599`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error: could not compile `libcontainer` (lib) due to 1 previous error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过分析，应该是 &lt;a rel=&quot;external&quot; href=&quot;https://crates.io/crates/libseccomp&quot;&gt;libseccomp-rs&lt;/a&gt; 这个 crate 在构建过程中发生了错误，查询资料发现这个 crate 依赖系统中的 libseccomp 库，并且其版本不低于 2.5.0。&lt;/p&gt;
&lt;p&gt;在 Debian 及其派生系统上，我们可以使用以下命令安装 libseccomp 库：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; seccomp&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libseccomp-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后，上述问题顺利解决。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #b40000; font-weight:bold;&quot;&gt;但是&lt;/span&gt;，笔者昨天在为团队成员从头打包开发环境的时候再次遇到了以上问题，并且确认系统中已经安装 libseccomp 库。&lt;/p&gt;
&lt;h2 id=&quot;yuan-yin-fen-xi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-yin-fen-xi&quot; aria-label=&quot;Anchor link for: yuan-yin-fen-xi&quot;&gt;原因分析&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;考虑到当前系统中已经安装了 libseccomp 库，因此 libseccomp-rs 应该还有其他依赖没有安装导致编译时刻无法获取系统中的 libseccomp 库。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;build.rs&lt;/code&gt; 中，libseccomp-rs 使用 pkg-config 来探测系统中是否存在 libseccomp 库并设置条件编译标志 &lt;code&gt;libseccomp_v2_5&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; build.rs:25-31&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; pkg_config&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;atleast_version&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;2.5.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;probe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;libseccomp&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;is_ok&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;cargo:rustc-cfg=libseccomp_v2_5&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中，pkg-config 是一个在编译时帮助管理库文件的工具，它通过 &lt;code&gt;.pc&lt;/code&gt; 文件获取库的编译和链接选项并在编译时自动插入，避免了硬编码编译选项的麻烦。&lt;/p&gt;
&lt;p&gt;进一步分析 libseccomp-rs 代码可以发现，其入口文件 &lt;code&gt;lib.rs&lt;/code&gt; 只在 &lt;code&gt;#[cfg(any(libseccomp_v2_5, doc))]&lt;/code&gt; 条件成立的情况下导入了 &lt;code&gt;notify&lt;/code&gt; 模块：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; src/lib.rs:75-78&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;any&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;libseccomp_v2_5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; doc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;mod&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; notify&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;mod&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; syscall&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;mod&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; version&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到这里其实问题已经非常明显了，由于笔者打包环境时使用的时全新安装的 Debian 12，系统中默认没有安装 pkg-config 导致即使已经安装 libseccomp 库也无法在构建 libseccomp-rs 时被探测到。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;安装 pkg-config 工具之后就可以顺利构建了：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pkg-config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://crates.io/crates/libseccomp&lt;/li&gt;
&lt;li&gt;https://github.com/youki-dev/youki/issues/1318&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>解决 WSL 下 gpg 签名 git commit 报错</title>
        <published>2025-03-09T00:00:00+00:00</published>
        <updated>2025-03-09T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-wsl-gpg-sign-error/"/>
        <id>https://jjl9807.com/posts/resolve-wsl-gpg-sign-error/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-wsl-gpg-sign-error/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WSL 中使用以下使用 gpg 对提交的更改并进行签名：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; commit&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;This is my commit message&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error: gpg failed to sign the data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fatal: failed to write commit object&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;yuan-yin-fen-xi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-yin-fen-xi&quot; aria-label=&quot;Anchor link for: yuan-yin-fen-xi&quot;&gt;原因分析&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pinentry 是 GnuPG 的密码输入工具，默认情况下会弹出一个图形化窗口来请求用户输入密码，但是在 WSL2 环境中，由于没有图形桌面环境，密码输入框无法弹出，导致 gpg 签名无法继续进行。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;针对上述分析，笔者梳理了目前常见的三种解决方案，分别利用了 pinentry 回环模式、gpg-agent 缓存机制、socket 重定向以及 WSL 客户机与宿主机的互通性，其中笔者采用的是最后一种方案，直接调用 Windows 下的 gpg.exe，以实现与 vscode 优雅集成。&lt;/p&gt;
&lt;h3 id=&quot;hui-huan-mo-shi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hui-huan-mo-shi&quot; aria-label=&quot;Anchor link for: hui-huan-mo-shi&quot;&gt;回环模式&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用以下命令配置 pinentry 启用 loopback 模式：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\nuse-agent\npinentry-mode loopback&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.gnupg/gpg.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\nallow-loopback-pinentry&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.gnupg/gpg-agent.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述命令首先启用 GPG 代理并设置密码输入模式为 “回环模式”，接着配置 gpg-agent 允许使用回环模式进行密码输入。此时，密码输入将通过命令行回传给 GnuPG，而不是依赖图形界面。&lt;/p&gt;
&lt;p&gt;这种方案有效解决了密码输入框无法弹出的问题，但是只能在终端环境下使用，如果日常使用 vscode 配合 WSL 进行开发，则无法直接在 vscode 中直接提交 git commit，降低了开发体验。此外，通过命令行回传密码通常也被认为不够安全。&lt;/p&gt;
&lt;h3 id=&quot;gpg-agent-huan-cun&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gpg-agent-huan-cun&quot; aria-label=&quot;Anchor link for: gpg-agent-huan-cun&quot;&gt;gpg-agent 缓存&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;gpg-agent 会缓存我们输入的密码，在缓存有效期内我们对数据签名不需要重复输入密码，因此我们可以写一个 shell 脚本并设置合适的密码缓存时间，这样就能够实现开机后手动输入一次密码，之后就能顺利使用 vscode 提交 git commit。&lt;/p&gt;
&lt;p&gt;笔者写了一个示例脚本供各位参考：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;gpg-login&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    export&lt;/span&gt;&lt;span&gt; GPG_TTY&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;TTY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    echo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; gpg&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-clearsign&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /dev/null&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; 2&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&amp;amp;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;gpg-logout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    echo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; RELOADAGENT&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; gpg-connect-agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;gpg-login()&lt;/code&gt; 函数首先将 gpg 重定向到当前终端，然后对字符串 &lt;code&gt;test&lt;/code&gt; 进行签名，这个过程需要在终端中输入密码，之后密码就能被缓存下来。将上述代码添加到 &lt;code&gt;~/.bashrc&lt;/code&gt; 文件中，然后在终端输入 &lt;code&gt;gpg-login&lt;/code&gt; 就能输入并缓存密码，输入 &lt;code&gt;gpg-logout&lt;/code&gt; 则可以及时清除已经缓存的密码，避免安全隐患。&lt;/p&gt;
&lt;p&gt;gpg-agent 的缓存时间可以在 &lt;code&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt; 文件中配置，具体如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;default-cache-ttl 21600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;max-cache-ttl 21600&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数字的单位为秒，上述配置将缓存时间设置为 6 小时，基本能够满足使用需求。&lt;/p&gt;
&lt;h3 id=&quot;socket-zhong-ding-xiang&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#socket-zhong-ding-xiang&quot; aria-label=&quot;Anchor link for: socket-zhong-ding-xiang&quot;&gt;socket 重定向&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;通过 &lt;code&gt;socat&lt;/code&gt; 命令将 WSL 中的 gpg-agent socket 重定向到 Windows 下的 gpg-agent，以间接实现调用 Windows 下的各种认证服务，比如生物识别、硬件密钥等。这种方式有很多开源的解决方案，如 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/tmuntaner/wsl-gpg-agent&quot;&gt;tmuntaner/wsl-gpg-agent&lt;/a&gt;，&lt;a rel=&quot;external&quot; href=&quot;https://github.com/demonbane/wsl-gpg-systemd&quot;&gt;demonbane/wsl-gpg-systemd&lt;/a&gt; 和 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/mkulke/wsl-gpg-relay&quot;&gt;mkulke/wsl-gpg-relay&lt;/a&gt; 等，由于配置步骤较为复杂，笔者这里不再展开赘述，感兴趣的读者可以参考上述项目的具体实现。&lt;/p&gt;
&lt;h3 id=&quot;zhi-jie-diao-yong-gpg-exe&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-jie-diao-yong-gpg-exe&quot; aria-label=&quot;Anchor link for: zhi-jie-diao-yong-gpg-exe&quot;&gt;直接调用 gpg.exe&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;socket 重定向方案的目标是间接调用 Windows 下的 gpg 服务，考虑到 WSL 与宿主机在网络访问、文件系统等方面均互联互通，我们其实可以直接配置 git 使用 Windows 下的 gpg.exe：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-global&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; gpg.program&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /mnt/c/PROGRA~2/GnuPG/bin/gpg.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;笔者电脑上安装的是 gpg4win，具体路径为 &lt;code&gt;C:\Program Files (x86)\GnuPG\bin\gpg.exe&lt;/code&gt;，由于 &lt;code&gt;Program Files (x86)&lt;/code&gt; 带有空格在命令行中不方便输入，这里使用短文件名 &lt;code&gt;PROGRA~2&lt;/code&gt; 替代。&lt;/p&gt;
&lt;p&gt;这种方案相比映射 socket 省去了繁琐复杂的配置，也避免了前两个方案使用命令行回传密码带来的潜在安全隐患，同时还能够与 vscode 无缝集成，整体来看是一个不错的解决方案。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/paolocarrasco/18ca8fe6e63490ae1be23e84a7039374&quot;&gt;How to understand the &lt;code&gt;gpg failed to sign the data&lt;/code&gt; problem in git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://stackoverflow.com/questions/61939216/vscode-with-ubuntu-wsl-2-never-prompts-for-gpg-passphrase-even-after-configura&quot;&gt;vscode with ubuntu + wsl 2 never prompts for gpg passphrase even after configuration just &quot;failed to write commit data&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://askubuntu.com/questions/349238/how-can-i-clear-my-cached-gpg-password&quot;&gt;How can I clear my cached gpg password?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>pyinstaller 打包程序的解包与反编译</title>
        <published>2025-02-19T00:00:00+00:00</published>
        <updated>2025-02-19T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/pyinstaller-extract-and-decompile/"/>
        <id>https://jjl9807.com/posts/pyinstaller-extract-and-decompile/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/pyinstaller-extract-and-decompile/">&lt;p&gt;笔者今天拿到一个 pyinstaller 打包的小工具，由于程序几经流转，已无法联系作者获取源码，于是尝试从可执行程序中反编译出对应的 python 代码。&lt;/p&gt;
&lt;h2 id=&quot;jie-bao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-bao&quot; aria-label=&quot;Anchor link for: jie-bao&quot;&gt;解包&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;对于 pyinstaller 打包出来的程序，目前主流的方法是使用 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/extremecoders-re/pyinstxtractor&quot;&gt;pyinstxtractor&lt;/a&gt; 进行解包。下载 &lt;code&gt;pyinstxtractor.py&lt;/code&gt; 文件并与待解包程序放置于同一目录下，然后执行以下命令：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;python .\pyinstxtractor.py .\&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sample.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解包出的文件位于 &lt;code&gt;sample.exe_extracted&lt;/code&gt; 目录中，另外可以看到程序的入口位于 &lt;code&gt;main.pyc&lt;/code&gt; 文件中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Processing .\sample.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Pyinstaller version: 2.1+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Python version: 3.13&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Length of package: 23482162 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Found 113 files in CArchive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Beginning extraction...please standby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Possible entry point: pyiboot01_bootstrap.pyc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Possible entry point: pyi_rth_inspect.pyc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Possible entry point: pyi_rth_pkgutil.pyc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Possible entry point: pyi_rth_multiprocessing.pyc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Possible entry point: main.pyc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Found 636 files in PYZ archive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[+] Successfully extracted pyinstaller archive: .\sample.exe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;You can now use a python decompiler on the pyc files within the extracted directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于本地没有 python 环境的情况，也可以使用 &lt;a rel=&quot;external&quot; href=&quot;https://pyinstxtractor-web.netlify.app/&quot;&gt;PyInstaller Extractor WEB&lt;/a&gt; 进行在线解包。&lt;/p&gt;
&lt;h2 id=&quot;fan-bian-yi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fan-bian-yi&quot; aria-label=&quot;Anchor link for: fan-bian-yi&quot;&gt;反编译&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上面得到的 &lt;code&gt;.pyc&lt;/code&gt; 文件是 python 编译后的字节码文件，接下来还需要将其反编译。&lt;/p&gt;
&lt;p&gt;首先安装 uncompyle6：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pip install uncompyle6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;details&gt;
    &lt;summary&gt;添加系统变量&lt;/summary&gt;
    &lt;p&gt;如果运行 uncompyle6 时出现找不到命令的提示则需要将 uncomply6 安装路径添加至系统变量，笔者电脑中 python 版本为 3.12，则对应的安装路径为 &lt;code&gt;C:\Users\jjl9807\AppData\Roaming\Python\Python312\Scripts&lt;/code&gt;。&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;然后进行反编译：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;uncompyle6.exe&lt;/span&gt;&lt;span&gt; .\main.pyc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span&gt;o ..\sample.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果提示 &lt;code&gt;Unsupported Python version&lt;/code&gt;，查询资料发现 python 3.13 版本太新，uncompyle6 还暂时没有支持。后来笔者在 &lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/learnpython/comments/1ddiq3h/comment/l9cxos2/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&amp;amp;rdt=47907&quot;&gt;reddit&lt;/a&gt; 上找到了一个网站 &lt;a rel=&quot;external&quot; href=&quot;https://pylingual.io/&quot;&gt;PyLingual&lt;/a&gt; 提供在线反编译 &lt;code&gt;.pyc&lt;/code&gt; 文件的服务，实测支持 python 3.13，最终顺利拿到了反编译出的代码。&lt;/p&gt;
&lt;h2 id=&quot;xiao-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiao-jie&quot; aria-label=&quot;Anchor link for: xiao-jie&quot;&gt;小结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;实际上通过  &lt;a rel=&quot;external&quot; href=&quot;https://pyinstxtractor-web.netlify.app/&quot;&gt;PyInstaller Extractor WEB&lt;/a&gt; 和  &lt;a rel=&quot;external&quot; href=&quot;https://pylingual.io/&quot;&gt;PyLingual&lt;/a&gt; 这两个网站完全可以在本地没有 python 环境的情况下在线完成 pyinstaller 打包程序的解包与反编译，非常方便。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>多沙箱容器运行时 kuasar 安装与配置</title>
        <published>2025-01-06T00:00:00+00:00</published>
        <updated>2025-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/kuasar-build-and-install/"/>
        <id>https://jjl9807.com/posts/kuasar-build-and-install/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/kuasar-build-and-install/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/kuasar-build-and-install/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kuasar 是一款支持多种类型沙箱统一管理的容器运行时，可同时支持业界主流的多种沙箱隔离技术，例如包括基于内核的原生容器沙箱、基于轻量级虚拟化技术的 microVM 沙箱、基于进程级虚拟化的 App Kernel 沙箱，以及新兴的 WebAssembly 沙箱。&lt;/p&gt;
&lt;p&gt;目前 Kuasar 仍处于积极开发的过程中，但是 GitHub release 上的最新发布停留在 2024 年 8 月 19 日的 v1.0.0 版本，想要使用最新的版本需要自行编译，笔者在此过程中发现 Kuasar 的编译构建比较繁琐，涉及多种编程语言工具链以及复杂的传递依赖关系，于是整理详细过程形成本文，以供读者参考。&lt;/p&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;ol&gt;
&lt;li&gt;为了避免权限问题，本文所有操作均以 root 身份执行；&lt;/li&gt;
&lt;li&gt;本文所用代码版本为 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/kuasar-io/kuasar/tree/54d5d2e0742e85d9e08505fb1b5a5f6523a869ed&quot;&gt;Commit 54d5d2e&lt;/a&gt;，此后上游依赖仓库发生了较大变动，本文中部分操作可能已不再适用。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;zhun-bei-gong-zuo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhun-bei-gong-zuo&quot; aria-label=&quot;Anchor link for: zhun-bei-gong-zuo&quot;&gt;准备工作&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;an-zhuang-cargo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-cargo&quot; aria-label=&quot;Anchor link for: an-zhuang-cargo&quot;&gt;安装 cargo&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://sh.rustup.rs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sSf&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;an-zhuang-gou-jian-gong-ju&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-gou-jian-gong-ju&quot; aria-label=&quot;Anchor link for: an-zhuang-gou-jian-gong-ju&quot;&gt;安装构建工具&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;运行以下命令安装构建工具：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build-essential&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; clang&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cmake&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; unzip&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; flex&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; bison&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;an-zhuang-sha-xiang-huan-jing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-sha-xiang-huan-jing&quot; aria-label=&quot;Anchor link for: an-zhuang-sha-xiang-huan-jing&quot;&gt;安装沙箱环境&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;cloud-hypervisor&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloud-hypervisor&quot; aria-label=&quot;Anchor link for: cloud-hypervisor&quot;&gt;Cloud Hypervisor&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;直接下载预编译的二进制文件进行安装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/v43.0/cloud-hypervisor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;chmod&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; +x&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cloud-hypervisor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mv&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cloud-hypervisor&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/local/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;quark&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#quark&quot; aria-label=&quot;Anchor link for: quark&quot;&gt;Quark&lt;/a&gt;&lt;/h4&gt;
&lt;h5 id=&quot;an-zhuang-yi-lai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-yi-lai&quot; aria-label=&quot;Anchor link for: an-zhuang-yi-lai&quot;&gt;安装依赖&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Quark 是使用 Rust 语言开发的，构建之前需要安装 Rust nightly 版本，目前能正常构建 Quark 的最新 nightly 版本是 &lt;code&gt;nightly-2023-12-11-x86_64-unknown-linux-gnu&lt;/code&gt;。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rustup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; toolchain&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; nightly-2023-12-11-x86_64-unknown-linux-gnu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rustup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; default&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; nightly-2023-12-11-x86_64-unknown-linux-gnu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后将 rust-src 组件添加到当前工具链中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rustup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; component&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; add&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; rust-src&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着安装 cargo-xbuild 以进行 qkernel 交叉编译：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cargo-xbuild&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，安装 libcap 库：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libcap-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此外，还需要安装一些额外的库来编译 RDMA 模块：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; build-essential&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cmake&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; gcc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libudev-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libnl-3-dev&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libnl-route-3-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ninja-build&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; valgrind&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; python3-dev&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cython3&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;python3-docutils&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pandoc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libclang-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如有需要，可以根据 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/QuarkContainer/Quark#installing-from-source&quot;&gt;Quark 文档&lt;/a&gt; 的说明安装编译 GPU 模块所需要的依赖，笔者这里不再赘述。&lt;/p&gt;
&lt;h5 id=&quot;bian-yi-an-zhuang&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-an-zhuang&quot; aria-label=&quot;Anchor link for: bian-yi-an-zhuang&quot;&gt;编译安装&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;首先获取 Quark 源代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; git@github.com:QuarkContainer/Quark.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后运行以下命令编译安装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; Quark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;pei-zhi-yun-xing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-yun-xing&quot; aria-label=&quot;Anchor link for: pei-zhi-yun-xing&quot;&gt;配置运行&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;创建日志文件夹：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /var/log/quark&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改配置文件 &lt;code&gt;/etc/quark/config.json&lt;/code&gt;，将 &lt;code&gt;Sandboxed&lt;/code&gt; 选项设置为 &lt;code&gt;true&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;DebugLevel&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;    :&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;KernelMemSize&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 24&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;LogType&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;       :&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Sync&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;      :&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Simple&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;UringIO&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;       :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;UringBuf&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;      :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;UringFixedFile&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;EnableAIO&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;     :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;PrintException&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;KernelPagetable&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;PerfDebug&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;     :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;UringStatx&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;    :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;FileBufWrite&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;  :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;MmapRead&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;      :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;AsyncAccept&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;   :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;EnableRDMA&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;    :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;RDMAPort&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;      :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;PerSandboxLog&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;ReserveCpuCount&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;ShimMode&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;      :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;EnableInotify&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;ReaddirCache&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;  :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;HiberODirect&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;  :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;DisableCgroup&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;CopyDataWithPf&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;TlbShootdownWait&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;Sandboxed&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;确保配置文件中的 &lt;code&gt;ShimMode&lt;/code&gt; 选项为 &lt;code&gt;false&lt;/code&gt;，并且 &lt;code&gt;Sandboxed&lt;/code&gt; 选项为 true。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;wasmedge&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wasmedge&quot; aria-label=&quot;Anchor link for: wasmedge&quot;&gt;WasmEdge&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;根据 &lt;a rel=&quot;external&quot; href=&quot;https://wasmedge.org/docs/start/install/&quot;&gt;WasmEdge 文档&lt;/a&gt; 说明执行安装指令：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sSf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; bash&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;v&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;WasmEdge 要求其 C 库 (WasmEdge lib) 和 Rust SDK (wasmedge-sdk) 的版本严格对应，目前 kuasar WASM 运行时使用的 wasmedge-sdk 版本为 0.13.2，根据 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/kuasar-io/kuasar/commits/main/wasm&quot;&gt;wasmedge-sdk 文档&lt;/a&gt; WasmEdge C 库对应的版本为 0.13.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;an-zhuang-containerd&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-containerd&quot; aria-label=&quot;Anchor link for: an-zhuang-containerd&quot;&gt;安装 containerd&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kuasar 官方文档中建议安装他们维护的 containerd 以获得完整的功能体验，该版本在官方的 1.7.0 之上进行了一些定制化修改。&lt;/p&gt;
&lt;h4 id=&quot;an-zhuang-yi-lai-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-yi-lai-1&quot; aria-label=&quot;Anchor link for: an-zhuang-yi-lai-1&quot;&gt;安装依赖&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;从源代码编译安装 containerd 需要 Go 语言环境，首先从&lt;a rel=&quot;external&quot; href=&quot;https://golang.google.cn/doc/install&quot;&gt;官网&lt;/a&gt;下载预编译的二进制文件压缩包：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://golang.google.cn/dl/go1.23.4.linux-amd64.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用以下命令解压：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rm&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;rf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/local/go&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; tar&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/local&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;xzf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; go1.23.4.linux-amd64.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 &lt;code&gt;$HOME/.profile&lt;/code&gt; 中添加环境变量：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;export PATH=$PATH:/usr/local/go/bin&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.profile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后验证一下是否安装成功：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@ubuntu:~$ go version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;go version go1.23.4 linux/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;bian-yi-an-zhuang-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-an-zhuang-1&quot; aria-label=&quot;Anchor link for: bian-yi-an-zhuang-1&quot;&gt;编译安装&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;将源代码克隆至本地：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; v0.2.0-kuasar&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://github.com/kuasar-io/containerd.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行以下命令完成编译安装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; containerd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 CNI 插件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cni-plugins.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /opt/cni/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;xvzf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cni-plugins.tgz&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /opt/cni/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 runc：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; runc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;pei-zhi-yun-xing-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-yun-xing-1&quot; aria-label=&quot;Anchor link for: pei-zhi-yun-xing-1&quot;&gt;配置运行&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;运行以下命令自动生成默认配置，如果提示目录或文件不存在的话需要手动创建：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; config&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; default&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/containerd/config.toml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认配置文件中需要增加 kuasar 所用运行时的有关配置，具体如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vmm&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;proxy_plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;vmm&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  address&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/run/vmm-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;&amp;#39;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cri&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;v1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtime&amp;#39;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtimes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;kuasar-vmm&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runtime_type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;io.containerd.kuasar-vmm.v1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sandboxer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;vmm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  io_type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;streaming&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Quark&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;proxy_plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;quark&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  address&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/run/quark-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;&amp;#39;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cri&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;v1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtime&amp;#39;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtimes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;kuasar-quark&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runtime_type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;io.containerd.kuasar-quark.v1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sandboxer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;quark&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;wasm&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;proxy_plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;wasm&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  address&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/run/wasm-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;plugins&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;&amp;#39;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cri&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;v1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtime&amp;#39;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;containerd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;runtimes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;kuasar-wasm&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runtime_type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;io.containerd.kuasar-wasm.v1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sandboxer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;wasm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-important&quot;&gt;
&lt;p&gt;AppArmor 特性尚未支持，记得在配置文件中更新 &lt;code&gt;disable_apparmor = true&lt;/code&gt; 条目！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后，启动 containerd：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ENABLE_CRI_SANDBOXES=1 containerd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;details&gt;
	&lt;summary&gt;报错解决&lt;/summary&gt;
	&lt;p&gt;如果 containerd 启动时出现以下报错：&lt;/p&gt;
	&lt;img src=&quot;./no-network-config.png&quot; alt=&quot;&quot; style=&quot;zoom:80%;&quot; /&gt;
	&lt;p&gt;安装 nerdctl 后以默认配置运行任一测试容器即可消除该错误。&lt;/p&gt;
&lt;/details&gt;
&lt;h3 id=&quot;an-zhuang-crictl&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-crictl&quot; aria-label=&quot;Anchor link for: an-zhuang-crictl&quot;&gt;安装 crictl&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;crictl 是一个用于与兼容 CRI 的容器运行时交互的命令行工具，根据&lt;a rel=&quot;external&quot; href=&quot;https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md#install-crictl&quot;&gt;官方文档&lt;/a&gt;安装即可：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;v1.32.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; #&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; check latest version in releases page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://github.com/kubernetes-sigs/cri-tools/releases/download/&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/crictl-&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-linux-amd64.tar.gz&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-output&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; crictl-&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-linux-amd64.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; zxvf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; crictl-&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-linux-amd64.tar.gz&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/local/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;rm&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; crictl-&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;VERSION&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-linux-amd64.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;导入配置文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/crictl.yaml&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;runtime-endpoint: unix:///run/containerd/containerd.sock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;image-endpoint: unix:///run/containerd/containerd.sock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;timeout: 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;debug: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;pull-image-on-create: false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;an-zhuang-virtiofsd&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-virtiofsd&quot; aria-label=&quot;Anchor link for: an-zhuang-virtiofsd&quot;&gt;安装 virtiofsd&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;virtiofsd 是一个用于虚拟机和主机之间共享文件系统的守护进程，可以直接从&lt;a rel=&quot;external&quot; href=&quot;https://gitlab.com/virtio-fs/virtiofsd#building-from-sources&quot;&gt;官网&lt;/a&gt;下载预编译的二进制文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;https://gitlab.com/virtio-fs/virtiofsd/-/jobs/artifacts/main/download?job=publish&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virtiofsd.zip&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用以下命令解压安装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;unzip&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virtiofsd.zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mv&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; target/x86_64-unknown-linux-musl/release/virtiofsd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/local/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;bian-yi-yuan-ma&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-yuan-ma&quot; aria-label=&quot;Anchor link for: bian-yi-yuan-ma&quot;&gt;编译源码&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;将源码克隆至本地：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; clone&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://github.com/kuasar-io/kuasar.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译安装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; kuasar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;Guest OS 镜像需在容器里编译，所以需要提前启动 containerd 或其他容器运行时。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;笔者在编译客户机镜像时还遇到了如下的报错：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/kuasar-build-and-install/./bash-not-found.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;将 &lt;code&gt;kuasar/vmm/scripts/image/build.sh&lt;/code&gt; 脚本中 &lt;code&gt;# build rootfs in container&lt;/code&gt; 部分的 &lt;code&gt;bash&lt;/code&gt; 替换为 &lt;code&gt;/bin/bash&lt;/code&gt; 即可。&lt;/p&gt;
&lt;details&gt;
	&lt;summary&gt;其他报错&lt;/summary&gt;
	&lt;p&gt;笔者最初在 WSL 中编译时还出现了如下报错：&lt;/p&gt;
	&lt;img src=&quot;./loop-device-failed.png&quot; alt=&quot;&quot; style=&quot;zoom:50%;&quot;/&gt;
	&lt;p&gt;经过反复尝试后最终通过转战 VMware 虚拟机解决。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id=&quot;yun-xing-yu-ce-shi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yun-xing-yu-ce-shi&quot; aria-label=&quot;Anchor link for: yun-xing-yu-ce-shi&quot;&gt;运行与测试&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;qi-dong-kuasar&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-dong-kuasar&quot; aria-label=&quot;Anchor link for: qi-dong-kuasar&quot;&gt;启动 kuasar&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用以下命令启动 kuasar：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vmm&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;nohup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; vmm-sandboxer&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-listen&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /run/vmm-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /run/kuasar-vmm&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;quark&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;nohup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; quark-sandboxer&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-listen&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /run/quark-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /var/lib/kuasar-quark&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;wasm&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;nohup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wasm-sandboxer&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-listen&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /run/wasm-sandboxer.sock&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-dir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /run/kuasar-wasm&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-ce-shi-rong-qi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yun-xing-ce-shi-rong-qi&quot; aria-label=&quot;Anchor link for: yun-xing-ce-shi-rong-qi&quot;&gt;运行测试容器&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;由于 Kuasar 属于低阶容器运行时，所有交互都应通过 containerd 中的 CRI 完成，例如 crictl 或 Kubernetes，这里笔者用的是上文已经安装过的 crictl。&lt;/p&gt;
&lt;p&gt;Kuasar 仓库已经提供了启动测试容器的脚本，直接运行即可：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; For vmm, quark or runc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; NOTE: The &amp;#39;&amp;lt;runtime&amp;gt;` option should be kuasar-vmm, kuasar-quark or kuasar-runc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;./examples/run_example_container.sh&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;runtim&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; For wasm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; NOTE: Wasm container needs its own container image so the script has to build and import the container image at first.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;./examples/run_example_wasm_container.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://kuasar.io/docs/developer/build&lt;/li&gt;
&lt;li&gt;https://bbs.huaweicloud.com/blogs/405617&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>rk8s</title>
        <published>2025-01-06T00:00:00+00:00</published>
        <updated>2025-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/projects/rk8s/"/>
        <id>https://jjl9807.com/projects/rk8s/</id>
        
        <content type="html" xml:base="https://jjl9807.com/projects/rk8s/"></content>
        
    </entry>
    <entry xml:lang="en">
        <title>阿里云服务器从 Debian 11 升级 Debian 12</title>
        <published>2024-11-28T00:00:00+00:00</published>
        <updated>2024-11-28T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/upgrade-debian-11-to-12/"/>
        <id>https://jjl9807.com/posts/upgrade-debian-11-to-12/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/upgrade-debian-11-to-12/">&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;笔者近期在阿里云上购买了一台 2c/2g 的轻量应用服务器，在配置界面发现阿里云提供的服务器镜像中 Debian 系统的版本还停留在 11.3，出于系统安全和个人习惯考虑，笔者决定先安装 Debian 11.3，再设法升级到最新的稳定版 Debian 12.8。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./aliyun-image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;笔者本来准备使用&lt;a href=&quot;https://jjl9807.com/posts/install-linux-with-network-bootloader/&quot;&gt;之前博客&lt;/a&gt;中介绍过的 iPXE 给服务器重装系统，但是在查询 Debian 12 发行手册的时候发现其中提供了从 Debian 11 手动升级的详细说明，遂决定一试。&lt;/p&gt;
&lt;h2 id=&quot;sheng-ji-bu-zou&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#sheng-ji-bu-zou&quot; aria-label=&quot;Anchor link for: sheng-ji-bu-zou&quot;&gt;升级步骤&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先，运行以下命令将 Debian 11 更新到最新版本：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; full-upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; autoremove&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，记录一下系统当前的版本信息：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./uname.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;使用以下命令妥善备份 apt 配置文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cp&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/apt/sources.list&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/backup/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cp&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;vr&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/apt/sources.list.d/&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/backup/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开 &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; 文件，以下是修改之前的文件内容：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./sources.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;使用 Debian 12 的发行代号 &lt;code&gt;bookworm&lt;/code&gt; 替换文件中的 &lt;code&gt;bullseye&lt;/code&gt;，并在原有条目末尾新增 &lt;code&gt;non-free-firmware&lt;/code&gt; 仓库，修改后的 &lt;code&gt;sources.list&lt;/code&gt; 文件内容如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb http://mirrors.cloud.aliyuncs.com/debian/ bookworm main contrib non-free non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb http://mirrors.cloud.aliyuncs.com/debian/ bookworm-updates main contrib non-free non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb http://mirrors.cloud.aliyuncs.com/debian/ bookworm-backports main non-free contrib non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb-src http://mirrors.cloud.aliyuncs.com/debian/ bookworm-updates main contrib non-free non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb-src http://mirrors.cloud.aliyuncs.com/debian/ bookworm main contrib non-free non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb-src http://mirrors.cloud.aliyuncs.com/debian/ bookworm-backports main contrib non-free non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb http://mirrors.cloud.aliyuncs.com/debian-security/ bookworm-security main non-free contrib non-free-firmware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb-src http://mirrors.cloud.aliyuncs.com/debian-security/ bookworm-security main non-free contrib non-free-firmware&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行以下命令开始升级：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; full-upgrade&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;升级过程中可能会出现类似下图的配置界面：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./package-configuration.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;仔细阅读说明后根据实际情况选择，大部分情况下直接保留原有配置或使用默认选项即可。&lt;/p&gt;
&lt;h2 id=&quot;yan-zheng-yu-qing-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yan-zheng-yu-qing-li&quot; aria-label=&quot;Anchor link for: yan-zheng-yu-qing-li&quot;&gt;验证与清理&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;升级完成后重启系统，再次查看系统版本信息以验证是否升级成功：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./uname-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;可以看到我们成功从 Debian 11.11 升级到了最新的稳定版 Debian 12.8，内核版本也升级到了 Debian 6.1.0。确认升级成功后运行 &lt;code&gt;sudo apt --purge autoremove&lt;/code&gt; 命令清理不必要的软件包以及之前升级过程中产生的临时文件：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/upgrade-debian-11-to-12/./autoremove.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最后，对于经常使用阿里云的用户，可以基于服务器的当前状态创建自定义镜像以用作 Debian 12.8 系统的基础镜像。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://www.debian.org/releases/bookworm/amd64/release-notes/ch-upgrading.zh-cn.html&lt;/li&gt;
&lt;li&gt;https://www.debugpoint.com/upgrade-debian-12-from-debian-11/&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ubuntu 通过 SSH 端口转发使用本机代理上网</title>
        <published>2024-10-30T00:00:00+00:00</published>
        <updated>2024-10-30T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/forward-local-proxy-with-ssh/"/>
        <id>https://jjl9807.com/posts/forward-local-proxy-with-ssh/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/forward-local-proxy-with-ssh/">&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上周，笔者在一台 Ubuntu 18.04 的训练服务器上创建 Python 环境时，遇到了如下报错：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/forward-local-proxy-with-ssh/./connection-failed.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;尝试为 anaconda 配置镜像源后，该报错没有任何变化，遂怀疑服务器处于断网环境，使用 &lt;code&gt;ping&lt;/code&gt; 和 &lt;code&gt;nslookup&lt;/code&gt; 指令检查网络连通性，发现服务器 DNS 服务异常。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/forward-local-proxy-with-ssh/./dns-error.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;由于笔者并没有服务器的管理员权限，无法修改网络相关的配置，因此只能考虑 “曲线救国”，通过 SSH 隧道将本地代理服务端口转发到服务器上，这样服务器就可以通过 SSH 隧道访问互联网。&lt;/p&gt;
&lt;h2 id=&quot;zhuan-fa-ben-di-dai-li-duan-kou&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhuan-fa-ben-di-dai-li-duan-kou&quot; aria-label=&quot;Anchor link for: zhuan-fa-ben-di-dai-li-duan-kou&quot;&gt;转发本地代理端口&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先在本地机器上启动代理，这里笔者使用 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/clash-verge-rev/clash-verge-rev&quot;&gt;Clash Verge Rev&lt;/a&gt; 在 7897 端口开了一个 Direct 模式的代理服务。然后使用以下命令连接服务器：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ssh&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 7890:localhost:7897&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;usernam&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;servr_i&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;-R&lt;/code&gt; 参数表示远程端口转发，即通过 SSH 隧道把服务器 7890 端口的流量转发到本地的 7897 端口。&lt;/p&gt;
&lt;h2 id=&quot;fu-wu-qi-duan-dai-li-pei-zhi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fu-wu-qi-duan-dai-li-pei-zhi&quot; aria-label=&quot;Anchor link for: fu-wu-qi-duan-dai-li-pei-zhi&quot;&gt;服务器端代理配置&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;zhong-duan-dai-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhong-duan-dai-li&quot; aria-label=&quot;Anchor link for: zhong-duan-dai-li&quot;&gt;终端代理&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;服务器端可以通过设置 &lt;code&gt;http_proxy&lt;/code&gt; 和 &lt;code&gt;https_proxy&lt;/code&gt; 环境变量来配置代理的使用：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; http_proxy&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;://&lt;/span&gt;&lt;span&gt;localhost&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;7890&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; https_proxy&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;http_proxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; ftp_proxy&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;http_proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的指令效果是临时的，为了方便也可以将其写入 &lt;code&gt;.bsshrc&lt;/code&gt; 文件。如果选择后者，记得使用 &lt;code&gt;source .bashrc&lt;/code&gt; 更新配置。&lt;/p&gt;
&lt;h3 id=&quot;conda-dai-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conda-dai-li&quot; aria-label=&quot;Anchor link for: conda-dai-li&quot;&gt;conda 代理&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;除了命令行，conda 也需要单独配置代理服务，具体而言，需要在 &lt;code&gt;.condarc&lt;/code&gt; 配置文件中新增如下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;roxy_servers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;  h&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;ttp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;ttp://localhost:7890&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;  h&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;ttps&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;    h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;ttp://localhost:7890&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以运行以下命令来检查配置是否生效：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;conda&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-show&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; proxy_servers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jie-yu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-yu&quot; aria-label=&quot;Anchor link for: jie-yu&quot;&gt;结语&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;至此，我们已经完成了所需的全部配置，现在服务器上的流量能够通过 SSH 隧道转发到本地代理从而实现网络访问。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>解决 Vmware Kernel Module Updater 报错</title>
        <published>2024-10-09T00:00:00+00:00</published>
        <updated>2024-10-09T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-vmware-kernel-module-error/"/>
        <id>https://jjl9807.com/posts/resolve-vmware-kernel-module-error/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-vmware-kernel-module-error/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linux 内核更新后启动 Vmware Workstation 出现以下提示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/resolve-vmware-kernel-module-error/./kernel-headers-not-found.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;其中 “Kernel headers for version 6.1.0-25-amd64 were not found” 提示没有找到与更新后的版本对应的内核头文件。&lt;/p&gt;
&lt;h2 id=&quot;yuan-yin-fen-xi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-yin-fen-xi&quot; aria-label=&quot;Anchor link for: yuan-yin-fen-xi&quot;&gt;原因分析&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linux 版本的 Vmware Workstation 用到了大量的内核接口，因此运行前需要根据当前内核版本编译对应的模块，系统内核更新后对应的头文件并不会自动更新，因此启动 Vmware Workstation 时由于找不到新版本的内核头文件无法更新相应模块。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用以下命令安装与当前内核版本对应的头文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; linux-headers-&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;uname&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;r&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://wiki.vi-toolkit.com/index.php/Build_host_vmware_kernel_modules&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust Security Best Practices</title>
        <published>2024-09-15T00:00:00+00:00</published>
        <updated>2024-09-15T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/talks/rust-security-best-practices/"/>
        <id>https://jjl9807.com/talks/rust-security-best-practices/</id>
        
        <content type="html" xml:base="https://jjl9807.com/talks/rust-security-best-practices/">&lt;p&gt;This talk covers essential security practices for Rust developers, including how to leverage Rust&#39;s type system for security, managing unsafe code, and auditing dependencies.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>WSL 更新失败 (退出代码: 1603) 解决方案</title>
        <published>2024-08-09T00:00:00+00:00</published>
        <updated>2024-08-09T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-wsl-update-failure-1603/"/>
        <id>https://jjl9807.com/posts/resolve-wsl-update-failure-1603/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-wsl-update-failure-1603/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;wsl --update --web-download&lt;/code&gt; 命令升级 WSL，出现以下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PS C:\Users\jjl9807&amp;gt; wsl --update --web-download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;正在检查更新。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;正在将适用于 Linux 的 Windows 子系统更新到版本： 2.2.4。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Could not write value  to key \SOFTWARE\Classes\Directory\shell\WSL.   Verify that you have sufficient access to that key, or contact your support personnel.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;更新失败(退出代码: 1603)。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;日志文件: C:\Users\jjl98\AppData\Local\Temp\wsl-install-logs.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Error code: Wsl/UpdatePackage/ERROR_INSTALL_FAILURE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;笔者所用 WSL 版本如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PS C:\Users\jjl9807&amp;gt; wsl -v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WSL 版本： 2.1.5.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;内核版本： 5.15.146.1-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WSLg 版本： 1.0.60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MSRDC 版本： 1.2.5105&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Direct3D 版本： 1.611.1-81528511&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DXCore 版本： 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Windows 版本： 10.0.19045.4651&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;打开注册表编辑器，将以下注册表项删除或重命名后再次尝试升级即可：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_CLASSES_ROOT\Drive\shell\WSL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_CLASSES_ROOT\Directory\Background\shell\WSL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_CLASSES_ROOT\Directory\shell\WSL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于系统版本的不同，以上注册表项的具体路径也有可能是下面这样：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Drive\shell\WSL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\WSL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\WSL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/microsoft/WSL/issues/11697&quot;&gt;Could not write value to key \SOFTWARE\Classes\Drive\shell\WSL · Issue #11697 · microsoft/WSL (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://answers.microsoft.com/zh-hans/windows/forum/all/wsl-install/cd18be19-e2fb-4173-82ad-c5a7600fc18e&quot;&gt;wsl --install 报错：灾难性故障 - Microsoft Community&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building Lightning-Fast Static Sites with Zola</title>
        <published>2024-06-22T00:00:00+00:00</published>
        <updated>2024-06-22T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/talks/building-fast-static-sites/"/>
        <id>https://jjl9807.com/talks/building-fast-static-sites/</id>
        
        <content type="html" xml:base="https://jjl9807.com/talks/building-fast-static-sites/">&lt;p&gt;An introduction to Zola and static site generation, demonstrating how to achieve sub-second build times and perfect Lighthouse scores.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>IEDA 配置 Hadoop 项目开发</title>
        <published>2024-05-20T00:00:00+00:00</published>
        <updated>2024-05-20T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/develop-hadoop-project-with-idea/"/>
        <id>https://jjl9807.com/posts/develop-hadoop-project-with-idea/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/develop-hadoop-project-with-idea/">&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文假设读者已经在 WSL (Ubuntu 22.04) 环境下完成了 Hadoop 单机伪分布式安装，如果尚未完成，可以参考&lt;a href=&quot;https://jjl9807.com/posts/pseudo-distributed-hadoop-install-in-wsl/&quot;&gt;这篇博客&lt;/a&gt;。笔者使用 IDEA Ultimate 2024.1.1 进行远程开发，IEDA 不同版本的安装过程和操作 UI 可能有些许不同，具体请参照&lt;a rel=&quot;external&quot; href=&quot;https://www.jetbrains.com/help/idea/getting-started.html&quot;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&quot;xin-jian-maven-xiang-mu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xin-jian-maven-xiang-mu&quot; aria-label=&quot;Anchor link for: xin-jian-maven-xiang-mu&quot;&gt;新建 Maven 项目&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;点击窗口左上角 “文件-新建-项目”，按照下图标注创建一个 Maven 示例项目。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/develop-hadoop-project-with-idea/./new-project.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;pei-zhi-xiang-mu-yi-lai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-xiang-mu-yi-lai&quot; aria-label=&quot;Anchor link for: pei-zhi-xiang-mu-yi-lai&quot;&gt;配置项目依赖&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;等待项目初始化并加载完毕后，打开 &lt;code&gt;pom.xml&lt;/code&gt; 文件配置项目依赖。如果你的开发情境与笔者类似，可以将 &lt;code&gt;pom.xml&lt;/code&gt; 直接复制替换为本文末尾给出的配置文件。&lt;/p&gt;
&lt;p&gt;首先，自定义项目信息并修改项目属性为以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;UTF-8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.source&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.source&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.target&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.target&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;3.3.6&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;这里的 &lt;code&gt;hadoop.version&lt;/code&gt; 需要与运行环境中的 Hadoop 版本一致！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后，添加 Hadoop 相关的依赖：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-common&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-hdfs&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-mapreduce-client-core&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-client&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于本地环境与集群环境 Hadoop 版本不一致的情况，可以通过添加 profile 解决，具体配置如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profiles&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profile&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;id&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;Cluster&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;id&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;3.2.1&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profile&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profiles&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，点击窗口右上角的刷新按钮更新项目配置。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/develop-hadoop-project-with-idea/./load-changes.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;bian-xie-dai-ma&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-xie-dai-ma&quot; aria-label=&quot;Anchor link for: bian-xie-dai-ma&quot;&gt;编写代码&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;完成以上配置后，就可以开始在项目的 &lt;code&gt;src/main/java&lt;/code&gt; 目录下添加代码文件了。&lt;/p&gt;
&lt;h2 id=&quot;xiang-mu-da-bao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiang-mu-da-bao&quot; aria-label=&quot;Anchor link for: xiang-mu-da-bao&quot;&gt;项目打包&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;完成代码编写后，按照下图标注进行打包，如果前面配置了 profile，按需勾选即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/develop-hadoop-project-with-idea/./packaging.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果打包成功，输出日志应该与下面类似：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] Building jar: /home/jjl9807/Dev/lab2/target/lab2-1.0.jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] ------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] BUILD SUCCESS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] ------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] Total time:  1.415 s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] Finished at: 2024-05-20T19:19:50+08:00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[INFO] ------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打包好的 JAR 包位于项目的 &lt;code&gt;target&lt;/code&gt; 目录下，拷贝到运行环境就可以执行了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/develop-hadoop-project-with-idea/./target.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;pom-xml-shi-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pom-xml-shi-li&quot; aria-label=&quot;Anchor link for: pom-xml-shi-li&quot;&gt;pom.xml 示例&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;最后，给出一份笔者自己使用的项目配置：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; xmlns&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;http://maven.apache.org/POM/4.0.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    xmlns&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;xsi&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; xsi&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;schemaLocation&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;modelVersion&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;4.0.0&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;modelVersion&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.example&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;lab2&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;packaging&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;jar&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;packaging&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;lab2&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;url&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;http://maven.apache.org&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;url&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;UTF-8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.source&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.source&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.target&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;maven.compiler.target&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;3.3.6&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profiles&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profile&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;id&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;Cluster&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;id&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;3.2.1&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;hadoop.version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;properties&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profile&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;profiles&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependencies&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-common&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-hdfs&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-mapreduce-client-core&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;org.apache.hadoop&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;groupId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop-client&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;artifactId&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;${hadoop.version}&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;version&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependency&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;dependencies&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;project&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>WSL 网络异常排查经过</title>
        <published>2024-04-24T00:00:00+00:00</published>
        <updated>2024-04-24T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-wsl-dns-error/"/>
        <id>https://jjl9807.com/posts/resolve-wsl-dns-error/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-wsl-dns-error/">&lt;h2 id=&quot;gu-zhang-fa-xian&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gu-zhang-fa-xian&quot; aria-label=&quot;Anchor link for: gu-zhang-fa-xian&quot;&gt;故障发现&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;今天更新了 WSL 版本后发现不能上网，更新后的版本如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PS C:\Users\jjl9807&amp;gt; wsl -v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WSL 版本： 2.1.5.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;内核版本： 5.15.146.1-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WSLg 版本： 1.0.60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MSRDC 版本： 1.2.5105&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Direct3D 版本： 1.611.1-81528511&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DXCore 版本： 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Windows 版本： 10.0.19045.4291&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更新完成后启动 Debian，使用 &lt;code&gt;sudo apt update&lt;/code&gt; 命令检查软件更新，出现如下报错：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;错误:1 https://security.debian.org/debian-security bookworm-security InRelease&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  暂时不能解析域名“security.debian.org”&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;ping -c 4 baidu.com&lt;/code&gt; 检查网络连通性，结果如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ping&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ping:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; baidu.com:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 域名解析暂时失败&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;初步确定 WSL 的域名解析出现问题，使用 &lt;code&gt;nslookup baidu.com&lt;/code&gt; 查看百度域名的 DNS 查询结果：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; nslookup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; communications&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; error&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 172.18.32.1#53:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; timed&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; communications&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; error&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 172.18.32.1#53:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; timed&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; communications&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; error&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 172.18.32.1#53:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; timed&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; no&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; servers&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; could&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; be&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; reached&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到多次查询均以超时告终，确定 WSL 的 DNS 服务发生异常。&lt;/p&gt;
&lt;h2 id=&quot;pai-cha-guo-cheng&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pai-cha-guo-cheng&quot; aria-label=&quot;Anchor link for: pai-cha-guo-cheng&quot;&gt;排查过程&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;jian-cha-wang-luo-lian-tong-xing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-cha-wang-luo-lian-tong-xing&quot; aria-label=&quot;Anchor link for: jian-cha-wang-luo-lian-tong-xing&quot;&gt;检查网络连通性&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;首先确认主机网络情况，主机使用的是路由器 &lt;code&gt;192.168.1.1&lt;/code&gt; 提供的 DNS 服务，网络访问一切正常。&lt;/p&gt;
&lt;p&gt;接着，由于 WSL 默认配置的 DNS 服务器就是主机地址，因此需要检查主机与 WSL 之间的连通性：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PS C:\Users\jjl9807&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; ping &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;正在 Ping &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 具有 &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt; 字节的数据:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;来自 &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 的回复: 字节&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt; 时间&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;1ms TTL&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;来自 &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 的回复: 字节&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt; 时间&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;1ms TTL&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;来自 &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 的回复: 字节&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt; 时间&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;1ms TTL&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;来自 &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 的回复: 字节&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt; 时间&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;1ms TTL&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;172.18&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32.168&lt;/span&gt;&lt;span&gt; 的 Ping 统计信息:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    数据包: 已发送 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span&gt;，已接收 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span&gt;，丢失 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span&gt; 丢失&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;往返行程的估计时间&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;以毫秒为单位&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    最短 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; 0ms，最长 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; 0ms，平均 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; 0ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现主机到 WSL 只能单向连通：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ping&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 172.18.32.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;PING&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 172.18.32.1&lt;/span&gt;&lt;span&gt; (172.18.32.1&lt;/span&gt;&lt;span&gt;) 56(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;84&lt;/span&gt;&lt;span&gt;) bytes of data.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 172.18.32.1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ping&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; statistics&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; packets&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; transmitted,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; received,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 100%&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; packet&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; loss,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; time&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 3120ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里怀疑是 Windows 防火墙策略设置问题，在管理员模式下使用以下指令为 WSL 添加入站策略：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;New-NetFirewallRule&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span&gt;DisplayName &lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;WSL&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span&gt;Direction Inbound  &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span&gt;InterfaceAlias &lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;vEthernet (WSL)&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;  -&lt;/span&gt;&lt;span&gt;Action Allow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再次检查，发现主机与 WSL 已经双向联通，但是 DNS 异常的问题依旧存在。&lt;/p&gt;
&lt;h3 id=&quot;jian-cha-dns-pei-zhi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-cha-dns-pei-zhi&quot; aria-label=&quot;Anchor link for: jian-cha-dns-pei-zhi&quot;&gt;检查 DNS 配置&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;首先查看 WSL 的 DNS 配置：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cat&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/resolv.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; [network]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; generateResolvConf = false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;nameserver&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 172.18.32.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过注释可以发现 DNS 配置是 WSL 自动生成的，默认设置主机为 DNS 服务器。接着使用以下命令查看 WSL 能否正常使用路由器提供的 DNS 服务：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; nslookup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; baidu.com&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 192.168.1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Server:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;         192.168.1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;        192.168.1.1#53&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;   baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 110.242.68.66&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;   baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 39.156.66.10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现系统能够正常使用路由器提供的 DNS 服务，查看主机 53 号端口确认主机并没有提供或转发 DNS 服务，显然问题就出在 WSL 的默认 DNS 配置上。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;fang-an-yi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fang-an-yi&quot; aria-label=&quot;Anchor link for: fang-an-yi&quot;&gt;方案一&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这里可以按照 &lt;code&gt;/etc/resolv.conf&lt;/code&gt; 文件注释中提示的那样设置 &lt;code&gt;/etc/wsl.conf&lt;/code&gt; 文件并且手动指定 DNS 服务器地址，但是很不优雅，在安装了多个 Linux 发行版或者主机网络环境变化的情况下需要重复配置。&lt;/p&gt;
&lt;h3 id=&quot;fang-an-er&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fang-an-er&quot; aria-label=&quot;Anchor link for: fang-an-er&quot;&gt;方案二&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;通过查询 &lt;a rel=&quot;external&quot; href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/wsl-config&quot;&gt;WSL 配置文档&lt;/a&gt;发现 WSL 2 提供了 &lt;code&gt;dnsProxy&lt;/code&gt; 配置项：默认为 &lt;code&gt;true&lt;/code&gt;，在 NAT 模式下将 Linux 中的 DNS 服务器配置为主机上的 NAT。 设置为 &lt;code&gt;false&lt;/code&gt; 会将 DNS 服务器从 Windows 镜像到 Linux。&lt;/p&gt;
&lt;p&gt;因此，在 &lt;code&gt;%UserProfile%&lt;/code&gt; 目录下创建 &lt;code&gt;.wslconfig&lt;/code&gt; 文件并写入以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Settings apply across all Linux distros running on WSL 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;wsl2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;dnsProxy&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重启 WSL，发现 Linux 已经和主机使用相同的 DNS 服务器，域名解析和网络访问恢复正常：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@debian:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; nslookup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Server:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;         192.168.1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;        192.168.1.1#53&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;   baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 39.156.66.10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;   baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 110.242.68.66&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>WSL 配置 Hadoop 单机伪分布式安装</title>
        <published>2024-04-18T00:00:00+00:00</published>
        <updated>2024-04-18T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/pseudo-distributed-hadoop-install-in-wsl/"/>
        <id>https://jjl9807.com/posts/pseudo-distributed-hadoop-install-in-wsl/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/pseudo-distributed-hadoop-install-in-wsl/">&lt;h2 id=&quot;an-zhuang-ubuntu-22-04&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-ubuntu-22-04&quot; aria-label=&quot;Anchor link for: an-zhuang-ubuntu-22-04&quot;&gt;安装 Ubuntu 22.04&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先根据&lt;a rel=&quot;external&quot; href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/install&quot;&gt;微软文档&lt;/a&gt;安装 WSL，然后使用如下指令安装 Ubuntu 22.04：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;wsl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span&gt;install &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span&gt;distribution Ubuntu&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;22.04&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 ssh 和 rsync：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt-get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ssh&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; rsync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;an-zhuang-java-8&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-java-8&quot; aria-label=&quot;Anchor link for: an-zhuang-java-8&quot;&gt;安装 Java 8&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;前往&lt;a rel=&quot;external&quot; href=&quot;https://www.oracle.com/cn/java/technologies/javase/javase8u211-later-archive-downloads.html&quot;&gt;官网&lt;/a&gt;下载 JDK 8，创建安装目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将二进制文件解压至安装目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; tar&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;zxf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; jdk-8u401-linux-x64.tar.gz&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/java/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;an-zhuang-hadoop-3-3-6&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-hadoop-3-3-6&quot; aria-label=&quot;Anchor link for: an-zhuang-hadoop-3-3-6&quot;&gt;安装 Hadoop 3.3.6&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;前往&lt;a rel=&quot;external&quot; href=&quot;https://hadoop.apache.org/&quot;&gt;官网&lt;/a&gt;下载 Hadoop 3.3.6，创建安装目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/hadoop_installs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将下载的压缩包移动到上述目录后解压：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;tar&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;zxvf&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; hadoop-3.3.6.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;pei-zhi-huan-jing-bian-liang&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-huan-jing-bian-liang&quot; aria-label=&quot;Anchor link for: pei-zhi-huan-jing-bian-liang&quot;&gt;配置环境变量&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;编辑 &lt;code&gt;.bashrc&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;nano&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在文件末尾添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Set up Hadoop and Java&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; JAVA_HOME&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;usr&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;jdk1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;0_401&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; JRE_HOME&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;JAVA_HOME&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;jre&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; HADOOP_HOME&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;hadoop_installs&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;hadoop-3&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;JAVA_HOME&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;bin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;HADOOP_HOME&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;bin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;HADOOP_HOME&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;sbin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;PATH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; CLASSPATH&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;JAVA_HOME&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;JRE_HOME&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使上述修改即刻生效：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;向系统注册 JDK：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; update-alternatives&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/bin/java&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; java&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /usr/java/jdk1.8.0_401/bin/java&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 300&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 java 版本，预期结果如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@ubuntu:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; java&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;1.8.0_401&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Java(TM&lt;/span&gt;&lt;span&gt;) SE Runtime Environment (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 1.8.0_401-b10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Java&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; HotSpot&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;TM&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 64-Bit&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; Server&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; VM&lt;/span&gt;&lt;span&gt; (build&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 25.401-b10,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; mixed&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; mode&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;pei-zhi-ssh-mi-yao-fang-wen&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-ssh-mi-yao-fang-wen&quot; aria-label=&quot;Anchor link for: pei-zhi-ssh-mi-yao-fang-wen&quot;&gt;配置 SSH 密钥访问&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建密钥：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; rsa&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_rsa&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加密钥：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/id_rsa.pub&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;chmod&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0600&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试连接：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ssh&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; localhost&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;pei-zhi-hadoop&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pei-zhi-hadoop&quot; aria-label=&quot;Anchor link for: pei-zhi-hadoop&quot;&gt;配置 Hadoop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hadoop 的配置文件存放在安装目录下的 &lt;code&gt;etc/hadoop&lt;/code&gt; 目录中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;cd&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span&gt;HADOOP_HOME&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/etc/hadoop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改 &lt;code&gt;hadoop-env.sh&lt;/code&gt; 文件中以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;export&lt;/span&gt;&lt;span&gt; JAVA_HOME&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;usr&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;jdk1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;0_401&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改 core-site.xml，添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;fs.defaultFS&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hdfs://localhost:9000&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;hadoop.work.dir&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;/home/jjl9807/hadoop_tmp&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;请将上面的 &lt;code&gt;/home/jjl9807/hadoop_tmp&lt;/code&gt; 调整为你自己设定的 Hadoop 工作路径！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;修改 hdfs-site.xml，添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;dfs.replication&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改 mapred-site.xml，添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;mapreduce.framework.name&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;yarn&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;mapreduce.application.classpath&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/etc/hadoop,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/common/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/common/lib/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/hdfs/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/hdfs/lib/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/mapreduce/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/mapreduce/lib/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/yarn/*,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            $HADOOP_HOME/share/hadoop/yarn/lib*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改 yarn-site.xml，添加以下内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;yarn.nodemanager.aux-services&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;mapreduce_shuffle&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;yarn.nodemanager.env-whitelist&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;Value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;Value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;property&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;configuration&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;qi-dong-hadoop&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-dong-hadoop&quot; aria-label=&quot;Anchor link for: qi-dong-hadoop&quot;&gt;启动 Hadoop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;格式化 NameNode：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; namenode&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;format&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;切勿多次格式化！如果需要重新格式化，必须要删除后重新创建前面指定的工作目录。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;启动 NameNode daemon 和 DataNode daemon：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;start-dfs.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看集群状态，输出结果应与如下内容相近：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl807@ubuntu:~/$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; jps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;200918&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; DataNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;201142&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; SecondaryNameNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;200746&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; NameNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;201342&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; Jps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以通过 http://localhost:9870 访问 HDFS NameNode 的 Web 接口。&lt;/p&gt;
&lt;p&gt;启动 ResourceManage daemon 和 NodeManage daemon：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;start-yarn.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再次查看集群状态，输出结果应与如下内容相近：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl807@ubuntu:~/$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; jps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;200918&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; DataNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;201142&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; SecondaryNameNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;226890&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; Jps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;200746&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; NameNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;226334&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ResourceManager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;226493&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; NodeManager&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以通过 http://localhost:8088 访问 Resource Manager 的 Web 接口。&lt;/p&gt;
&lt;h2 id=&quot;yun-xing-shi-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yun-xing-shi-li&quot; aria-label=&quot;Anchor link for: yun-xing-shi-li&quot;&gt;运行示例&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建执行 MapReduce 作业的 HDFS 目录：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dfs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dfs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /user/jjl9807&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dfs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test-in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面第三条命令在当前用户工作目录下创建，省略了 &lt;code&gt;/user/&amp;lt;username&amp;gt;&lt;/code&gt;，直接使用了相对路径。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;./test&lt;/code&gt; 文件夹中创建以下两个文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;file1.txt:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; hello&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; hadoop&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; hello&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;file2.txt:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; goodbye&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; hadoop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拷贝输入文件至分布式文件系统：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dfs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;.txt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test-in&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 Hadoop 自带的 MapReduce 示例：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hadoop&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; jar&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span&gt;HADOOP_HOME&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; wordcount&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test-in&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test-out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Hadoop 正常运行，部分输出日志应与如下内容相近：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:03,769 INFO mapreduce.Job: Running job: job_1713438748713_0002&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:08,819 INFO mapreduce.Job: Job job_1713438748713_0002 running in uber mode : false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:08,820 INFO mapreduce.Job:  map 0% reduce 0%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:12,855 INFO mapreduce.Job:  map 100% reduce 0%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:15,867 INFO mapreduce.Job:  map 100% reduce 100%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:16,877 INFO mapreduce.Job: Job job_1713438748713_0002 completed successfully&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-04-18 19:14:16,927 INFO mapreduce.Job: Counters: 54&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将 HDFS 的输出文件拷贝至本地文件系统：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hdfs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; dfs&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test-out&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; output&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看输出结果，预期内容如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;jjl9807@ubuntu:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; cat&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; output/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;goodbye&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hadoop&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;   2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;   1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Debugging Kernel Drivers: Tools and Techniques</title>
        <published>2024-03-10T00:00:00+00:00</published>
        <updated>2024-03-10T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/talks/debugging-kernel-drivers/"/>
        <id>https://jjl9807.com/talks/debugging-kernel-drivers/</id>
        
        <content type="html" xml:base="https://jjl9807.com/talks/debugging-kernel-drivers/">&lt;p&gt;This talk demonstrates advanced debugging workflows for kernel driver development, including live kernel debugging, crash dump analysis, and performance profiling.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git 报错“克隆成功，但是检出失败”解决方案</title>
        <published>2023-11-22T00:00:00+00:00</published>
        <updated>2023-11-22T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/resolve-git-checkout-error/"/>
        <id>https://jjl9807.com/posts/resolve-git-checkout-error/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/resolve-git-checkout-error/">&lt;h2 id=&quot;wen-ti-miao-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti-miao-shu&quot; aria-label=&quot;Anchor link for: wen-ti-miao-shu&quot;&gt;问题描述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;执行 &lt;code&gt;git clone&lt;/code&gt; 命令时出现以下报错:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;警告：克隆成功，但是检出失败。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;您可以通过 &amp;#39;git status&amp;#39; 检查哪些已被检出，然后使用命令&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;#39;git restore --source=HEAD :/&amp;#39; 重试&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;已经排除网络连接问题。&lt;/p&gt;
&lt;h2 id=&quot;yuan-yin-fen-xi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-yin-fen-xi&quot; aria-label=&quot;Anchor link for: yuan-yin-fen-xi&quot;&gt;原因分析&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;文件名称或者路径过长导致无法检出工作树。&lt;/p&gt;
&lt;h2 id=&quot;jie-jue-fang-an&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue-fang-an&quot; aria-label=&quot;Anchor link for: jie-jue-fang-an&quot;&gt;解决方案&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-system&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; core.longpaths&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Introduction to WebAssembly</title>
        <published>2023-11-05T00:00:00+00:00</published>
        <updated>2023-11-05T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/talks/intro-to-webassembly/"/>
        <id>https://jjl9807.com/talks/intro-to-webassembly/</id>
        
        <content type="html" xml:base="https://jjl9807.com/talks/intro-to-webassembly/">&lt;p&gt;A beginner-friendly introduction to WebAssembly, showing how to compile Rust code to run in the browser and achieve near-native performance for compute-intensive tasks.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 机器创建及初始化机制简析</title>
        <published>2023-09-24T00:00:00+00:00</published>
        <updated>2023-09-24T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-machine-create/"/>
        <id>https://jjl9807.com/posts/qemu-system-machine-create/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-machine-create/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-machine-create/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 是一个通用的、开源的模拟器，能够通过纯软件方式实现硬件的虚拟化，模拟外部硬件，为用户提供抽象、虚拟的硬件环境，可以模拟各种硬件架构并运行多种操作系统。QEMU 的初始化是一个复杂的过程，由 &lt;code&gt;qemu_init&lt;/code&gt; 函数负责完成，该过程主要包括参数解析、主循环初始化、机器创建、设备初始化等流程，本文将以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例，分析 virt 机器创建及初始化机制。&lt;/p&gt;
&lt;p&gt;本文使用以下命令在 QEMU 中创建一台 virt 机器并启动 5.18 版本的 RISC-V Linux 内核：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu-system-riscv64&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virt&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 256M&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;nographic&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; linux-kernel/arch/riscv/boot/Image&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;drive&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; file=rootfs.img,format=raw,id=hd0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virtio-blk-device,drive=hd0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;root=/dev/vda rw console=ttyS0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;机器创建的工作由函数 &lt;code&gt;qemu_create_machine&lt;/code&gt; 完成，而机器初始化则由 &lt;code&gt;qemu_apply_legacy_machine_options&lt;/code&gt; 和 &lt;code&gt;qemu_apply_machine_options&lt;/code&gt; 完成，如果命令行参数没有配置 &lt;code&gt;--preconfig&lt;/code&gt; 选项，则 &lt;code&gt;qmp_x_exit_preconfig&lt;/code&gt; 也会承担一部分的机器初始化工作。待机器初始化完成后，QEMU 会调用机器类型对应的初始化方法对机器实例进行初始化。&lt;/p&gt;
&lt;p&gt;QEMU 机器创建及初始化的基本流程如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-machine-create/./machine-creation-process.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ji-qi-chuang-jian&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-qi-chuang-jian&quot; aria-label=&quot;Anchor link for: ji-qi-chuang-jian&quot;&gt;机器创建&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 在完成命令行参数的解析以及主循环的初始化后，会根据命令行指定的机器类型调用函数 &lt;code&gt;qemu_create_machine&lt;/code&gt; 进行机器创建：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 2011 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_create_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qdict&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;machine_class &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; select_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_set_machine_compat_props&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;compat_props&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    current_machine &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MACHINE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_new_with_class&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_property_add_child&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_get_root&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;machine&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                              OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_property_add_child&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;container_get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;                                            &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;/unattached&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;                              &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;sysbus&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sysbus_get_default&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;minimum_page_bits&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;set_preferred_target_page_bits&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;minimum_page_bits&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; This would be a board error: specifying a minimum smaller than&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;             * a target&amp;#39;s compile-time fixed setting.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;             */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_assert_not_reached&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    cpu_exec_init_all&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    page_size_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;hw_version&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qemu_set_hw_version&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;hw_version&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Get the default machine options from the machine if it is not already&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * specified either by the configuration file or by the command line.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;default_machine_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        QDict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;default_opts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            keyval_parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;default_machine_opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                         &amp;amp;&lt;/span&gt;&lt;span&gt;error_abort&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qemu_apply_legacy_machine_options&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;default_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        object_set_properties_from_keyval&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; default_opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                                          false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_abort&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qobject_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;default_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;qemu_create_machine&lt;/code&gt; 函数首先调用 &lt;code&gt;select_machine&lt;/code&gt; 函数检查命令行指定的机器类型是否在 QEMU 支持的机器列表中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 1577 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;select_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;optarg &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qdict_get_try_str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;machines &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_class_get_list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TYPE_MACHINE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;local_err &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        machine_class &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; machines&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qdict_del&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;unsupported machine type&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        machine_class &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_default_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machines&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;No machine specified, and there is no default&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_slist_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machines&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_append_hint&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Use -machine help to list supported machines&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_propagate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; machine_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;select_machine&lt;/code&gt; 首先调用 &lt;code&gt;object_class_get_list&lt;/code&gt; 函数选出由该机器类型所派生出的各种具体机器型号并储存在链表 &lt;code&gt;machines&lt;/code&gt; 中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 1155 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_class_get_list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;implements_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                              bool&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; include_abstract&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;list &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_class_foreach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;object_class_get_list_tramp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                         implements_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; include_abstract&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;machines&lt;/code&gt; 列表不为空，则意味着命令行指定的机器类型位于 QEMU 的支持列表中，则 &lt;code&gt;select_machine&lt;/code&gt; 会继续调用 &lt;code&gt;find_machine&lt;/code&gt; 函数找到对应机器类型并返回：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 799 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;find_machine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;machines&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;el&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;el &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; machines&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; el&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; el &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; el&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; el&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;strcmp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ||&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_strcmp0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt; mc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来 QEMU 会调用 &lt;code&gt;object_set_machine_compat_props&lt;/code&gt; 设置 virt 机器的全局属性，然后之前选择出的机器类型创建一个该类的实例 &lt;code&gt;current_machine&lt;/code&gt;，这里的 &lt;code&gt;current_machine&lt;/code&gt; 是一个 &lt;code&gt;MachineState&lt;/code&gt; 类型的指针：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/hw/boards.h: 324 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; MachineState &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; &amp;lt; private &amp;gt; &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Object parent_obj&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; &amp;lt; public &amp;gt; &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;fdt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;dtb&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;dumpdtb&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; phandle_start&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;dt_compatible&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; dump_guest_core&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; mem_merge&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; usb&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; usb_disabled&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;firmware&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; iommu&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; suppress_vmdesc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; enable_graphics&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ConfidentialGuestSupport &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;cgs&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    HostMemoryBackend &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;memdev&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * convenience alias to ram_memdev_id backend memory region&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * or to numa container memory region&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MemoryRegion &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ram&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceMemoryState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;device_memory&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    ram_addr_t&lt;/span&gt;&lt;span&gt; ram_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    ram_addr_t&lt;/span&gt;&lt;span&gt; maxram_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    uint64_t&lt;/span&gt;&lt;span&gt;   ram_slots&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BootConfiguration boot_config&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;kernel_filename&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;kernel_cmdline&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;initrd_filename&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;cpu_type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AccelState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;accelerator&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CPUArchIdList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;possible_cpus&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CpuTopology smp&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; NVDIMMState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;nvdimms_state&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; NumaState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;numa_state&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;QEMU 使用 &lt;code&gt;MachineState&lt;/code&gt; 结构体对机器的参数和运行状态进行描述，这里的 &lt;code&gt;current_machine&lt;/code&gt; 就描述了新创建的 virt 机器，对 virt 的各类初始化操作就是对 &lt;code&gt;current_machine&lt;/code&gt; 的成员变量进行操作。完成机器的实例化之后，&lt;code&gt;qemu_create_machine&lt;/code&gt; 函数通过调用 &lt;code&gt;object_property_add_child&lt;/code&gt; 将新创建的机器实例添加到 QEMU 的对象树中，并将默认的系统总线添加为其子对象。最后，QEMU 使用 &lt;code&gt;cpu_exec_init_all&lt;/code&gt; 和 &lt;code&gt;page_size_init&lt;/code&gt; 等函数对包括 IO 空间、内存映射、页面大小在内的一系列运行环境进行初始化，最终完成机器的创建，退出 &lt;code&gt;qemu_create_machine&lt;/code&gt; 函数。&lt;/p&gt;
&lt;h2 id=&quot;ji-qi-can-shu-chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-qi-can-shu-chu-shi-hua&quot; aria-label=&quot;Anchor link for: ji-qi-can-shu-chu-shi-hua&quot;&gt;机器参数初始化&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;机器参数初始化环节主要是根据命令函参数解析的结果设置新创建的机器实例的参数，具体工作由 &lt;code&gt;qemu_apply_legacy_machine_options&lt;/code&gt; 和 &lt;code&gt;qemu_apply_machine_options&lt;/code&gt; 函数完成。&lt;code&gt;qemu_apply_legacy_machine_options&lt;/code&gt; 函数负责设置不在 &lt;code&gt;MachineState&lt;/code&gt; 结构体中的属性，主要包括 &lt;code&gt;accel&lt;/code&gt;, &lt;code&gt;kernel-irqchip&lt;/code&gt;, &lt;code&gt;memory-backend&lt;/code&gt; 等命令行选项：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 1649 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_apply_legacy_machine_options&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qdict&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QObject &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;prop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    keyval_dashify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Legacy options do not correspond to MachineState properties. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qdict_get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;prop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        have_custom_ram_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            qobject_type&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;prop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; QTYPE_QDICT &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            qdict_haskey&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qobject_to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; prop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以本文开头的 QEMU 启动命令为例，其中使用 &lt;code&gt;-m 256M&lt;/code&gt; 选项指定了机器内存大小，&lt;code&gt;qemu_apply_legacy_machine_options&lt;/code&gt; 在遍历参数过程中会设置布尔变量 &lt;code&gt;have_custom_ram_size&lt;/code&gt; 值为 &lt;code&gt;true&lt;/code&gt;，这一变量在之后调用 &lt;code&gt;qemu_resolve_machine_memdev&lt;/code&gt; 函数解析和设置虚拟机内存后端的过程中用来判断用户是否指定自定义的 RAM 大小。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;qemu_apply_machine_options&lt;/code&gt; 函数主要目的是将参数解析提供的机器选项应用到当前创建的虚拟机上：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 1845 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_apply_machine_options&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qdict&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_set_properties_from_keyval&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; qdict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;semihosting_enabled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;semihosting_get_argc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; fall back to the -kernel/-append &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        semihosting_arg_fallback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;kernel_filename&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; current_machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;kernel_cmdline&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;smp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cpus&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        replay_add_blocker&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;smp&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;qemu_apply_machine_options&lt;/code&gt; 函数会调用 &lt;code&gt;object_set_properties_from_keyval&lt;/code&gt; 函数将 &lt;code&gt;qdict&lt;/code&gt; 中的键值对设置为 &lt;code&gt;current_machine&lt;/code&gt; 对象的属性，并在结束执行前检查机器是否启用 &lt;code&gt;semi-host&lt;/code&gt; 模式以及是否配置了多个 CPU。&lt;/p&gt;
&lt;h2 id=&quot;ji-qi-shi-li-chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-qi-shi-li-chu-shi-hua&quot; aria-label=&quot;Anchor link for: ji-qi-shi-li-chu-shi-hua&quot;&gt;机器实例初始化&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果命令行参数启用了 &lt;code&gt;--preconfig&lt;/code&gt; 选项，那么 QEMU 将会在完成创建初始虚拟机之前暂停，进入交互式配置状态并允许通过 &lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/interop/qemu-qmp-ref.html&quot;&gt;QEMU Machine Protocol&lt;/a&gt;（QMP）进行一些配置。在本文中，没有配置 &lt;code&gt;--preconfig&lt;/code&gt; 选项，因此 &lt;code&gt;qemu_init&lt;/code&gt; 函数在初始化工作进入尾声时会调用 &lt;code&gt;qmp_x_exit_preconfig&lt;/code&gt; 函数以避免 QEMU 执行暂停：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/vl.c: 2602 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qmp_x_exit_preconfig&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;phase_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PHASE_MACHINE_INITIALIZED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;The command is permitted only before machine initialization&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_init_board&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_create_cli_devices&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_machine_creation_done&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;loadvm&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        load_snapshot&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loadvm&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;replay_mode &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!=&lt;/span&gt;&lt;span&gt; REPLAY_MODE_NONE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        replay_vmstate_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;incoming&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;local_err &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;strcmp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;incoming&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            qmp_migrate_incoming&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;incoming&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                error_reportf_err&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-incoming &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; incoming&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;autostart&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qmp_cont&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;qemu_init_board&lt;/code&gt; 函数会进一步调用 &lt;code&gt;machine_run_board_init&lt;/code&gt; 完成机器实例（主板）的一些初始化操作，包括设置内存、检查 CPU 类型、初始化加速器和其他相关的设置：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; hw/core/machine.c: 1307 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; machine_run_board_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MachineState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;machine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;mem_path&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MachineClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;machine_class &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MACHINE_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;oc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_class_by_name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cpu_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CPUClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;cc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; This checkpoint is required by replay to separate prior clock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;       reading from the other reads, because timer polling functions query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;       clock values from the log. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    replay_checkpoint&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CHECKPOINT_INIT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;xen_enabled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; On 32-bit hosts, QEMU is limited by virtual address space &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;2047&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 20&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; HOST_LONG_BITS &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;at most 2047 MB RAM can be simulated&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;memdev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;        ram_addr_t&lt;/span&gt;&lt;span&gt; backend_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_property_get_uint&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;memdev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;                                                           &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;  &amp;amp;&lt;/span&gt;&lt;span&gt;error_abort&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;backend_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!=&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Machine memory size does not match the size of the memory backend&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;default_ram_id&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;               numa_uses_legacy_mem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;create_default_memdev&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;current_machine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; mem_path&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;numa_state&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        numa_complete_configuration&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;numa_state&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;num_nodes&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            machine_numa_finish_cpu_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;memdev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; machine_consume_memdev&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;memdev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; If the machine supports the valid_cpu_types check and the user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * specified a CPU with -cpu check here that the user CPU is supported.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cpu_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_class_dynamic_cast&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;oc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                          machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;                /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; The user specificed CPU is in the valid field, we are&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;                 * good to go.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;                 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; The user specified CPU is not valid &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Invalid CPU type: &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cpu_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_printf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;The valid types are: &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                         machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                error_printf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;valid_cpu_types&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_printf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Check if CPU type is deprecated and warn if so &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CPU_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;oc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; cc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;deprecation_note&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        warn_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;CPU model &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; is deprecated -- &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cpu_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    cc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;deprecation_note&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cgs&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * With confidential guests, the host can&amp;#39;t see the real&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * contents of RAM, so there&amp;#39;s no point in it trying to merge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * areas.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        machine_set_mem_merge&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_abort&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * Virtio devices can&amp;#39;t count on directly accessing guest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * memory, so they need iommu_platform=on to use normal DMA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * mechanisms.  That requires also disabling legacy virtio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * support for those virtio pci devices which allow it.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        object_register_sugar_prop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TYPE_VIRTIO_PCI&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;disable-legacy&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;                                   &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        object_register_sugar_prop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TYPE_VIRTIO_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;iommu_platform&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;                                   &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    accel_init_interfaces&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;ACCEL_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;accelerator&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    machine_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    phase_advance&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PHASE_MACHINE_INITIALIZED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在上述代码中需要关注的是通过 &lt;code&gt;machine_class-&amp;gt;init&lt;/code&gt; 来调用机器类型的初始化方法对机器实例 &lt;code&gt;machine&lt;/code&gt; 进行初始化，通过动态调试我们可以发现，这里实际调用的是 &lt;code&gt;virt_machine_init&lt;/code&gt; 函数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; hw/riscv/virt.c: 1332 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; virt_machine_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MachineState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span&gt; MemMapEntry &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;memmap &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; virt_memmap&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    RISCVVirtState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; RISCV_VIRT_MACHINE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MemoryRegion &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;system_memory &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_system_memory&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MemoryRegion &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mask_rom &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemoryRegion&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;soc_name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mmio_irqchip&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;virtio_irqchip&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;pcie_irqchip&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; base_hartid&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; hart_count&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; socket_count &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; riscv_socket_count&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Check socket count limit &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Initialize sockets &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; register system main memory (actual RAM) &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    memory_region_add_subregion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;system_memory&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; memmap&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VIRT_DRAM&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ram&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; boot rom &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    memory_region_init_rom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mask_rom&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;riscv_virt_board.mrom&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;                           memmap&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VIRT_MROM&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    memory_region_add_subregion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;system_memory&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; memmap&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VIRT_MROM&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                mask_rom&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * device tree cannot be altered and we get FDT_ERR_NOSPACE.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fw_cfg&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; create_fw_cfg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    rom_set_fw&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fw_cfg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; SiFive Test MMIO device &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    sifive_test_create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;memmap&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VIRT_TEST&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;base&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; VirtIO MMIO devices &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; load/create device tree &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;dtb&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fdt&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; load_device_tree&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;dtb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fdt_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;machine&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fdt&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;load_device_tree() failed&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        create_fdt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; memmap&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;machine_done&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;notify&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; virt_machine_done&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_machine_init_done_notifier&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;machine_done&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;virt_machine_init&lt;/code&gt; 函数是 QEMU 中 RISC-V 架构机器 virt 的初始化函数，它首先会检查插槽数量，初始化插槽并每个插槽创建一个中断控制器，然后根据 32 位或 64 位设置 PCIe 内存映射参数，接着注册系统主内存并初始化引导 ROM。此后，会初始化 virt 机器的一系列的设备，包括 VirtIO MMIO 设备、PCIe 设备、平台总线、串行设备、RTC 和闪存设备等，最后加载或创建设备树并设置机器初始化完成通知符告知 QEMU 机器（主板）初始化完成。&lt;/p&gt;
&lt;p&gt;当机器初始化工作全部完成后，由 &lt;code&gt;qemu_machine_creation_done&lt;/code&gt; 函数执行一系列后置的检查和状态同步操作，通知 QEMU 机器初始化工作全部完成且通过检查，执行流程可以进入下一阶段。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文梳理了 QEMU 机器创建及初始化的基本流程，并以 RISC-V 架构的 virt 平台为例，从机器类型选择、机器参数初始化和机器实例初始化三个环节切入，深入分析了 QEMU 机器创建机制的技术细节，打通了 QEMU 中虚拟机创建流程的内在逻辑。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/tinylab/riscv-linux/blob/master/articles/20220911-qemu-riscv-zsbl.md&quot;&gt;QEMU 启动方式分析（3）: QEMU 代码与 RISCV &#39;virt&#39; 平台 ZSBL 分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/6891922292075397127&quot;&gt;QEMU RISC-V virt 平台分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/interop/qemu-qmp-ref.html&quot;&gt;QEMU QMP Reference Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/system/riscv/virt.html&quot;&gt;‘virt’ Generic Virtual Platform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 设备模型简析（三）：QOM 设计实现</title>
        <published>2023-09-07T00:00:00+00:00</published>
        <updated>2023-09-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-device-model-part3/"/>
        <id>https://jjl9807.com/posts/qemu-system-device-model-part3/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-device-model-part3/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part3/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在&lt;a href=&quot;https://jjl9807.com/posts/qemu-system-device-model-part2/&quot;&gt;上一篇文章&lt;/a&gt;中我们聚焦 QEMU 中面向对象的设备管理机制，阐述了引入对象模型的必要性，介绍了 QOM 基本功能和顶层设计，本文将在此基础上进一步深入，详细分析 QOM 对象系统的设计思路以及实现方式。&lt;/p&gt;
&lt;h2 id=&quot;guan-jian-jie-gou&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-jian-jie-gou&quot; aria-label=&quot;Anchor link for: guan-jian-jie-gou&quot;&gt;关键结构&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;通过之前的分析，我们已经知道 QOM 有如下几大关键数据结构：&lt;code&gt;Object&lt;/code&gt;、&lt;code&gt;ObjectClass&lt;/code&gt;、&lt;code&gt;TypeInfo&lt;/code&gt; 和 &lt;code&gt;TypeImpl&lt;/code&gt;，他们的关系如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part3/./qom-object.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;通过上图不难看出，QOM 对象模型的核心结构是 &lt;code&gt;Object&lt;/code&gt;，这个结构体十分简洁，只保存了有关类型和父类的信息。&lt;code&gt;ObjectClass&lt;/code&gt; 结构体就比较复杂，保存指向类型信息 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体的指针，保证了能够获取有关类型的信息。&lt;code&gt;TypeImpl&lt;/code&gt; 存储着一个类型的信息，包括类型名称、类型大小、是否抽象类、父类名称、父类类型指针、&lt;code&gt;ObjectClass&lt;/code&gt; 等。&lt;code&gt;TypeInfo&lt;/code&gt; 结构体没有直接与其他任何数据结构产生直接关联，通过前面的分析我们已经知道，这是面向开发者的一个工具结构，主要用于在注册类型的时候提供类型的基本信息，在类型注册伊始，QEMU 会自动生成对应的 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体，保存类型的全部信息。&lt;/p&gt;
&lt;h2 id=&quot;mian-xiang-dui-xiang-te-xing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#mian-xiang-dui-xiang-te-xing&quot; aria-label=&quot;Anchor link for: mian-xiang-dui-xiang-te-xing&quot;&gt;面向对象特性&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先，我们需要回顾一下面向对象的基本特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;封装&lt;/li&gt;
&lt;li&gt;接口&lt;/li&gt;
&lt;li&gt;继承&lt;/li&gt;
&lt;li&gt;析构&lt;/li&gt;
&lt;li&gt;静态成员&lt;/li&gt;
&lt;li&gt;多态&lt;/li&gt;
&lt;li&gt;动态类型装换&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面我们将详细分析上述特性在 QOM 对象系统中的具体实现。&lt;/p&gt;
&lt;h3 id=&quot;feng-zhuang&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#feng-zhuang&quot; aria-label=&quot;Anchor link for: feng-zhuang&quot;&gt;封装&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在分析 QOM 如何实现封装之前，我们需要再次回顾 &lt;code&gt;Object&lt;/code&gt; 结构体的定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 153 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; Object&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; private: &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectFree &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;free&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GHashTable &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    uint32_t&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里需要关注的是第一行的注释，它表示结构体中的所有属性都是私有的，只能被类的内部成员访问和修改。但是，仅靠 C 语言中的结构体是无法实现对私有变量的访问控制的，因此 QEMU 在 &lt;code&gt;Object&lt;/code&gt; 中引入了属性表，即 &lt;code&gt;properties&lt;/code&gt; 指针，它指向一张哈希表，该表含了 &lt;code&gt;Object&lt;/code&gt; 中的所有可以访问、修改的数据和函数其中每一个键值对表示 &lt;code&gt;property&lt;/code&gt; 的名称以及指向相应 &lt;code&gt;ObjectProperty&lt;/code&gt; 结构体的指针。下面给出 &lt;code&gt;ObjectProperty&lt;/code&gt; 结构体的实现代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 88 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; ObjectProperty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectPropertyResolve &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectPropertyRelease &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;release&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectPropertyInit &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QObject &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;defval&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，&lt;code&gt;ObjectProperty&lt;/code&gt; 结构体包含了这个属性的名称、类型、描述、读写方法以及解析和释放函数，还包括这个 &lt;code&gt;property&lt;/code&gt; 特有的属性，使用 &lt;code&gt;opaque&lt;/code&gt; 指针来表示。QOM 通过 &lt;code&gt;ObjectProperty&lt;/code&gt; 结构体将对象的每个数据都保存在这样一个单元之中，再利用一个哈希表实现对对象所有数据的统一管理，进而实现了数据封装。当用户需要向 &lt;code&gt;Object&lt;/code&gt; 中增加属性时，需要调用 &lt;code&gt;object_property_add&lt;/code&gt; 函数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 1257 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ObjectProperty &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_property_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;get&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;set&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ObjectPropertyRelease &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;release&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_property_try_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; release&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                   opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_abort&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数通过进一步调用 &lt;code&gt;object_property_try_add&lt;/code&gt; 函数向 &lt;code&gt;properties&lt;/code&gt; 所指向的哈希表中插入了一个新的属性：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 1206 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ObjectProperty &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_property_try_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;get&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        ObjectPropertyAccessor &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;set&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        ObjectPropertyRelease &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;release&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                        void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectProperty &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;prop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; name_len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; strlen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;name_len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;memcmp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;+&lt;/span&gt;&lt;span&gt; name_len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;[*]&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ObjectProperty &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name_no_array &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_strdup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;        name_no_array&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;name_len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 3&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; INT16_MAX&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ++&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;full_name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_strdup_printf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; name_no_array&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_property_try_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; full_name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                          release&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;full_name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name_no_array&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_property_find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_setg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;attempt to add duplicate property &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39; to object (type &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;)&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                   name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_get_typename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_malloc0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;prop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_strdup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_strdup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;release&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; release&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; opaque&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_hash_table_insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; prop&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; prop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; prop&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;ji-cheng&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-cheng&quot; aria-label=&quot;Anchor link for: ji-cheng&quot;&gt;继承&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在面向对象编程中主要包括三种继承形式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可视继承：&lt;/strong&gt; QEMU 中可视继承主要用于处理图形界面的相关问题，这里不做深入讨论&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现继承：&lt;/strong&gt; 子类能够直接使用基类的属性和方法而无需重新编写代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接口继承：&lt;/strong&gt; 子类仅使用基类的属性和方法名称，属性和代码的具体内容需要重新编写代码实现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于实现继承，QOM 通过结构体的包含关系完成。在 QEMU 中我们创建一个新类时，会实现两个数据结构：类的数据结构 &lt;code&gt;ObjectClass&lt;/code&gt; 和对象的数据结构 &lt;code&gt;Object&lt;/code&gt;，由于这两个结构体中的第一个成员变量就是父类（对象），那么只要通过 “指针 + 偏移量” 就可以直接使用父类的属性和方法，完成了实现继承的功能。&lt;/p&gt;
&lt;p&gt;对于接口继承，QEMU 中定义了专门的接口结构：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 514 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; InterfaceClass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass parent_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; private: &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;concrete_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Type interface_type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 QOM 中一个类可以实现多个接口，也就是接口继承。&lt;code&gt;ObjectClass&lt;/code&gt; 结构体中与接口继承相关的属性是 &lt;code&gt;interfaces&lt;/code&gt;，它指向一条链表，链表中的每个元素都是一个指向 &lt;code&gt;InterfaceClass&lt;/code&gt; 的指针，再通过其中的 &lt;code&gt;interface_type&lt;/code&gt; 指针指向一个 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体，我们可以通过给该指针指向的 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体中的函数指针赋值，从而达到实现对应接口的目的。&lt;/p&gt;
&lt;h3 id=&quot;duo-tai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#duo-tai&quot; aria-label=&quot;Anchor link for: duo-tai&quot;&gt;多态&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;多态是同一操作作用于不同的对象，可以有不同的解释，产生不同的执行结果。为了实现多态，QOM 实现了一个非常重要的功能，即动态强制类型转换（dynamic cast）。我们可以使用相关的函数，将一个 &lt;code&gt;Object&lt;/code&gt; 的指针在运行时 cast 为子类对象的指针，可以将一个 &lt;code&gt;ObjectClass&lt;/code&gt; 的指针在运行时 cast 为子类的指针。这样就可以调用子类中定义的函数指针来完成相应的功能。动态 cast 功能主要由 &lt;code&gt;object_class_dynamic_cast&lt;/code&gt; 函数实现：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 908 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;object_class_dynamic_cast&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                                       const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;typename&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;target_type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; A simple fast path that can trigger a lot for leaf classes. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    type &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; typename&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    target_type &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_get_by_name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;target_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; target class type unknown, so fail the cast &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            type_is_ancestor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type_interface&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int&lt;/span&gt;&lt;span&gt; found &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;target_class &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_is_ancestor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target_class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; target_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; target_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                found&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; The match was ambiguous, don&amp;#39;t allow a cast &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;found &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_is_ancestor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; target_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;xi-gou&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xi-gou&quot; aria-label=&quot;Anchor link for: xi-gou&quot;&gt;析构&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QOM 的通过 “引用计数” 来判断何时调用析构函数删除对象，&lt;code&gt;Object&lt;/code&gt; 的结构体中有一个专门用于对 &lt;code&gt;Object&lt;/code&gt; 引用的计数变量 &lt;code&gt;ref&lt;/code&gt;，如果 &lt;code&gt;ref&lt;/code&gt; 的值减少为 0，就意味着系统不会继续使用这个对象了，那么就可以对相应的内存空间等进行回收操作：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 1192 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;objptr&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; OBJECT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;objptr&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ref&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; parent always holds a reference to its children &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qatomic_fetch_dec&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ref&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        object_finalize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在注册类型时，可以通过定义 &lt;code&gt;TypeInfo&lt;/code&gt; 结构体中的 &lt;code&gt;instance_finalize&lt;/code&gt; 实现自定义析构函数，对于引用计数为 0 的 &lt;code&gt;Object&lt;/code&gt; 进行垃圾回收操作。QOM 提供了默认析构函数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 688 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_finalize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ti &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_property_del_all&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    object_deinit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ref&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;free&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        obj&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Object&lt;/code&gt; 数据结构中有一个 &lt;code&gt;ObjectFree *&lt;/code&gt; 类型的函数指针 &lt;code&gt;free&lt;/code&gt;，当 &lt;code&gt;Object&lt;/code&gt; 的引用计数为 0 时，就会调用这个函数进行垃圾回收：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 677 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; object_deinit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_finalize&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;instance_finalize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_has_parent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        object_deinit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_get_parent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数会调用 &lt;code&gt;TypeImpl&lt;/code&gt; 中的实例析构函数。如果存在父类，则会递归继续调用父类的实例析构函数。这里之所以需要调用父类实例析构函数是因为一个 &lt;code&gt;Object&lt;/code&gt; 结构体的第一个成员变量就是父类对象的实例，因此当我们需要对对象析构时，不仅要调用当前类的析构方法，也需要调用父类的析构方法将结构体中的第一个成员进行析构。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QOM 实现了一套较为完备的对象管理系统，包括自动化的对象注册、完善的对象管理以及巧妙的动态类型转换，本文梳理了 QOM 实现中几大关键数据结构之间的联系，详细分析了封装、多态、继承以及析构等面向对象特性在 QOM 中的集体实现，与之前的文章相呼应，打通了 QEMU 设备模型从使用到实现的全过程逻辑链条。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.linux-kvm.org/images/9/90/Kvmforum14-qom.pdf&quot;&gt;Kvmforum14-qom.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http://blog.chinaunix.net/uid-28541347-id-5784376.html&quot;&gt;QOM 实现分析&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 设备模型简析（二）：面向对象的设备管理</title>
        <published>2023-08-30T00:00:00+00:00</published>
        <updated>2023-08-30T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-device-model-part2/"/>
        <id>https://jjl9807.com/posts/qemu-system-device-model-part2/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-device-model-part2/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part2/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上一篇文章介绍了 QEMU 设备模型的生命周期，分析了 QEMU 中设备类型注册、设备类型初始化、设备实例化等环节的基本原理与执行流程，在这个过程中我们不难发现 QEMU 设备模型采用了面向对象的设计思想，本文将以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例，阐述 QEMU 中面向对象的设备管理机制。&lt;/p&gt;
&lt;p&gt;在 Linux 中一切皆文件，而 QEMU 中模拟的一切实体皆对象。以 CPU 模拟为例，QEMU 中要实现对各种 CPU 架构的模拟，而且对于同一种架构的 CPU，比如 RISC-V 架构，由于功能特性的不同，也会有不同的 CPU 型号。任何型号的 CPU 中都有 CPU 的通用属性，同时也包含各自特有的属性，使用面向对象的设计思想可以非常高效地实现各种型号 CPU 的模拟。&lt;/p&gt;
&lt;p&gt;此外，在主板上一个设备会通过总线与其他的设备相连接，而其他的设备也可以进一步通过总线与更多的设备连接，同时一个总线上会连接多个设备。这种总线型关系的模拟也可以非常便捷地使用面向对象的模型实现。&lt;/p&gt;
&lt;p&gt;QEMU 对象模型（QEMU Object Model, QOM）提供了一个通用的面向对象框架，用于注册用户创建的设备类型和实例化这些类型的对象。QOM 提供以下功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;动态的设备类型注册系统&lt;/li&gt;
&lt;li&gt;支持设备类型的单一继承&lt;/li&gt;
&lt;li&gt;无状态接口的多重继承&lt;/li&gt;
&lt;li&gt;将内部成员映射到公开的属性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;QOM 中最基础的对象是 &lt;code&gt;TYPE_OBJECT&lt;/code&gt;，它提供所有对象共有的基本方法。&lt;/p&gt;
&lt;h2 id=&quot;ji-lei&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-lei&quot; aria-label=&quot;Anchor link for: ji-lei&quot;&gt;基类&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ObjectClass&lt;/code&gt; 是 QOM 中所有类的基础，每一类对象会实例化一个 &lt;code&gt;ObjectClass&lt;/code&gt;，类的成员是这类对象通用的内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 127 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; ObjectClass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; private: &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Type type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;object_cast_cache&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;OBJECT_CLASS_CAST_CACHE&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;class_cast_cache&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;OBJECT_CLASS_CAST_CACHE&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectUnparent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;unparent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GHashTable &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Object&lt;/code&gt; 是 QOM 中所有对象的基础，QOM 的每一个设备会实例化一个 &lt;code&gt;Object&lt;/code&gt;，&lt;code&gt;Object&lt;/code&gt; 的成员是每个设备独有的内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 153 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; Object&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; private: &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectFree &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;free&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GHashTable &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    uint32_t&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Object&lt;/code&gt; 的第一个成员是指向 &lt;code&gt;ObjectClass&lt;/code&gt; 的指针。由于 C 语言保证结构体的第一个成员始终从该结构体首地址开始，只要任何子对象将其父对象作为第一个成员，就可以直接将其转换为 &lt;code&gt;Object&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;QOM 中 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt; 的关系，可以像上一篇文章中一样理解为设备类型与具体设备的关系，一个 &lt;code&gt;ObjectClass&lt;/code&gt; 可以对应多个 &lt;code&gt;Object&lt;/code&gt;，而 一个 &lt;code&gt;Object&lt;/code&gt; 只会指向一个 &lt;code&gt;ObjectClass&lt;/code&gt;。也可以将 &lt;code&gt;ObjectClass&lt;/code&gt; 理解为设备驱动，&lt;code&gt;Object&lt;/code&gt; 理解为设备。&lt;code&gt;ObjectClass&lt;/code&gt; 所描述的主要是某一类设备的通用操作接口，而且 &lt;code&gt;ObjectClass&lt;/code&gt; 也会实例化一个实体，这个实体是这一类设备所共用的；而每一个实际的设备都对应一个 &lt;code&gt;Object&lt;/code&gt;，每个 &lt;code&gt;Object&lt;/code&gt; 又会有一个指针指向 &lt;code&gt;ObjectClass&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;下面以 virtio-net 设备为例，分析 QEMU 对象模型的继承和派生关系：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;QOM 最底层的基类是 &lt;code&gt;ObjectClass&lt;/code&gt;，对应的对象是 &lt;code&gt;Object&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;设备的类 &lt;code&gt;DeviceClass&lt;/code&gt;，对应的对象是 &lt;code&gt;DeviceState&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;PCI 设备在设备类的基础上派生出了 &lt;code&gt;PCIDeviceClass&lt;/code&gt;，对应的对象是 &lt;code&gt;PCIDevice&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;virtio-pci 设备又在 PCI 设备的基础上派生出 &lt;code&gt;VirtioPCIClass&lt;/code&gt;，对应的对象是 &lt;code&gt;VirtIOPCIProxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;virtio-net 设备在 VIRTIO-PCI 设备的基础上进一步派生出新的类，这里需要注意的是 virtio-net 设备相比 virtio-pci 设备并不需要增加新的内容，所以这一层派生出的依旧是 &lt;code&gt;VirtioPCIClass&lt;/code&gt;，但是对应的对象依然需要增加网络设备特有的内容，因此会派生出新结构体 &lt;code&gt;VirtIONetPCI&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本质上 C 语言中派生的实现形式就是结构体的包含嵌套，派生类层层包含父类，具体关系如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part2/./object-class.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;正如上文在分析 &lt;code&gt;Object&lt;/code&gt; 时介绍的那样，为了更好的在派生结构体之间互相引用，通常把被引用的结构体，也就是父类放在自己的第一个字段，这样就可以很方便地通过首地址加偏移量的方式进行对象类型转换。就拿上图中的 &lt;code&gt;VirtIONetPCI&lt;/code&gt; 结构体来说，它的各级父类的 &lt;code&gt;VirtioPCIProxy&lt;/code&gt;、&lt;code&gt;PCIDevice&lt;/code&gt;、&lt;code&gt;DeviceState&lt;/code&gt; 以及 &lt;code&gt;Object&lt;/code&gt; 指针指向的就是自己的首地址。&lt;/p&gt;
&lt;p&gt;除了 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt; 这两个结构体之外，QOM 中还有两个重要的数据结构，就是上一篇文章中已经介绍过的 &lt;code&gt;TypeInfo&lt;/code&gt; 和 &lt;code&gt;TypeImpl&lt;/code&gt;。&lt;code&gt;TypeInfo&lt;/code&gt; 是与 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt; 并列的结构，每一类设备不仅对应一种 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt;，而且还需要对应一个 &lt;code&gt;TypeInfo&lt;/code&gt; 结构。在 QOM 中，&lt;code&gt;TypeInfo&lt;/code&gt; 是统一的，并不是 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt; 那样自底向上层层派生的结构。&lt;code&gt;TypeInfo&lt;/code&gt; 是一个对外的接口，其目的是收集用户创建设备的必要信息，以实例化出相应的 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt;。QOM 内部维护了一个全局的 &lt;code&gt;TypeTmpl&lt;/code&gt; 哈希表，当 QMP 命令生产一个对象的时候，会从该表中找到对应的 &lt;code&gt;TypeImpl&lt;/code&gt; 结构，然后根据 &lt;code&gt;TypeImpl&lt;/code&gt; 的内容去初始化化相应的 &lt;code&gt;ObjectClass&lt;/code&gt; 和 &lt;code&gt;Object&lt;/code&gt;。需要注意的是，如果已经注册过相同类型的设备，则已有 &lt;code&gt;ObjectClass&lt;/code&gt;，无需再次初始化。&lt;/p&gt;
&lt;h2 id=&quot;ji-yu-qom-de-she-bei-guan-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-yu-qom-de-she-bei-guan-li&quot; aria-label=&quot;Anchor link for: ji-yu-qom-de-she-bei-guan-li&quot;&gt;基于 QOM 的设备管理&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;chuang-jian-xin-she-bei-lei-xing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#chuang-jian-xin-she-bei-lei-xing&quot; aria-label=&quot;Anchor link for: chuang-jian-xin-she-bei-lei-xing&quot;&gt;创建新设备类型&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用 QOM 对象模型创建新设备类型的详细内容可以参考 QEMU 官方文档，QOM 各接口的使用说明详见 &lt;code&gt;include/qom/object.h&lt;/code&gt; 文件中各函数的注释。这里仅以最简单的设备类型为例，介绍使用 QOM 对象模型创建新的设备类型的一般方法：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;qdev.h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;my-device&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; No new virtual functions: we can reuse the typedef for the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; superclass.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span&gt; DeviceClass MyDeviceClass&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; MyDevice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceState parent_obj&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; reg0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; reg1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; reg2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; MyDevice&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo my_device_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDevice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; my_device_register_types&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    type_register_static&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;my_device_info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;my_device_register_types&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在上述代码中，我们使用 &lt;code&gt;TypeInfo&lt;/code&gt; 结构体描述了新创建的 &lt;code&gt;my-device&lt;/code&gt; 设备类型，并定义了设备类型注册函数。这里需要注意的是，在 &lt;code&gt;MyDevice&lt;/code&gt; 结构体中，父对象必须是结构体的的第一个成员，以便实现父对象向子对象的投射。&lt;code&gt;my_device_info&lt;/code&gt; 结构体的父类是 &lt;code&gt;TYPE_DEVICE&lt;/code&gt;，该类是在 QEMU 中所有设备的父类，&lt;code&gt;TYPE_DEVICE&lt;/code&gt; 提供一些通用方法来处理 QEMU 设备模型。&lt;/p&gt;
&lt;p&gt;对于多个静态设备类型，也可以使用辅助宏 &lt;code&gt;DEFINE_TYPES&lt;/code&gt; 一并注册：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo device_types_info&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE_A&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDeviceA&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE_B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDeviceB&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;DEFINE_TYPES&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;device_types_info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如上文所述，每个 &lt;code&gt;Object&lt;/code&gt; 都有一个与之关联的 &lt;code&gt;ObjectClass&lt;/code&gt;，&lt;code&gt;ObjectClass&lt;/code&gt; 是动态实例化的，但任何给定 &lt;code&gt;Object&lt;/code&gt; 都只有一个 &lt;code&gt;ObjectClass&lt;/code&gt; 实例。对于每个新的设备类型，都要定义由 &lt;code&gt;ObjectClass&lt;/code&gt; 动态转换为 &lt;code&gt;MyDeviceClass&lt;/code&gt; 的方法，也会定义由 &lt;code&gt;Object&lt;/code&gt; 动态转换为 &lt;code&gt;MyDevice&lt;/code&gt; 的方法。以下涉及的宏 &lt;code&gt;OBJECT_GET_CLASS&lt;/code&gt;、&lt;code&gt;OBJECT_CLASS_CHECK&lt;/code&gt; 和 &lt;code&gt;OBJECT_CHECK&lt;/code&gt; 都在 &lt;code&gt;include/qemu/object.h&lt;/code&gt; 文件中定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_DEVICE_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;   OBJECT_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDeviceClass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_DEVICE_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;klass&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;   OBJECT_CLASS_CHECK&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDeviceClass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_DEVICE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;   OBJECT_CHECK&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDevice&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外，如果 &lt;code&gt;ObjectClass&lt;/code&gt; 的实现可以作为模块构建，则必须调用 &lt;code&gt;module_obj&lt;/code&gt; 函数，以确保 QEMU 在需要时正确加载模块：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;module_obj&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;she-bei-lei-xing-chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#she-bei-lei-xing-chu-shi-hua&quot; aria-label=&quot;Anchor link for: she-bei-lei-xing-chu-shi-hua&quot;&gt;设备类型初始化&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在初始化 &lt;code&gt;Object&lt;/code&gt; 之前，必须先初始化对应的 &lt;code&gt;ObjectClass&lt;/code&gt;。&lt;code&gt;ObjectClass&lt;/code&gt; 的初始化顺序是首先初始化父类，当父类对象初始化完成后，它将被复制到当前 &lt;code&gt;ObjectClass&lt;/code&gt; 中，剩余都将被清零。这样做的目的在于，该 &lt;code&gt;ObjectClass&lt;/code&gt; 能够自动继承父类已初始化的任何虚拟函数指针。&lt;/p&gt;
&lt;p&gt;如果我们在定义新类型中，实现了父类的虚函数，那么需要定义新的 class 的初始化函数，并且在 &lt;code&gt;TypeInfo&lt;/code&gt; 数据结构中，给 &lt;code&gt;TypeInfo&lt;/code&gt; 的 &lt;code&gt;class_init&lt;/code&gt; 字段赋予该初始化函数的函数指针：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;qdev.h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; my_device_class_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;class_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;dc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DEVICE_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;klass&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;reset&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; my_device_reset&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo my_device_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDevice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_init &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; my_device_class_init&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，引入新的虚拟方法需要 &lt;code&gt;Object&lt;/code&gt; 定义自己的结构体，并在 &lt;code&gt;TypeInfo&lt;/code&gt; 中添加 &lt;code&gt;.class_size&lt;/code&gt; 成员，每个方法还需要一个封装函数，以方便调用：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;qdev.h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; MyDeviceClass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceClass parent_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;frobnicate&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;MyDevice &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; MyDeviceClass&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo my_device_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DEVICE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDevice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .abstract &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; or set a default in my_device_class_init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDeviceClass&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; my_device_frobnicate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyDevice &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyDeviceClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_DEVICE_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    klass&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;frobnicate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;pai-sheng-lei&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pai-sheng-lei&quot; aria-label=&quot;Anchor link for: pai-sheng-lei&quot;&gt;派生类&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当我们需要从一个类创建一个派生类时，如果需要重写该类原有的虚拟方法，派生类中，可以增加相关的属性将类原有的虚拟函数指针保存，然后给虚拟函数赋予新的函数指针，保证父类原有的虚拟函数指针不会丢失：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; MyState MyState&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;MyDoSomething&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; MyClass &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass parent_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyDoSomething do_something&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; MyClass&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; my_do_something&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; do something&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; my_class_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;oc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;oc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;do_something&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; my_do_something&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo my_type_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_OBJECT&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .instance_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyState&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyClass&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_init &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; my_class_init&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; DerivedClass &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyClass parent_class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyDoSomething parent_do_something&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; DerivedClass&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; derived_do_something&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DerivedClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;dc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DERIVED_GET_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; do something here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;parent_do_something&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; do something else here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; derived_class_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;oc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MyClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; MY_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;oc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DerivedClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;dc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DERIVED_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;oc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;parent_do_something&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; mc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;do_something&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mc&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;do_something&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; derived_do_something&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; TypeInfo derived_type_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_DERIVED&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; TYPE_MY&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_size &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DerivedClass&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .class_init &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; derived_class_init&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;re-cha-ba&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#re-cha-ba&quot; aria-label=&quot;Anchor link for: re-cha-ba&quot;&gt;热插拔&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;由于类的初始化过程不能失败，因此设备一般会有两个辅助函数 &lt;code&gt;realize&lt;/code&gt; 和 &lt;code&gt;unrealize&lt;/code&gt; 来专门处理动态设备的创建。在调用 &lt;code&gt;realize&lt;/code&gt; 函数时，如果设备无法成功创建，则应设置 &lt;code&gt;Error **&lt;/code&gt; 指针。否则，在 &lt;code&gt;realize&lt;/code&gt; 函数成功返回后，设备对象将被添加到 QOM 树中，并对客户机可见。与 &lt;code&gt;realize&lt;/code&gt; 函数功能相反的是 &lt;code&gt;unrealize&lt;/code&gt; 函数，主要负责在系统完成设备的使用之后清理释放资源。&lt;/p&gt;
&lt;p&gt;QEMU 中所有设备都可以通过 C 代码实例化，但是只有部分设备可以通过命令行或者 QEMU Monitor 动态创建。同样，只有部分设备支持热插拔，即可以在创建后拔下，这需要给出明确的 &lt;code&gt;unrealize&lt;/code&gt; 函数实现。另外，只有当设备的父总线注册了 &lt;code&gt;HotplugHandler&lt;/code&gt; 时，设备才能被顺利拔出。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文聚焦 QEMU 中面向对象的设备管理机制，阐述了引入对象模型的必要性，介绍了 QOM 基本功能和顶层设计，分析了 &lt;code&gt;Object&lt;/code&gt; 和 &lt;code&gt;ObjectClass&lt;/code&gt; 的结构与联系，梳理了面向对象的设备管理中设备的层次关系，总结归纳了使用 QOM 接口管理设备的一般方法。在下一篇文章中，我们将继续深入，分析 QOM 面向对象特性的底层实现。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://blog.csdn.net/leiyanjie8995/article/details/124613572&quot;&gt;QOM 设备管理机制概述&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/devel/qom.html&quot;&gt;The QEMU Object Model (QOM)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 设备模型简析（一）：生命周期</title>
        <published>2023-08-22T00:00:00+00:00</published>
        <updated>2023-08-22T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-device-model-part1/"/>
        <id>https://jjl9807.com/posts/qemu-system-device-model-part1/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-device-model-part1/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part1/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 系统模拟模式能够提供运行虚拟机所需的完整环境，包括 CPU，内存和外部设备等。其中，设备模拟是系统模拟模式的重要组成部分，也是系统模拟模式和用户模拟模式的本质区别之一。设备模型是 QEMU 中用于描述和实现设备模拟的软件结构和框架，它为设备提供了标准化的接口和方法，使得开发者可以轻松地为 QEMU 添加新的设备。本文将以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例，分析介绍 QEMU 设备模型的生命周期。&lt;/p&gt;
&lt;h2 id=&quot;she-bei-lei-xing-zhu-ce&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#she-bei-lei-xing-zhu-ce&quot; aria-label=&quot;Anchor link for: she-bei-lei-xing-zhu-ce&quot;&gt;设备类型注册&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;ding-yi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ding-yi&quot; aria-label=&quot;Anchor link for: ding-yi&quot;&gt;定义&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 模拟的每一种设备都必须定义对应的设备类型，这个设备类型在代码中由结构体 &lt;code&gt;TypeInfo&lt;/code&gt; 描述：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qom/object.h: 412 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; TypeInfo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; instance_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; instance_align&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_post_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_finalize&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; abstract&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; class_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class_base_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;class_data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    InterfaceInfo &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该结构体的成员变量比较繁多，目前只需要关注以下两个成员：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;name：&lt;/strong&gt; 设备类型名称&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;parent：&lt;/strong&gt; 父设备类型名称&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过这两个变量我们可以发现，QEMU 设备模型中使用名称作为设备类型的唯一标识，并且设备类型之间还存在继承关系。&lt;/p&gt;
&lt;h3 id=&quot;zhu-ce&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-ce&quot; aria-label=&quot;Anchor link for: zhu-ce&quot;&gt;注册&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成设备类型的定义后，必须注册这一设备类型，以通知 QEMU 系统可以支持这一类型的设备，为后续添加这一类型的设备准备条件。注册工作由 &lt;code&gt;type_register&lt;/code&gt; 函数负责：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 140 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_register_internal&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;const&lt;/span&gt;&lt;span&gt; TypeInfo &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    type_table_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;const&lt;/span&gt;&lt;span&gt; TypeInfo &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_register_internal&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数通过调用 &lt;code&gt;type_new&lt;/code&gt; 生成一个 &lt;code&gt;TypeInfo&lt;/code&gt; 对应的 &lt;code&gt;TypeImpl&lt;/code&gt; 类型，并以 &lt;code&gt;name&lt;/code&gt; 为关键字添加到名为 &lt;code&gt;type_table&lt;/code&gt; 的一个哈希表中。&lt;code&gt;type_table&lt;/code&gt; 是 QEMU 维护的一个全局的类型哈希表，使用类型名字符串索引到具体的 &lt;code&gt;TypeImpl&lt;/code&gt; 对象。&lt;/p&gt;
&lt;p&gt;下面给出 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体的定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 48 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; TypeImpl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; class_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; instance_size&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; instance_align&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class_base_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;class_data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_post_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;instance_finalize&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; abstract&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;parent_type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; num_interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    InterfaceImpl &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;interfaces&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;MAX_INTERFACES&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过观察不难发现 &lt;code&gt;TypeInfo&lt;/code&gt; 和 &lt;code&gt;TypeImpl&lt;/code&gt; 两个结构体的结构相似，绝大多数成员变量都相同，那么为什么注册过程中不直接使用，而要重新复制一遍呢？这与 QEMU 对象系统的设计理念有关，&lt;code&gt;TypeInfo&lt;/code&gt; 结构体是面向 API 使用者的一个工具，使用者只有在注册设备类型的时候会使用到 &lt;code&gt;TypeInfo&lt;/code&gt;，提供类型注册所需的必要信息和回调函数，此后 QEMU 会根据 &lt;code&gt;TypeInfo&lt;/code&gt; 自动生成对应的 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体，至此 &lt;code&gt;TypeInfo&lt;/code&gt; 的生命周期就结束了。换句话说，&lt;code&gt;TypeInfo&lt;/code&gt; 保存静态的注册数据，而 &lt;code&gt;TypeImpl&lt;/code&gt; 保存动态的运行数据，这种设计降低了系统的耦合度，提升了稳定性。&lt;/p&gt;
&lt;p&gt;下面我们来分析 &lt;code&gt;type_register()&lt;/code&gt; 函数的调用时机，这里就需要引申出另一个问题，就是注册函数本身也有 “注册 - 执行” 机制。我们以虚拟网卡设备 e1000 为例进行分析：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; hw/e1000.c: 1822 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; e1000_register_types&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    type_register_static&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;e1000_base_info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ARRAY_SIZE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e1000_devices&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        const&lt;/span&gt;&lt;span&gt; E1000Info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;e1000_devices&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TypeInfo type_info &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type_info&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; info&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type_info&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; TYPE_E1000_BASE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type_info&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class_data&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        type_info&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class_init&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; e1000_class_init&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        type_register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;type_info&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e1000_register_types&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;函数 &lt;code&gt;e1000_register_types&lt;/code&gt; 负责执行 e1000 网卡的设备类型注册，注意最后一行代码调用 &lt;code&gt;type_init&lt;/code&gt; 函数对 &lt;code&gt;e1000_register_types&lt;/code&gt; 函数进行注册，下面给出 &lt;code&gt;type_init&lt;/code&gt; 函数的定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qemu/module.h: 56 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;function&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; module_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; MODULE_INIT_QOM&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;type_init&lt;/code&gt; 函数实际上是通过宏的形式对 &lt;code&gt;module_init&lt;/code&gt; 进行包装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qemu/module.h: 35 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; module_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                                         \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; __attribute__&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; do_qemu_init_ ## &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                                                                           \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    register_module_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                                   \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们需要关注的是这个修饰 &lt;code&gt;__attribute__((constructor))&lt;/code&gt;，它是 GCC 的一个扩展，用于确保被修饰的函数在 &lt;code&gt;main&lt;/code&gt; 函数执行之被调用。仍然以上文的 e1000 网卡为例，调用 &lt;code&gt;type_init&lt;/code&gt; 时传入的函数名为 &lt;code&gt;e1000_register_types&lt;/code&gt;，这个宏的作用就是生成函数 &lt;code&gt;static void do_qemu_init_e1000_register_types(void)&lt;/code&gt;，并保证其在 &lt;code&gt;main&lt;/code&gt; 函数之前被调用，以达到自动初始化的目的。&lt;/p&gt;
&lt;p&gt;下面分析 &lt;code&gt;register_module_init&lt;/code&gt; 函数的行为：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/module.c: 70 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; register_module_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; module_init_type &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ModuleEntry &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ModuleTypeList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    e &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_malloc0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; fn&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    l &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_type&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_INSERT_TAIL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;QEMU 维护了一个全局的链表头数组 &lt;code&gt;init_type_list&lt;/code&gt;，分别指向不同类型的注册函数链表，具体如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part1/./init-type-list.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;register_module_init&lt;/code&gt; 函数会将待注册的设备类型注册函数，这里的例子中是 &lt;code&gt;e1000_register_types&lt;/code&gt;，添加到 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 下标所指向的链表尾部，完成注册工作。直到此时，真正的设备类型注册函数都没有执行，到底什么时候进行设备类型的注册呢？在&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/tinylab/riscv-linux/blob/master/articles/20230801-qemu-system-event-loop-part2.md&quot;&gt;之前的文章&lt;/a&gt;中，我们有分析过 QEMU 主事件循环的一般执行流程，&lt;code&gt;main&lt;/code&gt; 函数会调用 &lt;code&gt;qemu_init&lt;/code&gt; 函数进行初始化，&lt;code&gt;qemu_init&lt;/code&gt; 在执行过程中会调用 &lt;code&gt;qemu_init_subsystems&lt;/code&gt; 函数，而 &lt;code&gt;qemu_init_subsystems&lt;/code&gt; 则会调用 &lt;code&gt;module_call_init&lt;/code&gt; 函数，并传入参数 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/module.c: 755 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; module_call_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;module_init_type &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ModuleTypeList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ModuleEntry &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;modules_init_done&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    l &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_type&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_FOREACH&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; l&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;    modules_init_done&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里 &lt;code&gt;module_call_init&lt;/code&gt; 函数作用就是找到 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 对应的链表，然后依次执行链表项中的 &lt;code&gt;init&lt;/code&gt; 成员函数，对于 e1000 网卡而言就是之前通过 &lt;code&gt;register_module_init&lt;/code&gt; 注册的 &lt;code&gt;e1000_register_types&lt;/code&gt; 函数。&lt;/p&gt;
&lt;p&gt;到此为止，设备类型注册的逻辑链条就算完整了。&lt;/p&gt;
&lt;h2 id=&quot;she-bei-lei-xing-chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#she-bei-lei-xing-chu-shi-hua&quot; aria-label=&quot;Anchor link for: she-bei-lei-xing-chu-shi-hua&quot;&gt;设备类型初始化&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;设备类型注册后，在使用之前需要初始化该类型，并生成对应的 &lt;code&gt;ObjectClass&lt;/code&gt; 对象。&lt;/p&gt;
&lt;p&gt;这里回顾一下上文介绍的 &lt;code&gt;TypeImpl&lt;/code&gt; 结构体，可以发现其中有一个名为 &lt;code&gt;class&lt;/code&gt; 的 &lt;code&gt;ObjectClass&lt;/code&gt; 类型的成员变量，所谓初始化其实就是初始化这个 &lt;code&gt;class&lt;/code&gt; 成员，负责具体初始化工作的是 &lt;code&gt;type_initialize&lt;/code&gt; 函数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; qom/object.c: 286 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_initialize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_class_get_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_object_get_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Any type with zero instance_size is implicitly abstract.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * This means interface types are all abstract.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_is_ancestor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type_interface&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_post_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_finalize&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;num_interfaces&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_malloc0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_get_parent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        type_initialize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        GSList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_size&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        memcpy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_size&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; e &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            InterfaceClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;iface &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ObjectClass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;klass &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; OBJECT_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;iface&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            type_initialize_interface&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; iface&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interface_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; klass&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;num_interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;t &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_get_by_name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;missing interface &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39; for object &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                             ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                abort&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;interfaces&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; e &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                TypeImpl &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;target_type &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; OBJECT_CLASS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;type_is_ancestor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target_type&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                    break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                continue&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            type_initialize_interface&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;properties&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_hash_table_new_full&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;g_str_hash&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; g_str_equal&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                  object_property_free&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_base_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            parent&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;class_base_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; type_get_parent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;parent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_init&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;class_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;class_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;type_initialize&lt;/code&gt; 函数首先执行一些必要的检查，接着会设置类型的大小并创建该类型，设置类型实例的大小，为实例化设备做准备，
然后初始化父设备类型和接口类型，最后调用父设备类型的 &lt;code&gt;class_base_init&lt;/code&gt; 和自己的 &lt;code&gt;class_init&lt;/code&gt; 完成初始化工作。&lt;/p&gt;
&lt;p&gt;此外，通过上述代码我们还可以得出两点结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QEMU 设备管理是一个树型结构&lt;/li&gt;
&lt;li&gt;QEMU 设备模型采用了面向对象的思想，存在继承关系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文重点关注设备的生命周期，以上两点这里不展开讨论，在后面的文章中会专题分析。&lt;/p&gt;
&lt;h2 id=&quot;she-bei-shi-li-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#she-bei-shi-li-hua&quot; aria-label=&quot;Anchor link for: she-bei-shi-li-hua&quot;&gt;设备实例化&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;完成了设备类型的初始化，接着就要实例化设备了，这个过程由 &lt;code&gt;object_initialize&lt;/code&gt; 函数实现，而 &lt;code&gt;object_initialize&lt;/code&gt; 又通过调用 &lt;code&gt;object_initialize_with_type&lt;/code&gt; 完成实例化工作。抽象地看，设备实例化主要完成三件事：首先，建立 &lt;code&gt;Object&lt;/code&gt; 和 &lt;code&gt;ObjectClass&lt;/code&gt; 之间的关联；然后，递归调用父类型的 &lt;code&gt;instance_init&lt;/code&gt; 函数；最后，调用自己的 &lt;code&gt;instance_init&lt;/code&gt; 函数。需要注意的是，这种抽象的视角简化了设备实例化流程，也模糊了很多真实场景下的具体细节。&lt;/p&gt;
&lt;h3 id=&quot;shi-li-hua-han-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-li-hua-han-shu&quot; aria-label=&quot;Anchor link for: shi-li-hua-han-shu&quot;&gt;实例化函数&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;下面以 &lt;code&gt;DeviceClass&lt;/code&gt; 为例详细分析设备的实例化过程。&lt;code&gt;DeviceClass&lt;/code&gt; 是 QEMU 设备模型的核心组件，它继承自 &lt;code&gt;ObjectClass&lt;/code&gt;，提供了设备的基本行为和属性的模板，是很多设备的父类，其实例化过程很有代表性。下图给出了 &lt;code&gt;DeviceClass&lt;/code&gt; 有关类和对象之间的关系：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part1/./device-class.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里我们需要关注的是负责实例化 &lt;code&gt;DeviceClass&lt;/code&gt; 的函数 &lt;code&gt;device_initfn&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; hw/core/qdev.c: 652 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; device_initfn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Object &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DeviceState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;dev &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DEVICE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;phase_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PHASE_MACHINE_READY&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;hotplugged&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        qdev_hot_added &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;instance_id_alias&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;realized&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;allow_unplug_during_migration&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QLIST_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;gpios&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QLIST_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;clocks&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;device_initfn&lt;/code&gt; 函数的整体执行逻辑比较简单，主要分为以下四个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设备状态转换：&lt;/strong&gt; 将传入的 &lt;code&gt;Object&lt;/code&gt; 指针转换为 &lt;code&gt;DeviceState&lt;/code&gt; 指针。&lt;code&gt;DEVICE&lt;/code&gt; 是一个宏，用于从基类 &lt;code&gt;Object&lt;/code&gt; 转换到派生类 &lt;code&gt;DeviceState&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检查机器准备状态：&lt;/strong&gt; 使用 &lt;code&gt;phase_check&lt;/code&gt; 函数检查当前的机器初始化阶段是否为 &lt;code&gt;PHASE_MACHINE_READY&lt;/code&gt;。如果是，则设置设备的 &lt;code&gt;hotplugged&lt;/code&gt; 属性为 1，表示该设备是在虚拟机已经启动后热插入的。同时，全局变量 &lt;code&gt;qdev_hot_added&lt;/code&gt; 被设置为 &lt;code&gt;true&lt;/code&gt;，表示有设备被热插入&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化设备属性：&lt;/strong&gt;&lt;code&gt;instance_id_alias&lt;/code&gt; 被设置为 &lt;code&gt;-1&lt;/code&gt;，表示没有别名；&lt;code&gt;realized&lt;/code&gt; 被设置为 &lt;code&gt;false&lt;/code&gt;，表示设备尚未实现；&lt;code&gt;allow_unplug_during_migration&lt;/code&gt; 被设置为 &lt;code&gt;false&lt;/code&gt;，表示在迁移期间不允许拔出此设备&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化设备的 GPIO 和时钟列表：&lt;/strong&gt; 使用 &lt;code&gt;QLIST_INIT&lt;/code&gt; 宏初始化了设备的 GPIO 和时钟列表&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;realized-shu-xing-she-zhi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#realized-shu-xing-she-zhi&quot; aria-label=&quot;Anchor link for: realized-shu-xing-she-zhi&quot;&gt;realized 属性设置&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;我们注意到 &lt;code&gt;device_initfn&lt;/code&gt; 函数将 &lt;code&gt;DeviceState&lt;/code&gt; 的 &lt;code&gt;realized&lt;/code&gt; 设置为 &lt;code&gt;false&lt;/code&gt;，意味着这个设备还没有被实现，那么这个属性究竟是什么时候被设置为 &lt;code&gt;true&lt;/code&gt; 的呢？通过分析 QEMU 的启动流程，可以梳理出如下函数调用链：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-device-model-part1/./qdev-realize.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;QEMU 在初始化阶段经过一系列函数调用，最终调用 &lt;code&gt;qdev_realize&lt;/code&gt; 函数，该函数是 QEMU 设备模型中的一个核心函数，用于激活设备，也就是将设备对应的 &lt;code&gt;DeviceState&lt;/code&gt; 结构的 &lt;code&gt;realized&lt;/code&gt; 属性设置为 &lt;code&gt;true&lt;/code&gt;，表示设备已经被实例化并准备好在模拟环境中运行。在设置 &lt;code&gt;realized&lt;/code&gt; 属性之前，函数会执行一些基础的检查，以确保设备尚未被实例化并且没有父总线，然后函数会检查设备总线类型并设置父总线，最后调用 &lt;code&gt;object_property_set_bool&lt;/code&gt; 函数设置 &lt;code&gt;realized&lt;/code&gt; 属性为 &lt;code&gt;true&lt;/code&gt;，完成设备实例化。&lt;/p&gt;
&lt;h2 id=&quot;she-bei-xiao-hui&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#she-bei-xiao-hui&quot; aria-label=&quot;Anchor link for: she-bei-xiao-hui&quot;&gt;设备销毁&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;设备销毁的步骤与设备创建过程正好相反，一般包含以下四个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设备反实例化：&lt;/strong&gt; 停止操作设备并释放占用资源后，通过代码 &lt;code&gt;object_property_set_bool(OBJECT(dev), &quot;realized&quot;, false, &amp;amp;error)&lt;/code&gt; 把 &lt;code&gt;realized&lt;/code&gt; 属性设置为 &lt;code&gt;false&lt;/code&gt;，标记设备已经反实例化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;从总线中移除：&lt;/strong&gt; 设备通常连接到一个总线，在销毁设备之前，需要将其从父总线中移除&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;销毁设备对象：&lt;/strong&gt; 调用 &lt;code&gt;object_unref&lt;/code&gt; 函数减少设备对象的引用计数，当引用计数降为 0 时，并调用设备对象的析构函数，释放所占内存空间及其他资源&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反注册设备类型：&lt;/strong&gt; 有时可能还需要反注册设备类型，注销回调函数，清理释放为设备分配的各种资源&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总而言之，设备的销毁过程可以视作设备添加过程的逆操作，除了顺序相反之外，执行流程基本相似，设备销毁的细节也不是本文关注的重点，这里仅介绍主要步骤，不再详细分析。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文从设备的生命周期这一角度入手，介绍了设备类型注册、设备类型初始化、设备实例化等环节的基本原理和执行流程，打通了从设备类型表创建到设备销毁的逻辑链条，在一个较为抽象的层面对 QEMU 设备模型进行了初步分析。下一篇文章中，我们将专题介绍 QEMU 对象模型以及面向对象的设备管理方法。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/devel/qom.html&quot;&gt;The QEMU Object Model (QOM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://richardweiyang-2.gitbook.io/understanding_qemu&quot;&gt;understanding_qemu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/6844903845550620685&quot;&gt;浅谈 QEMU 的对象系统&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>本地分支与上游仓库同步</title>
        <published>2023-08-21T00:00:00+00:00</published>
        <updated>2023-08-21T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/git-sync-with-upstream/"/>
        <id>https://jjl9807.com/posts/git-sync-with-upstream/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/git-sync-with-upstream/">&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;克隆仓库到本地&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加上游仓库的远程分支&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; remote&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; add&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; upstream&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;source-repo-ur&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看仓库远程分支&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; remote&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从上游仓库 &lt;code&gt;main&lt;/code&gt; 分支进行拉取更新&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pull&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; upstream&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将本地拉取的更新推送到自己 Fork 的仓库&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; push&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; origin&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>云服务器从网络安装操作系统</title>
        <published>2023-08-20T00:00:00+00:00</published>
        <updated>2023-08-20T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/install-linux-with-network-bootloader/"/>
        <id>https://jjl9807.com/posts/install-linux-with-network-bootloader/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/install-linux-with-network-bootloader/">&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载 iPXE Linux 内核文件并重命名放至合适位置。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;wget&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; https://boot.netboot.xyz/ipxe/netboot.xyz.lkrn&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /boot/generic-ipxe.lkrn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建 netboot.xyz initrd 文件以连接网络并指定文件下载源。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /boot/netboot.xyz-initrd&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\#!ipxe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\#/boot/netboot.xyz-initrd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;imgfree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;dhcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;set dns 8.8.8.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;ifopen net0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;chain --autofree https://boot.netboot.xyz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加 Grub2 启动菜单选项。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/grub.d/40_custom&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\#!/bin/sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;exec tail -n +3 $0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\# This file provides an easy way to add custom menu entries. Simply type the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\# menu entries you want to add after this comment. Be careful not to change&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;\# the &amp;#39;exec tail&amp;#39; line above.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;menuentry &amp;#39;netboot.xyz&amp;#39; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;set root=&amp;#39;hd0,msdos1&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;linux16 /boot/generic-ipxe.lkrn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;initrd16 /boot/netboot.xyz-initrd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;延长 Grub 启动菜单显示时间。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sed&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;s|^GRUB_TIMEOUT.*|GRUB_TIMEOUT=60|&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /etc/default/grub&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新 Grub 配置并重启，之后在启动菜单选择 netboot.xyz 进入。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;grub-mkconfig&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; /boot/grub/grub.cfg&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; reboot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入 netboot.xyz 后，选择 Linux Network Installs ，选择要安装的系统，选择图形化界面安装，之后等待下载好系统文件，便会转到系统安装界面。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 事件循环机制简析（三）：下半部机制</title>
        <published>2023-08-15T00:00:00+00:00</published>
        <updated>2023-08-15T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-event-loop-part3/"/>
        <id>https://jjl9807.com/posts/qemu-system-event-loop-part3/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-event-loop-part3/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part3/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在&lt;a href=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part2/&quot;&gt;上一篇文章&lt;/a&gt;中，我们详细分析了 QEMU 事件循环机制的基本组成，包括事件源、状态机回调函数以及 poll 机制，介绍了 QEMU 主事件循环的运行流程，本文将在此基础上进一步深入，以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例，分析 QEMU 下半部（Bottom Halves，BH）机制。&lt;/p&gt;
&lt;p&gt;在操作系统内核中，下半部是一个延迟执行的函数，在中断上下文之外运行。在 QEMU 中，下半部用于异步事件处理，QEMU 下半部机制利用事件循环机制，向其他模块提供异步调用的接口。因为其它模块的运行可能不在主线程中，但它想把自己注册的函数加入到 QEMU 主线程中运行，这时就可以使用下半部机制。QEMU 下半部功能在一个事件循环中实现，当下半部函数注册到一个事件循环中，这个事件循环在下一次 poll 的时候，就会调用该函数，从而实现异步延迟调用的效果。&lt;/p&gt;
&lt;h2 id=&quot;shu-ju-jie-gou&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#shu-ju-jie-gou&quot; aria-label=&quot;Anchor link for: shu-ju-jie-gou&quot;&gt;数据结构&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 将下半部机制所有必要信息（关联事件源、名称、回调函数和状态）进行抽象，封装为 &lt;code&gt;QEMUBH&lt;/code&gt; 结构体：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 61 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; QEMUBH &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUBHFunc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;cb&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_ENTRY&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    unsigned&lt;/span&gt;&lt;span&gt; flags&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面逐一分析该结构体各成员变量的含义与作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AioContext *ctx：&lt;/strong&gt; 指向 &lt;code&gt;AioContext&lt;/code&gt; 的指针，代表与下半部关联的异步 I/O 上下文。这允许 QEMU 在不同的上下文中处理不同的事件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;const char *name：&lt;/strong&gt; 下半部名称&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QEMUBHFunc *cb：&lt;/strong&gt; 指向回调函数的指针，当下半部被触发时，这个函数会被调用，这个回调函数通常会处理与下半部关联的事件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;void *opaque：&lt;/strong&gt; 指向数据的指针，它可以在回调函数中使用，一般用于为回调函数提供参数或者额外的上下文数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QSLIST_ENTRY(QEMUBH) next：&lt;/strong&gt; 一个用于将 &lt;code&gt;QEMUBH&lt;/code&gt; 结构体插入到单向链表的宏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;unsigned flags：&lt;/strong&gt; 用于存储底部半部的状态和属性的标志位，表示底部半部是否已经被调度或是否已经被删除&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中，&lt;code&gt;flags&lt;/code&gt; 标志一共有五种：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 44 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;enum&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Already enqueued and waiting for aio_bh_poll() &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BH_PENDING   &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Invoke the callback &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BH_SCHEDULED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Delete without invoking callback &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BH_DELETED   &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Delete after invoking callback &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BH_ONESHOT   &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Schedule periodically when the event loop is idle &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BH_IDLE      &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述五种标志分别对应如下含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BH_PENDING：&lt;/strong&gt; 表示下半部已经入队并等待 &lt;code&gt;aio_bh_poll()&lt;/code&gt; 的处理，当一个下半部被调度但尚未执行时，设置为该状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BH_SCHEDULED：&lt;/strong&gt; 表示下半部的回调函数应该被调用，当下半部被调度并准备执行其回调函数时，设置为该状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BH_DELETED：&lt;/strong&gt; 表示下半部应该被删除，但在删除之前不应该调用其回调函数，这通常在下半部不再需要时使用以确保其回调函数不被执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BH_ONESHOT：&lt;/strong&gt; 表示下半部应该在调用其回调函数后被删除，一般用于标示只需要执行一次的下半部&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BH_IDLE：&lt;/strong&gt; 表示下半部应该在事件循环空闲时被周期性地调度，一般用于标示需要在没有其他活动时执行的任务很有用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么需要设置 &lt;code&gt;flag&lt;/code&gt; 标志？因为 QEMU 下半部的注册和执行是异步的，因此需要有一种方法用来通知执行者下半部应该怎样执行。&lt;code&gt;flag&lt;/code&gt; 标志的设置提供了一种方式来控制和管理下半部的行为。例如，可以组合使用这五种标志来确定是否应该执行下半部的回调函数，或者下半部是否应该在执行后被删除。&lt;/p&gt;
&lt;h2 id=&quot;cao-zuo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cao-zuo&quot; aria-label=&quot;Anchor link for: cao-zuo&quot;&gt;操作&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;gua-zai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gua-zai&quot; aria-label=&quot;Anchor link for: gua-zai&quot;&gt;挂载&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 下半部在一个事件循环中实现，因此新建下半部需要指出基于哪个 &lt;code&gt;AioContext&lt;/code&gt;，同时要指定下半部中需要执行什么函数以及函数参数，下半部的创建由 &lt;code&gt;aio_bh_new_full&lt;/code&gt; 函数具体执行：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 139 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_bh_new_full&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QEMUBHFunc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                        const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;QEMUBH&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .cb &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .opaque &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下半部创建后需要挂载到相应 &lt;code&gt;AioContext&lt;/code&gt; 的下半部列表中，该操作由 &lt;code&gt;aio_bh_enqueue&lt;/code&gt; 完成：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 71 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_bh_enqueue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; unsigned&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; new_flags&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; bh&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    unsigned&lt;/span&gt;&lt;span&gt; old_flags&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Synchronizes with atomic_fetch_and() in aio_bh_dequeue(), ensuring that&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * insertion starts after BH_PENDING is set.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    old_flags &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qatomic_fetch_or&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; BH_PENDING &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; new_flags&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;old_flags &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; BH_PENDING&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * At this point the bottom half becomes visible to aio_bh_poll().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * This insertion thus synchronizes with QSLIST_MOVE_ATOMIC in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * aio_bh_poll(), ensuring that:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * 1. any writes needed by the callback are visible from the callback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         *    after aio_bh_dequeue() returns bh.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * 2. ctx is loaded before the callback has a chance to execute and bh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         *    could be freed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        QSLIST_INSERT_HEAD_ATOMIC&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_notify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Workaround for record/replay.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * vCPU execution should be suspended when new BH is set.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * This is needed to avoid guest timeouts caused&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * by the long cycles of the execution.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    icount_notify_exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个 &lt;code&gt;AioContext&lt;/code&gt; 上可以有多个下半部挂载，下半部通过 &lt;code&gt;AioContext&lt;/code&gt; 的 &lt;code&gt;bh_list&lt;/code&gt; 成员以及自身数据结构中的 &lt;code&gt;next&lt;/code&gt; 指针被维护成一个单向链表，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part3/./bh-list.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;QEMU 主线程有默认的事件循环 &lt;code&gt;qemu_aio_context&lt;/code&gt;，将下半部挂载到主线程的事件循环可以调用封装好的内部接口 &lt;code&gt;qemu_bh_new&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/qemu/main-loop.h: 390 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_bh_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_bh_new_full&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cb&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cb&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般 QEMU 下半部的执行方式是调用 &lt;code&gt;qemu_bh_schedule&lt;/code&gt; 函数，将 &lt;code&gt;flag&lt;/code&gt; 标志设置为 &lt;code&gt;BH_SCHEDULED&lt;/code&gt;，即该下半部应该被计划执行：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 199 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_bh_schedule&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_bh_enqueue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; BH_SCHEDULED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过这种方式执行的下半部在执行一次以后不会被删除，因此下一次调度执行不需要重新注册。而通过 &lt;code&gt;aio_bh_schedule_oneshot_full&lt;/code&gt; 接口创建并执行的下半部会在创建后尽快执行一次，然后就被删除：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 125 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_bh_schedule_oneshot_full&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QEMUBHFunc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                                  void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;QEMUBH&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .cb &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .opaque &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; opaque&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .name &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_bh_enqueue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; BH_SCHEDULED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; BH_ONESHOT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;观察代码可以发现，&lt;code&gt;aio_bh_schedule_oneshot_full&lt;/code&gt; 和 &lt;code&gt;qemu_bh_schedule&lt;/code&gt; 函数主要有两处不同：&lt;code&gt;aio_bh_schedule_oneshot_full&lt;/code&gt; 函数能够创建新的下半部，并且挂载时的 &lt;code&gt;flag&lt;/code&gt; 标志比 &lt;code&gt;qemu_bh_schedule&lt;/code&gt; 函数多一个 &lt;code&gt;BH_ONESHOT&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&quot;tong-zhi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tong-zhi&quot; aria-label=&quot;Anchor link for: tong-zhi&quot;&gt;通知&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 下半部挂载到对应 &lt;code&gt;AioContext&lt;/code&gt; 上并不会被立即执行，只有当事件循环的执行线程 poll 到 fd 准备好之后，才会触发回调执行下半部，如果对应 &lt;code&gt;AioContext&lt;/code&gt; 的 fd 一直没有准备就绪，那么 poll 就一直不返回，挂载在上面的下半部就会一直得不到执行。为避免这类问题，QEMU 实现了下半部调度接口，用于通知事件循环调度下半部。&lt;/p&gt;
&lt;p&gt;下半部调度接口通过 eventfd 实现，evenfd 可以用于线程间通信。QEMU 在 &lt;code&gt;aio_context_new&lt;/code&gt; 创建 &lt;code&gt;AioContext&lt;/code&gt; 时通过调用 &lt;code&gt;event_notifier_init&lt;/code&gt; 函数初始化 &lt;code&gt;EventNotifier&lt;/code&gt;，将 &lt;code&gt;EventNotifier&lt;/code&gt; 中的 &lt;code&gt;rfd&lt;/code&gt; 设置 &lt;code&gt;aio_set_event_notifier&lt;/code&gt; 为事件循环要监听的 fd。当一个线程把自己的下半部挂载到 &lt;code&gt;AioContext&lt;/code&gt; 上后，向 &lt;code&gt;EventNotifier&lt;/code&gt; 中的 &lt;code&gt;wfd&lt;/code&gt; 写入内容，另一端监听 &lt;code&gt;rfd&lt;/code&gt; 的事件循环就会 poll 到其上有事件，然后触发下半部的调度：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 542 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_context_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; event_notifier_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_set_event_notifier&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                           false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_poll&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_poll_ready&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;zhi-xing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-xing&quot; aria-label=&quot;Anchor link for: zhi-xing&quot;&gt;执行&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;事件循环在 poll 到 fd 准备好之后，会调度 QEMU 定制的状态机回调函数 &lt;code&gt;aio_ctx_dispatch&lt;/code&gt;，其主要功能是执行 fd 对应的回调函数，但在此之前会先检查 &lt;code&gt;AioContext&lt;/code&gt; 上是否挂载有下半部，如果有则会先执行下半部。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aio_ctx_dispatch&lt;/code&gt; 和 &lt;code&gt;aio_dispatch&lt;/code&gt; 函数在&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/tinylab/riscv-linux/blob/master/articles/20230801-qemu-system-event-loop-part2.md&quot;&gt;上一篇文章&lt;/a&gt;中已经详细分析过，本文不再赘述，这里我们重点关注具体落实下半部调度执行的函数 &lt;code&gt;aio_bh_poll&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 159 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_bh_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BHListSlice slice&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BHListSlice &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Synchronizes with QSLIST_INSERT_HEAD_ATOMIC in aio_bh_enqueue(). &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_MOVE_ATOMIC&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSIMPLEQ_INSERT_TAIL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_slice_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; QSIMPLEQ_FIRST&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_slice_list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        unsigned&lt;/span&gt;&lt;span&gt; flags&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_bh_dequeue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            QSIMPLEQ_REMOVE_HEAD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_slice_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            continue&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;flags &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;BH_SCHEDULED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; BH_DELETED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; BH_SCHEDULED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Idle BHs don&amp;#39;t count as progress &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;flags &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; BH_IDLE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            aio_bh_call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;flags &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;BH_DELETED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; BH_ONESHOT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_bh_poll&lt;/code&gt; 函数 QEMU 下半部机制的核心函数，这里首先定义了两个 &lt;code&gt;BHListSlice&lt;/code&gt; 变量和一个返回值 &lt;code&gt;ret&lt;/code&gt;。&lt;code&gt;BHListSlice&lt;/code&gt; 是一个结构，它包含一个 &lt;code&gt;BHList&lt;/code&gt; 类型的列表和一个后继指针 &lt;code&gt;next&lt;/code&gt;。接着，函数两个宏将当前 &lt;code&gt;AioContext&lt;/code&gt; 的 &lt;code&gt;bh_list&lt;/code&gt; 列表中所有下半部移动到一个新的 &lt;code&gt;BHListSlice&lt;/code&gt; 中，并将这个 &lt;code&gt;BHListSlice&lt;/code&gt; 添加到 &lt;code&gt;ctx-&amp;gt;bh_slice_list&lt;/code&gt; 的尾部。这样做的目的是保证处理下半部时“先来先处理”的顺序，即新添加的下半部总是在最后得到处理。最后，函数使用 &lt;code&gt;while&lt;/code&gt; 循环遍历 &lt;code&gt;bh_slice_list&lt;/code&gt; 中所有的 &lt;code&gt;BHListSlice&lt;/code&gt;，并更进一步地遍历 &lt;code&gt;BHListSlice&lt;/code&gt; 中每一个下半部，对于计划执行并且没有被标记删除的下半部，函数会调度执行，对于一次性的或者是被标记删除的下半部，函数会删除它并释放资源。&lt;/p&gt;
&lt;p&gt;在此过程中，有关数据结构的关系如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part3/./bh-slice-list.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;xie-zai&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xie-zai&quot; aria-label=&quot;Anchor link for: xie-zai&quot;&gt;卸载&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;下半部卸载是通过调用 &lt;code&gt;aio_bh_enqueue&lt;/code&gt; 函数更新 &lt;code&gt;flag&lt;/code&gt; 标志完成的，设置 &lt;code&gt;BH_DELETED&lt;/code&gt; 标志能够使下半部在下一次 dispatch 阶段被删掉并释放对应的内存空间：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 214 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_bh_delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_bh_enqueue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; BH_DELETED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;jin-yong&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jin-yong&quot; aria-label=&quot;Anchor link for: jin-yong&quot;&gt;禁用&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当我们希望下半部不再被事件循环调度，但又暂时不想删除这个下半部时可以调用 &lt;code&gt;qemu_bh_cancel&lt;/code&gt; 函数实现：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 206 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_bh_cancel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;bh&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qatomic_and&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ~&lt;/span&gt;&lt;span&gt;BH_SCHEDULED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个函数非常简洁，只有一行代码，使用原子操作来清除 &lt;code&gt;bh-&amp;gt;flags&lt;/code&gt; 中的 &lt;code&gt;BH_SCHEDULED&lt;/code&gt; 标志。&lt;code&gt;BH_SCHEDULED&lt;/code&gt; 标志表示这个下半部已经被计划执行，清除这个标志，意味着此后事件循环的 dispatch 时这个下半部不会再被调度执行。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文在前两篇文章的基础上，进一步分析了 QEMU 下半部机制，下半部利用事件循环机制，向其他模块提供异步调用的接口。文章梳理了下半部机制的主要数据结构以及它们之间的关系，介绍了 QEMU 下半部机制的执行原理，同时还整理了常见下半部操作的接口和用法。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://blog.csdn.net/huang987246510/article/details/100110183&quot;&gt;深入理解 QEMU 事件循环&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/link?target=http%3A%2F%2Fblog.vmsplice.net%2F2020%2F08%2Fqemu-internals-event-loops.html&quot;&gt;QEMU Internals: Event loops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 事件循环机制简析（二）：基本组成</title>
        <published>2023-08-07T00:00:00+00:00</published>
        <updated>2023-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-event-loop-part2/"/>
        <id>https://jjl9807.com/posts/qemu-system-event-loop-part2/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-event-loop-part2/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part2/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 采用了基于事件驱动的架构，其事件循环机制基于 glib 实现，&lt;a href=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part1/&quot;&gt;上一篇文章&lt;/a&gt;介绍了 glib 事件循环机制，本文将在此基础上以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例深入分析 QEMU 事件循环机制。&lt;/p&gt;
&lt;h2 id=&quot;gai-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gai-shu&quot; aria-label=&quot;Anchor link for: gai-shu&quot;&gt;概述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 的事件循环机制是其核心功能之一，用于协调虚拟机的各种异步操作。通过监听和调度各种事件源，它允许 QEMU 有效地响应外部输入、定时器事件等，从而实现高性能的虚拟化。&lt;/p&gt;
&lt;p&gt;QEMU 的默认事件循环是位于文件 &lt;code&gt;utils/main-loop.c&lt;/code&gt; 文件中的主循环 &lt;code&gt;main-loop&lt;/code&gt;，我们也可以使用选项 &lt;code&gt;–object iothread, id=&amp;lt;my_iothread_name&amp;gt;&lt;/code&gt; 自己创建事件循环。&lt;/p&gt;
&lt;h2 id=&quot;qemu-shi-jian-yuan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qemu-shi-jian-yuan&quot; aria-label=&quot;Anchor link for: qemu-shi-jian-yuan&quot;&gt;QEMU 事件源&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;尽管 QEMU 的事件循环机制基于 glib 实现，但是 QEMU 没有直接使用 glib 提供的事件源，而是自定义了一个新的事件源 &lt;code&gt;AioContext&lt;/code&gt;，主要有以下两种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;监听各种事件，例如 &lt;code&gt;iohandler_ctx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;处理块设备层的异步 I/O 请求，例如默认的 &lt;code&gt;qemu_aio_context&lt;/code&gt; 或者模块自己创建的 &lt;code&gt;AioContext&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; include/block/aio.h: 124 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; AioContext &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSource source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Used by AioContext users to protect from multi-threaded access.  &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuRecMutex lock&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Keep track of readers and writers of the block layer graph.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * This is essential to avoid performing additions and removal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * of nodes and edges from block graph while some&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * other thread is traversing it.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BdrvGraphRWlock &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;bdrv_graph&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; The list of registered AIO handlers.  Protected by ctx-&amp;gt;list_lock. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandlerList aio_handlers&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; The list of AIO handlers to be deleted.  Protected by ctx-&amp;gt;list_lock. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandlerList deleted_aio_handlers&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Used to avoid unnecessary event_notifier_set calls in aio_notify;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * only written from the AioContext home thread, or under the BQL in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * the case of the main AioContext.  However, it is read from any&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * thread so it is still accessed with atomic primitives.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * If this field is 0, everything (file descriptors, bottom halves,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * timers) will be re-evaluated before the next blocking poll() or&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * io_uring wait; therefore, the event_notifier_set call can be&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * skipped.  If it is non-zero, you may need to wake up a concurrent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * aio_poll or the glib main event loop, making event_notifier_set&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * necessary.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Bit 0 is reserved for GSource usage of the AioContext, and is 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * between a call to aio_ctx_prepare and the next call to aio_ctx_check.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Bits 1-31 simply count the number of active calls to aio_poll&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * that are in the prepare or poll phase.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * The GSource and aio_poll must use a different mechanism because&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * there is no certainty that a call to GSource&amp;#39;s prepare callback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * (via g_main_context_prepare) is indeed followed by check and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * dispatch.  It&amp;#39;s not clear whether this would be a bug, but let&amp;#39;s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * play safe and allow it---it will just cause extra calls to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * event_notifier_set until the next call to dispatch.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Instead, the aio_poll calls include both the prepare and the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * dispatch phase, hence a simple counter is enough for them.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    uint32_t&lt;/span&gt;&lt;span&gt; notify_me&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; A lock to protect between QEMUBH and AioHandler adders and deleter,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * and to ensure that no callbacks are removed while we&amp;#39;re walking and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * dispatching them.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuLockCnt list_lock&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Bottom Halves pending aio_bh_poll() processing &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BHList bh_list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Chained BH list slices for each nested aio_bh_poll() call &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSIMPLEQ_HEAD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; BHListSlice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; bh_slice_list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Used by aio_notify.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * &amp;quot;notified&amp;quot; is used to avoid expensive event_notifier_test_and_clear&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * calls.  When it is clear, the EventNotifier is clear, or one thread&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * is going to clear &amp;quot;notified&amp;quot; before processing more events.  False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * positives are possible, i.e. &amp;quot;notified&amp;quot; could be set even though the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * EventNotifier is clear.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Note that event_notifier_set *cannot* be optimized the same way.  For&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * more information on the problem that would result, see &amp;quot;#ifdef BUG2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * in the docs/aio_notify_accept.promela formal model.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; notified&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    EventNotifier notifier&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_HEAD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Coroutine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; scheduled_coroutines&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;co_schedule_bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; thread_pool_min&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; thread_pool_max&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Thread pool for performing work and receiving completion callbacks.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Has its own locking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; ThreadPool &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;thread_pool&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_LINUX_AIO&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * State for native Linux AIO.  Uses aio_context_acquire/release for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * locking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; LinuxAioState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;linux_aio&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_LINUX_IO_URING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * State for Linux io_uring.  Uses aio_context_acquire/release for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * locking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; LuringState &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;linux_io_uring&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; State for file descriptor monitoring using Linux io_uring &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; io_uring fdmon_io_uring&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandlerSList submit_list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; TimerLists for calling timers - one per clock type.  Has its own&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * locking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUTimerListGroup tlg&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; external_disable_cnt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Number of AioHandlers without .io_poll() &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; poll_disable_cnt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Polling mode parameters &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; poll_ns&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; current polling time in nanoseconds &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; poll_max_ns&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; maximum polling time in nanoseconds &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; poll_grow&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;      /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; polling time growth factor &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; poll_shrink&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; polling time shrink factor &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; AIO engine parameters &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; aio_max_batch&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;  /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; maximum number of requests in a batch &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * List of handlers participating in userspace polling.  Protected by&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * ctx-&amp;gt;list_lock.  Iterated and modified mostly by the event loop thread&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * from aio_poll() with ctx-&amp;gt;list_lock incremented.  aio_set_fd_handler()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * only touches the list to delete nodes if ctx-&amp;gt;list_lock&amp;#39;s count is zero.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandlerList poll_aio_handlers&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Are we in polling mode or monitoring file descriptors? &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; poll_started&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; epoll(7) state used when built with CONFIG_EPOLL &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; epollfd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span&gt; FDMonOps &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;fdmon_ops&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述结构体较为复杂，下面主要分析几个较为关键的成员变量的含义与作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GSource source：&lt;/strong&gt; glib 事件源，每一个 glib 自定义事件源的第一个成员必须是 &lt;code&gt;GSource&lt;/code&gt; 结构的成员&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QemuRecMutex lock：&lt;/strong&gt; 用于保护 &lt;code&gt;AioContext&lt;/code&gt; 的递归互斥锁，防止多线程访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AioHandlerList aio_handlers：&lt;/strong&gt; 一个链表头，其链表中的数据类型为 &lt;code&gt;AioHandler&lt;/code&gt;，所有加入到 &lt;code&gt;AioContext&lt;/code&gt; 事件源的文件 fd 的事件处理函数都挂载到该链表上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uint32_t notify_me&lt;/strong&gt;：用于避免在 &lt;code&gt;aio_notify&lt;/code&gt; 中进行不必要的 &lt;code&gt;event_notifier_set&lt;/code&gt; 调用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bool notified：&lt;/strong&gt;&lt;code&gt;notify_me&lt;/code&gt; 和 &lt;code&gt;notified&lt;/code&gt; 都与 &lt;code&gt;aio_notify&lt;/code&gt; 相关，主要用于在块设备层的 I/O 同步时处理 QEMU 下半部 (Bottom Halvs，BH)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BHList bh_list：&lt;/strong&gt; QEMU 下半部链表，用来连接挂到该事件源的下半部，QEMU 的 BH 默认挂载到 &lt;code&gt;qemu_aio_context&lt;/code&gt; 下&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EventNotifier notifier：&lt;/strong&gt; 事件通知对象，在块设备进行同步且需要调用 BH 的时候需要用到该成员&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QEMUTimerListGroup tlg：&lt;/strong&gt; 管理挂到该事件源的定时器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;AioContext&lt;/code&gt; 拓展了 glib 中事件源的功能，不但支持 fd 的事件处理，还模拟内核中的下半部机制，实现了 QEMU 中的下半部以及定时器的管理。&lt;code&gt;AioContext&lt;/code&gt; 可以通过调用 &lt;code&gt;aio_context_new&lt;/code&gt; 函数进行创建并初始化：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 542 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_context_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_source_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;aio_source_funcs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSIMPLEQ_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_slice_list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_context_setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; event_notifier_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_setg_errno&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Failed to initialize event notifier&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        goto&lt;/span&gt;&lt;span&gt; fail&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_set_can_recurse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_lockcnt_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;co_schedule_bh&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_bh_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; co_schedule_bh_cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_INIT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;scheduled_coroutines&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_set_event_notifier&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;                           false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_poll&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           aio_context_notifier_poll_ready&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_LINUX_AIO&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;linux_aio&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_LINUX_IO_URING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;linux_io_uring&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;thread_pool&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_rec_mutex_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    timerlistgroup_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;tlg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; aio_timerlist_notify&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_ns&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_max_ns&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_grow&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_shrink&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;aio_max_batch&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;thread_pool_min&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;thread_pool_max&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; THREAD_POOL_MAX_THREADS_DEFAULT&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    register_aiocontext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fail:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_destroy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_context_new&lt;/code&gt; 函数返回一个指向新创建的 &lt;code&gt;AioContext&lt;/code&gt; 的指针，并接受一个 &lt;code&gt;Error&lt;/code&gt; 指针的指针，用于报告初始化过程中出现的错误。该函数首先调用 &lt;code&gt;g_source_new&lt;/code&gt; 等函数完成 &lt;code&gt;AioContext&lt;/code&gt; 的创建、设置以及 QEMU 下半部列表的初始化，接着初始化事件通知器及其回调函数、初始化锁并设置协程调度，然后完成线程池、计时器列表、轮询参数等其他内容的初始化工作，最后注册新创建的 &lt;code&gt;AioContext&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;AioContext&lt;/code&gt; 的创建函数中，&lt;code&gt;aio_set_event_notifer&lt;/code&gt; 函数调用了 &lt;code&gt;aio_set_fd_handler&lt;/code&gt; 函数，后者用于添加或者删除 &lt;code&gt;AioContext&lt;/code&gt; 事件源中的 fd，如果是添加则会设置 fd 对应的读写函数。添加事件源中 fd 监听处理的具体过程如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/aio-posix.c: 100 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_set_fd_handler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                        int&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; fd&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                        bool&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; is_external&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        IOHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;io_read&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        IOHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;io_write&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        AioPollFn &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;io_poll&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        IOHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;io_poll_ready&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                        void&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;new_node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; is_new &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; deleted &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; poll_disable_change&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;io_poll &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;io_poll_ready&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        io_poll &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; polling only makes sense if there is a handler &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_lockcnt_lock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_aio_handler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; fd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Are we deleting the fd handler? &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;io_read &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;io_write &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;io_poll&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            qemu_lockcnt_unlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Clean events in order to unregister fd from the ctx epoll. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        poll_disable_change &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_poll&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        poll_disable_change &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;io_poll &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_poll&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            is_new &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Alloc and insert if it&amp;#39;s not already there &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_new0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioHandler&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Update handler with latest information &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_read&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; io_read&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_write&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; io_write&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_poll&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; io_poll&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_poll_ready&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; io_poll_ready&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; opaque&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;is_external&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; is_external&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;is_new&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; fd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_source_add_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;io_read &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;?&lt;/span&gt;&lt;span&gt; G_IO_IN &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; G_IO_HUP &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; G_IO_ERR &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        new_node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;io_write &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;?&lt;/span&gt;&lt;span&gt; G_IO_OUT &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; G_IO_ERR &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        QLIST_INSERT_HEAD_RCU&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;aio_handlers&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; new_node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; No need to order poll_disable_cnt writes against other updates;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * the counter is only used to avoid wasting time and latency on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * iterated polling when the system call will be ultimately necessary.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Changing handlers is a rare event, and a little wasted polling until&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * the aio_notify below is not an issue.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qatomic_set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_disable_cnt&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;               qatomic_read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;poll_disable_cnt&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; +&lt;/span&gt;&lt;span&gt; poll_disable_change&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fdmon_ops&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; new_node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        deleted &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_remove_fd_handler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_lockcnt_unlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_notify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;deleted&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数接受以下 6 个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AioContext *ctx：&lt;/strong&gt; 待添加 fd 的异步 I/O 上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;int fd：&lt;/strong&gt; 待处理的文件描述符&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bool is_external：&lt;/strong&gt; 用于块设备层，指示是否为外部事件，对于事件监听的 fd 都设置为 &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IOHandler *io_read：&lt;/strong&gt; 读取回调函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IOHandler *io_write：&lt;/strong&gt; 写入回调函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AioPollFn *io_poll：&lt;/strong&gt; 轮询回调函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IOHandler *io_poll_ready：&lt;/strong&gt; 轮询就绪回调函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;void *opaque：&lt;/strong&gt; 传递给回调函数的透明指针&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;aio_set_fd_handler&lt;/code&gt; 函数首先调用 &lt;code&gt;find_aio_handler&lt;/code&gt; 查找当前事件源中是否已有 fd，对于新加入的情况，这里会创建一个名为 &lt;code&gt;node&lt;/code&gt; 的 &lt;code&gt;AioHandler&lt;/code&gt;，使用 fd 初始化 &lt;code&gt;node-&amp;gt;pfd.fd&lt;/code&gt;，并将其插入到 &lt;code&gt;ctx-&amp;gt;aio_handlers&lt;/code&gt; 链表上，调用 glib 接口函数 &lt;code&gt;g_source_add_poll&lt;/code&gt; 将该 fd 插入到了事件源监听 fd 列表中。最后设置 &lt;code&gt;node&lt;/code&gt; 的事件读写函数为 &lt;code&gt;io_read&lt;/code&gt; 和 &lt;code&gt;io_write&lt;/code&gt;，根据 &lt;code&gt;io_read&lt;/code&gt; 和 &lt;code&gt;io_write&lt;/code&gt; 的有无设置 &lt;code&gt;node-&amp;gt;pfd.events&lt;/code&gt;，即要监听的事件。在 &lt;code&gt;aio_set_fd_handler&lt;/code&gt; 执行完成之后，新的 fd 事件就加入到了事件源的 &lt;code&gt;aio_handlers&lt;/code&gt; 链表上了，具体如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part2/./aio-handlers.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;zhuang-tai-ji-hui-diao-han-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhuang-tai-ji-hui-diao-han-shu&quot; aria-label=&quot;Anchor link for: zhuang-tai-ji-hui-diao-han-shu&quot;&gt;状态机回调函数&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 丰富了 glib 的事件源，状态机回调函数的实现逻辑变得更加复杂，但基本框架仍然遵循 glib 规范，&lt;code&gt;aio_context_new&lt;/code&gt; 函数中的 &lt;code&gt;aio_source_funcs&lt;/code&gt; 是状态机回调函数的声明：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 389 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; GSourceFuncs aio_source_funcs &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    aio_ctx_prepare&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    aio_ctx_check&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    aio_ctx_dispatch&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    aio_ctx_finalize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;aio_ctx_prepare&lt;/code&gt; 是状态机 prepare 阶段的回调函数，目的是准备 &lt;code&gt;AioContext&lt;/code&gt; 进行轮询，计算超时，并检查是否有即时事件需要处理。如果有即时事件，它会返回 &lt;code&gt;true&lt;/code&gt;，这意味着主事件循环应该立即处理这些事件而非等待。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 267 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_ctx_prepare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; gint    &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qatomic_set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notify_me&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qatomic_read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notify_me&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * Write ctx-&amp;gt;notify_me before computing the timeout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * (reading bottom half flags, etc.).  Pairs with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * smp_mb in aio_notify().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    smp_mb&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; We assume there is no timeout already supplied &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_timeout_ns_to_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_compute_timeout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_prepare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        *&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_ctx_check&lt;/code&gt; 是状态机 check 阶段的回调函数，主要负责检查 &lt;code&gt;AioContext&lt;/code&gt; 是否有待处理的事件。如果有则返回 &lt;code&gt;true&lt;/code&gt;。该函数首先使用原子操作清除 &lt;code&gt;ctx-&amp;gt;notify_me&lt;/code&gt; 的最低位，这是用于跟踪是否需要通知 &lt;code&gt;AioContext&lt;/code&gt; 的标志。接着调用 &lt;code&gt;aio_notify_accept&lt;/code&gt; 来处理任何挂起的通知，并通过 &lt;code&gt;QSLIST_FOREACH_RCU&lt;/code&gt; 宏遍历 &lt;code&gt;ctx-&amp;gt;bh_list&lt;/code&gt; 中的所有下半部，如果找到一个已调度但未删除的下半部，函数返回 &lt;code&gt;true&lt;/code&gt;。然后，使用 &lt;code&gt;QSIMPLEQ_FOREACH&lt;/code&gt; 和 &lt;code&gt;QSLIST_FOREACH_RCU&lt;/code&gt; 宏遍历 &lt;code&gt;ctx-&amp;gt;bh_slice_list&lt;/code&gt; 中的所有下半部，如果在任何切片中找到一个已调度但未删除的下半部，函数返回 &lt;code&gt;true&lt;/code&gt;。最后，使用 &lt;code&gt;aio_pending&lt;/code&gt; 函数检查是否有其他挂起的事件。此外，函数还会检查 &lt;code&gt;timerlistgroup_deadline_ns&lt;/code&gt; 的返回值是否为 0，这意味着有一个立即的定时器事件需要处理。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 291 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_ctx_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMUBH &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BHListSlice &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Finish computing the timeout before clearing the flag. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qatomic_store_release&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notify_me&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qatomic_read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notify_me&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ~&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_notify_accept&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSLIST_FOREACH_RCU&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;BH_SCHEDULED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; BH_DELETED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; BH_SCHEDULED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QSIMPLEQ_FOREACH&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_slice_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        QSLIST_FOREACH_RCU&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;bh_list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bh&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;BH_SCHEDULED &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;|&lt;/span&gt;&lt;span&gt; BH_DELETED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; BH_SCHEDULED&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_pending&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ||&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;timerlistgroup_deadline_ns&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;tlg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_ctx_dispatch&lt;/code&gt; 是状态机 dispatch 阶段的回调函数，整体逻辑较为简单，在确保参数 &lt;code&gt;callback&lt;/code&gt; 不为空的情况下直接调用 &lt;code&gt;aio_dispatch&lt;/code&gt; 函数进行处理。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/async.c: 318 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;aio_ctx_dispatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource     &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 GSourceFunc &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; callback&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 gpointer &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;    user_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ctx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;callback &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_dispatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_dispatch&lt;/code&gt; 函数是所有事件处理函数中最为重要的一个，主要负责事件的分派处理，具体负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下半部处理&lt;/li&gt;
&lt;li&gt;处理文件 fd 列表中有事件的 fd&lt;/li&gt;
&lt;li&gt;调用定时器到期的函数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;aio_dispatch&lt;/code&gt; 函数代码对上述三个行为进行了封装：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/aio-posix.c: 418 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_dispatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_lockcnt_inc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_bh_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    aio_dispatch_handlers&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; INVALID_HANDLE_VALUE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_lockcnt_dec&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    timerlistgroup_run_timers&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;tlg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们重点关注 &lt;code&gt;aio_dispatch_handlers&lt;/code&gt; 函数的执行逻辑：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/aio-posix.c: 406 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_dispatch_handlers&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AioContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; HANDLE &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;event&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; progress &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    AioHandler &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;tmp&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * We have to walk very carefully in case aio_set_fd_handler is&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     * called while we&amp;#39;re walking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QLIST_FOREACH_SAFE_RCU&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;aio_handlers&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int&lt;/span&gt;&lt;span&gt; revents &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revents&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;deleted&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (&lt;/span&gt;&lt;span&gt;revents &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; event_notifier_get_handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_notify&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revents&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;io_notify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; aio_notify() does not count as progress &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                progress &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;deleted&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_read&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ||&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_write&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revents&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;revents &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; G_IO_IN&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_read&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;io_read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                progress &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;revents &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; G_IO_OUT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;io_write&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;io_write&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opaque&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                progress &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; if the next select() will return an event, we have progressed &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;event &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; event_notifier_get_handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;notifier&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                WSANETWORKEVENTS ev&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                WSAEnumNetworkEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pfd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lNetworkEvents&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    progress &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;deleted&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu_lockcnt_dec_if_lock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                QLIST_REMOVE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                qemu_lockcnt_inc_and_unlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;list_lock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;aio_dispatch_handlers&lt;/code&gt; 函数的行为主要分为 4 个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;QLIST_FOREACH_SAFE_RCU&lt;/code&gt; 宏安全地遍历 &lt;code&gt;ctx-&amp;gt;aio_handlers&lt;/code&gt; 列表，检查监听 fd 上的事件是否发生。fd 发生的事件存在 &lt;code&gt;node-&amp;gt;pfd.revents&lt;/code&gt; 中，注册时指定需要接受的事件存放在 &lt;code&gt;node-&amp;gt;pfd.events&lt;/code&gt; 中，&lt;code&gt;revents&lt;/code&gt; 变量保存了 fd 接收到的事件。&lt;/li&gt;
&lt;li&gt;处理通知，如果事件没有被删除，其事件标志被设置，且有一个通知回调函数，那么该回调函数将被调用。&lt;/li&gt;
&lt;li&gt;处理读写事件，对应 &lt;code&gt;G_IO_IN&lt;/code&gt; 可读事件来说，会调用注册的 fd 的 &lt;code&gt;io_read&lt;/code&gt; 回调，对 &lt;code&gt;G_IN_OUT&lt;/code&gt; 可写事件来说，会调用注册的 fd 的 &lt;code&gt;io_write&lt;/code&gt; 函数。&lt;/li&gt;
&lt;li&gt;如果当前的 fd 已经被标记删除了，则会删除这个节点并释放锁。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;aio_ctx_finalize&lt;/code&gt; 函数是事件源不再被引用时的回调函数，其主要目的是确保与 &lt;code&gt;AioContext&lt;/code&gt; 关联的所有资源都被正确地清理和释放，以防止发生内存泄漏等问题。&lt;code&gt;aio_ctx_finalize&lt;/code&gt; 函数的整体逻辑相对而言比较简单，这里不再赘述。&lt;/p&gt;
&lt;h2 id=&quot;poll-ji-zhi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#poll-ji-zhi&quot; aria-label=&quot;Anchor link for: poll-ji-zhi&quot;&gt;poll 机制&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;应用程序对文件描述符的读写，一般有两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;阻塞式 IO：&lt;/strong&gt; 如果 fd 的某个状态（比如可读，可写）没有准备就绪，进程将永远阻塞在这个 IO 上&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;非阻塞式 IO：&lt;/strong&gt; 进程 IO 立即执行，如果 fd 没有准备就绪，直接返回错误，表示如果继续执行 IO 将阻塞。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通常来说，上述两种方式能够满足大多数应用程序对文件描述符的读写需求，但是在更复杂的场景下，比如一个不允许阻塞的进程需要读写一个可能永远阻塞进程的 fd，这时就需要使用内核提供的 poll 机制。poll 机制不直接读写 IO，而是先探测 fd 的 IO 状态是否就绪。这个探测行为可以设置超时时间：如果在超时时间到达前 IO 状态准备就绪，poll 接口立即返回，指示应用程序可以进行读写操作；如果 poll 超过了设置的超时时间，但应用需要的 IO 状态仍未完全就绪，poll 接口也会返回，同时把已经就绪的部分 IO 状态返回。这种机制使得应用程序能够根据内核返回的 poll 信息确定下一步的操作，避免应用程序被永远阻塞在某一 IO 上。&lt;/p&gt;
&lt;p&gt;QEMU 基于 glib 事件循环的框架，定制了 glib 事件循环机制中几乎所有的接口。需要注意的是，QEMU 并没有调用 glib 的接口 &lt;code&gt;g_main_loop_run&lt;/code&gt; 执行事件循环，而是直接调用了 glib 提供的 &lt;code&gt;g_poll&lt;/code&gt; 函数实现 poll 的功能。&lt;code&gt;g_poll&lt;/code&gt; 函数具有可移植性，在有 poll 接口的平台上由 poll 模拟，在没有 poll 接口的平台上由 select 模拟。当用户不想执行整个 glib 事件循环，又想实现阻塞一段时间的高级 IO，就可以通过直接调用 &lt;code&gt;g_poll&lt;/code&gt; 实现。&lt;/p&gt;
&lt;p&gt;QEMU 主事件循环的具体逻辑由函数 &lt;code&gt;qemu_main_loop&lt;/code&gt; 体现：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; softmmu/runstate.c: 720 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_main_loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; status &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; EXIT_SUCCESS&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_PROFILER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;main_loop_should_exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_PROFILER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ti &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; profile_getclock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        main_loop_wait&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_PROFILER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        dev_time &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; profile_getclock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span&gt; ti&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; status&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;观察上述代码我们可以发现，QEMU 使用了一条 &lt;code&gt;while&lt;/code&gt; 语句循环调用 &lt;code&gt;main_loop_wait&lt;/code&gt; 函数，再通过一串函数调用链最终调用 &lt;code&gt;g_poll&lt;/code&gt; 接口。&lt;code&gt;g_poll&lt;/code&gt; 接口接受的参数是一个文件描述符的数组，因此它能够同时 poll 多个 fd，poll 的时候是休眠的，一旦其中一个 fd 准备好，poll 就会被唤醒，同时 &lt;code&gt;GPollFD.revent&lt;/code&gt; 会被内核设置，以表明 fd 的状态。QEMU 对 &lt;code&gt;g_poll&lt;/code&gt; 接口的封装实现除了以纳秒为单位计算超时之外，其他方面均与 glib 的 &lt;code&gt;g_poll&lt;/code&gt; 接口保持一致：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/qemu-timer.c: 335 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_poll_ns&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GPollFD &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;fds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; guint &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;nfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; int64_t&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;ifdef&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; CONFIG_PPOLL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ppoll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; pollfd &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;fds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; nfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        struct&lt;/span&gt;&lt;span&gt; timespec ts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        int64_t&lt;/span&gt;&lt;span&gt; tvsec &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1000000000&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;LL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Avoid possibly overflowing and specifying a negative number of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         * seconds, which would turn a very long timeout into a busy-wait.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;         */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;tvsec &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int64_t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;INT32_MAX&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tvsec &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; INT32_MAX&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tv_sec&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; tvsec&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tv_nsec&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1000000000&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;LL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ppoll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; pollfd &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;fds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; nfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;ts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; nfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_timeout_ns_to_ms&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 QEMU 配置了 PPOLL，&lt;code&gt;qemu_poll_ns&lt;/code&gt; 函数会使用 PPOLL 实现 poll 探测，否则直接调用 &lt;code&gt;g_poll&lt;/code&gt; 函数实现 poll 探测。&lt;/p&gt;
&lt;h2 id=&quot;zhu-shi-jian-xun-huan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-shi-jian-xun-huan&quot; aria-label=&quot;Anchor link for: zhu-shi-jian-xun-huan&quot;&gt;主事件循环&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;yi-ban-liu-cheng&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-ban-liu-cheng&quot; aria-label=&quot;Anchor link for: yi-ban-liu-cheng&quot;&gt;一般流程&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 事件循环执行流程遵循 glib 标准，与普通应用的执行流程类似，相关函数的调用关系如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part2/./main-loop.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;QEMU 的 &lt;code&gt;main&lt;/code&gt; 函数定义在 &lt;code&gt;softmmu/ vl.c&lt;/code&gt; 文件中，主函数在调用 &lt;code&gt;qemu_init()&lt;/code&gt; 完成所有初始化工作之后会直接跳转函数 &lt;code&gt;qemu_main&lt;/code&gt; 开始执行主事件循环。&lt;/p&gt;
&lt;h3 id=&quot;chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#chu-shi-hua&quot; aria-label=&quot;Anchor link for: chu-shi-hua&quot;&gt;初始化&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 主事件循环初始化由 &lt;code&gt;qemu_init_main_loop&lt;/code&gt; 函数负责：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/main-loop.c: 156 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_init_main_loop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    init_clocks&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qemu_timer_notify_cb&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_signal_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qemu_aio_context &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_context_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;qemu_aio_context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span&gt;EMFILE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_set_current_aio_context&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qemu_aio_context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qemu_notify_bh &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_bh_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;notify_event_cb&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gpollfds &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_array_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;FALSE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; FALSE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GPollFD&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; aio_get_g_source&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;qemu_aio_context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_set_name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;aio-context&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_attach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; iohandler_get_g_source&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_set_name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;io-handler&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_attach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;观察上述代码可以发现，QEMU 事件初始化通过 glib 接口封装出本文开头所介绍的两种自定义事件源 &lt;code&gt;qemu_aio_context&lt;/code&gt; 和 &lt;code&gt;iohandler_ctx&lt;/code&gt;，然后将它们加入到 glib 默认的事件循环 &lt;code&gt;default GMainContext&lt;/code&gt; 中。此外，一个上下文只在一个线程中运行，而 &lt;code&gt;qemu_aio_context&lt;/code&gt; 和 &lt;code&gt;iohandler_ctx&lt;/code&gt; 属于同一个上下文，因此可以运行在同一线程中。&lt;/p&gt;
&lt;h3 id=&quot;guan-jian-han-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-jian-han-shu&quot; aria-label=&quot;Anchor link for: guan-jian-han-shu&quot;&gt;关键函数&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在上述函数调用关系图中，较为关键的是 &lt;code&gt;os_host_main_loop_wait&lt;/code&gt; 函数，具体执行对 fd 的监听行为。需要注意的是，&lt;code&gt;main_loop_wait&lt;/code&gt; 在调用 &lt;code&gt;os_host_main_loop_wait&lt;/code&gt; 函数前，会调用 &lt;code&gt;qemu_soonest_timeout&lt;/code&gt; 函数先计算一个最小的 &lt;code&gt;timeout&lt;/code&gt; 值，该值是从定时器列表中获取的，表示监听事件的时候最多让主事件循环阻塞的时间，&lt;code&gt;timeout&lt;/code&gt; 的存在使得 QEMU 能够及时处理系统中的定时器到期事件。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;os_host_main_loop_wait&lt;/code&gt; 函数定义位于 &lt;code&gt;util/main-loop.c&lt;/code&gt; 文件中，下面针对代码进行具体分析：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/main-loop.c: 296 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; os_host_main_loop_wait&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int64_t&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GMainContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;context &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_context_default&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_context_acquire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    glib_pollfds_fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_mutex_unlock_iothread&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    replay_mutex_unlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_poll_ns&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GPollFD &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;gpollfds&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; gpollfds&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;len&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    replay_mutex_lock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_mutex_lock_iothread&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    glib_pollfds_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_context_release&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在上述代码中，我们需要重点关注以下三个函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;glib_pollfds_fill：&lt;/strong&gt; 检索事件源中待监控的 fd 集合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;qemu_poll_ns：&lt;/strong&gt; QEMU 对 &lt;code&gt;g_poll&lt;/code&gt; 接口的封装实现，以纳秒为单位计算超时时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;glib_pollfds_poll：&lt;/strong&gt; 有事件发生，准备开始执行回调&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中 &lt;code&gt;qemu_poll_ns&lt;/code&gt; 函数上文已经分析过，这里重点关注另外两个函数。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/main-loop.c: 255 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; glib_pollfds_fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int64_t&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;cur_timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GMainContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;context &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_context_default&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int64_t&lt;/span&gt;&lt;span&gt; timeout_ns&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_context_prepare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;max_priority&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    glib_pollfds_idx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; gpollfds&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;len&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    n &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; glib_n_poll_fds&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    do&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        GPollFD &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;pfds&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        glib_n_poll_fds &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_array_set_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gpollfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; glib_pollfds_idx &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;+&lt;/span&gt;&lt;span&gt; glib_n_poll_fds&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pfds &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_array_index&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gpollfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; GPollFD&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; glib_pollfds_idx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        n &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_context_query&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; max_priority&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; pfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 glib_n_poll_fds&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!=&lt;/span&gt;&lt;span&gt; glib_n_poll_fds&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        timeout_ns &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        timeout_ns &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int64_t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int64_t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;SCALE_MS&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;cur_timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_soonest_timeout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;timeout_ns&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;cur_timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;glib_pollfds_fill&lt;/code&gt; 函数的主要工作是获取所有需要进行监听的 fd，并且计算一个最小的超时时间。该函数首先调用 &lt;code&gt;g_main_context_prepare&lt;/code&gt; 开始为主循环的监听做准备。接着在一个循环中调用 &lt;code&gt;g_main_context_query&lt;/code&gt; 获取需要监听的 fd，所有 fd 保存在全局变量 &lt;code&gt;gpollfds&lt;/code&gt; 数组中，需要监听的 fd 的数量保存在 &lt;code&gt;glib_n_poll_fds&lt;/code&gt; 中，&lt;code&gt;g_main_context_query&lt;/code&gt; 还会返回 fd 时间最小的 &lt;code&gt;timeout&lt;/code&gt;，该值用来与传入的参数 &lt;code&gt;cur_timeout&lt;/code&gt; 进行比较，选取较小值表示主循环的最大阻塞时间。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; util/main-loop.c: 284 &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; glib_pollfds_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GMainContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;context &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_context_default&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GPollFD &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;pfds &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_array_index&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gpollfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; GPollFD&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; glib_pollfds_idx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_main_context_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; max_priority&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; pfds&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; glib_n_poll_fds&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_main_context_dispatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;glib_pollfds_poll&lt;/code&gt; 函数负责对事件进行分发处理，它的代码结构比较简单，首先调用 glib 框架的 &lt;code&gt;g_main_context_check&lt;/code&gt; 检测事件，然后再调用 &lt;code&gt;g_main_context_dispatch&lt;/code&gt; 对事件进行分发处理。&lt;/p&gt;
&lt;h3 id=&quot;shi-jian-chu-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-jian-chu-li&quot; aria-label=&quot;Anchor link for: shi-jian-chu-li&quot;&gt;事件处理&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;signalfd 是 Linux 的一个系统调用，可以将特定的信号与一个 fd 绑定，当有信号到达的时 fd 就会产生对应的可读事件。下面以 signalfd 为例梳理总结 QEMU 事件处理的过程。&lt;/p&gt;
&lt;p&gt;初始化阶段主要逻辑如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;调用 &lt;code&gt;qemu_signal_init&lt;/code&gt; 将一个 fd 与一组信号关联起来，&lt;code&gt;qemu_signal_init&lt;/code&gt; 调用 &lt;code&gt;qemu_set_fd_handler&lt;/code&gt; 函数将该 signalfd 对应的可读回调函数设置为 &lt;code&gt;sigfd_handler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;qemu_set_fd_handler&lt;/code&gt; 在首次调用时会调用 &lt;code&gt;iohandler_init&lt;/code&gt; 创建一个全局的 &lt;code&gt;iohandler_ctx&lt;/code&gt; 事件源，这个事件源的作用是监听 QEMU 中的各类事件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;qemu_signal_init&lt;/code&gt; 在 &lt;code&gt;iohandlers_ctx&lt;/code&gt; 的 &lt;code&gt;aio_handlers&lt;/code&gt; 上挂载一个 &lt;code&gt;AioHandler&lt;/code&gt; 节点，其 fd 为 signalfd，其 &lt;code&gt;io_read&lt;/code&gt; 函数为 &lt;code&gt;sigfd_handler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;aio_context_new&lt;/code&gt; 创建一个全局的 &lt;code&gt;qemu_aio_context&lt;/code&gt; 事件源，这个事件源主要用于处理 BH 和块设备层的同步使用&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;aio_get_g_source&lt;/code&gt; 和 &lt;code&gt;iohandler_get_g_source&lt;/code&gt; 分别获取 &lt;code&gt;qemu_aio_context&lt;/code&gt; 和 &lt;code&gt;iohandler_ctx&lt;/code&gt; 的 &lt;code&gt;GSource&lt;/code&gt; 成员变量，以该变量为参数调用 &lt;code&gt;g_source_attach&lt;/code&gt; 两个 &lt;code&gt;AioContext&lt;/code&gt; 加入主循环&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;将信号对应的 fd 加入事件源并将事件源加入主循环之后，QEMU 就会进入上文所述的 &lt;code&gt;qemu_main_loop&lt;/code&gt; 函数循环进行事件监听。当使用 &lt;code&gt;kill&lt;/code&gt; 命令向 QEMU 进程发送 &lt;code&gt;SIGALARM&lt;/code&gt; 信号时，signalfd 就会有可读信号，从而导致主循环返回调用 &lt;code&gt;g_main_context_dispatch&lt;/code&gt; 进行事件分发，这会调用 &lt;code&gt;aio_ctx_dispatch&lt;/code&gt;，最终会调用 &lt;code&gt;qemu_signal_init&lt;/code&gt; 注册的可读处理函数 &lt;code&gt;sigfd_handler&lt;/code&gt; 进行事件处理。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文在 glib 事件循环机制的基础上，介绍了 QEMU 事件循环机制的基本组成，包括事件源、状态机回调函数以及 poll 机制，详细分析了 QEMU 主事件循环的运行原理，并以 signalfd 为例梳理了 QEMU 事件处理流程。在下一篇文章中，我们将继续深入分析 QEMU 下半部（Bottom Halvs，BH）机制。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://blog.csdn.net/huang987246510/article/details/90738137&quot;&gt;深入理解 QEMU 事件循环&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://mp.weixin.qq.com/s/-fNJNfynm7fxrrXYWI3npA&quot;&gt;QEMU 事件循环机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http://blog.vmsplice.net/2020/08/qemu-internals-event-loops.html&quot;&gt;QEMU Internals: Event loops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 事件循环机制简析（一）：glib 事件循环</title>
        <published>2023-07-25T00:00:00+00:00</published>
        <updated>2023-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-event-loop-part1/"/>
        <id>https://jjl9807.com/posts/qemu-system-event-loop-part1/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-event-loop-part1/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part1/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 采用了基于事件驱动的架构，其事件循环机制基于 glib 实现，因此 QEMU 中有大量的概念来源于 glib，在深入分析 QEMU 事件循环机制之前先了解 glib 事件循环的基本原理有助于增进我们对 QEMU 事件循环机制的理解，本文将基于 glib v2.25.7 源码介绍 glib 事件循环机制。&lt;/p&gt;
&lt;h2 id=&quot;gai-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gai-shu&quot; aria-label=&quot;Anchor link for: gai-shu&quot;&gt;概述&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;glib 是一个跨平台的、使用 C 语言编写的若干底层库的集合，它实现了完整的事件循环分发机制，在这个机制中有一个主事件循环负责管理所有可用事件源。这些事件可以来自多种不同类型的源，如文件描述符（文件、管道或套接字）和超时，我们还可以通过调用 &lt;code&gt;g_source_attach()&lt;/code&gt; 函数添加新类型的事件源。&lt;/p&gt;
&lt;p&gt;glib 使用 &lt;code&gt;GMainLoop&lt;/code&gt; 结构体来表示一个主事件循环，一个 &lt;code&gt;GMainLoop&lt;/code&gt; 由 &lt;code&gt;g_main_loop_new()&lt;/code&gt; 函数创建，添加初始事件源后，调用 &lt;code&gt;g_main_loop_run()&lt;/code&gt; 函数运行，该函数将持续检查每个事件源的新事件，并将其派发出去，直到处理完其中一个事件源的事件后，调用 &lt;code&gt;g_main_loop_quit()&lt;/code&gt; 函数退出主循环，&lt;code&gt;g_main_loop_run()&lt;/code&gt; 函数才会返回。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GMainContext&lt;/code&gt; 用于表示主事件循环的上下文，每一个 &lt;code&gt;GMainLoop&lt;/code&gt; 都有一个对应的上下文 &lt;code&gt;GMainContext&lt;/code&gt;，它封装了事件循环的状态和行为。事件源使用 &lt;code&gt;GSource&lt;/code&gt; 表示，每个 &lt;code&gt;GSource&lt;/code&gt; 可以关联多个文件描述符，为了能够在不同线程中处理多组独立的事件源，每个 &lt;code&gt;GSource&lt;/code&gt; 会关联到一个 &lt;code&gt;GMainContext&lt;/code&gt;，而一个 &lt;code&gt;GMainContext&lt;/code&gt; 可以关联多个 &lt;code&gt;GSource&lt;/code&gt;，具体关系如下图所示。需要注意的是，&lt;code&gt;GMainContext&lt;/code&gt; 只能在单线程中运行，但是事件源可以由其他线程添加或删除。因此，所有对 &lt;code&gt;GMainContext&lt;/code&gt; 以及内置的 &lt;code&gt;GSource&lt;/code&gt; 进行操作的函数都是线程安全的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part1/./gmain-context.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;glib 中每个事件源都有一个优先级，默认优先级 &lt;code&gt;G_PRIORITY_DEFAULT&lt;/code&gt; 为 0，大于 0 表示优先级较低。来自高优先级事件源的事件总是先于来自低优先级事件源的事件得到处理。此外，还可以添加空闲函数（idle functions），并为其分配优先级，当没有来自更高优先级事件源的事件需要处理时，空闲函数就会运行。&lt;/p&gt;
&lt;h2 id=&quot;zhuang-tai-ji&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhuang-tai-ji&quot; aria-label=&quot;Anchor link for: zhuang-tai-ji&quot;&gt;状态机&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;glib 的核心是 poll 机制，通过 poll 检查用户注册的事件源，并执行对应的回调，用户不需要关注其具体实现，只需要按照要求注册对应的事件源和回调。&lt;/p&gt;
&lt;p&gt;glib 事件循环机制管理所有注册的事件源，不同事件源可以在一个线程中处理，也可以在不同线程中处理，这取决于事件源所在的上下文，一个上下文只能运行在一个线程中，如果想要事件源在不同线程中并发被处理，可以将其放在不同的上下文中。&lt;/p&gt;
&lt;p&gt;glib 中一次主循环分为 4 个阶段：prepare、query、check 和 dispatch，其状态转移如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-event-loop-part1/./state-transition.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;上述状态机中的四个阶段分别对应以下四个函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;prepare：&lt;/strong&gt;&lt;code&gt;gboolean g_main_context_prepare(GMainContext *context, gint *priority)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;该函数接受两个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;context：&lt;/strong&gt; 主循环的上下文，若为 &lt;code&gt;NULL&lt;/code&gt;，则使用默认上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;priority：&lt;/strong&gt; 用于返回准备好的事件源的最高优先级&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;函数执行过程中会循环遍历所有事件源，调用相应事件源的 &lt;code&gt;prepare&lt;/code&gt; 函数检查事件源是否准备好被分派。如果准备好了，设置相应事件源的 &lt;code&gt;G_SOURCE_READY&lt;/code&gt; 标志。此外，该函数还会计算下一个超时事件的时间。如果存在准备好的事件源，超时将被设置为 0，函数返回 &lt;code&gt;TRUE&lt;/code&gt;，否则待超时后直接返回 &lt;code&gt;FALSE&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;query：&lt;/strong&gt;&lt;code&gt;gint g_main_context_query(GMainContext *context, gint max_priority, gint *timeout_, GPollFD *fds, gint n_fds)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;该函数接受五个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;context：&lt;/strong&gt; 主循环的上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;max_priority：&lt;/strong&gt; 要查询的最大优先级&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;timeout：&lt;/strong&gt; 返回下一个超时的时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fds：&lt;/strong&gt; 用于存储查询结果的文件描述符数组&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;n_fds：&lt;/strong&gt; 文件描述符数组的大小&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;函数执行过程中会遍历上下文中的轮询记录，将每个记录转换为 &lt;code&gt;GPollFD&lt;/code&gt; 结构，并存储在 &lt;code&gt;fds&lt;/code&gt; 数组中，其中数组的大小由 &lt;code&gt;n_fds&lt;/code&gt; 指定，如果轮询记录的数量超过 &lt;code&gt;n_fds&lt;/code&gt;，则多余的记录将被忽略。如果 &lt;code&gt;timeout&lt;/code&gt; 参数不为 &lt;code&gt;NULL&lt;/code&gt;，则函数会将上下文的超时值复制到 &lt;code&gt;timeout&lt;/code&gt; 指向的位置。如果超时不为 0，则设置 &lt;code&gt;context-&amp;gt;time_is_current&lt;/code&gt; 为 &lt;code&gt;FALSE&lt;/code&gt;。最后，函数将返回填充到 &lt;code&gt;fds&lt;/code&gt; 数组中的轮询记录数量。该函数将主循环上下文中的轮询记录转换为可以传递给底层轮询系统调用的格式，使得主循环可以等待多个事件源上的事件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;check：&lt;/strong&gt;&lt;code&gt;gint g_main_context_check(GMainContext *context, gint max_priority, GPollFD *fds, gint n_fds)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;该函数接受四个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;context：&lt;/strong&gt; 主循环的上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;max_priority：&lt;/strong&gt; 要检查的最大优先级&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fds：&lt;/strong&gt; 包含轮询结果的文件描述符数组&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;n_fds：&lt;/strong&gt; 文件描述符数组的大小&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;函数执行过程中会遍历上下文中的轮询记录，并使用 &lt;code&gt;fds&lt;/code&gt; 数组中的结果更新每个记录的 &lt;code&gt;revents&lt;/code&gt; 字段。然后遍历上下文中的事件源，调用每个事件源的 &lt;code&gt;check&lt;/code&gt; 函数来确定是否准备好。如果事件源准备好，则将其添加到待调度列表中，并更新准备好的事件源源的数量和最大优先级。最后，如果有一个或多个事件源准备好，则函数返回 &lt;code&gt;TRUE&lt;/code&gt;，否则返回 &lt;code&gt;FALSE&lt;/code&gt;。该函数保证了主循环能够根据事件源的优先级和准备状态来进行调度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;dispatch：&lt;/strong&gt;&lt;code&gt;void g_main_context_dispatch (GMainContext *context)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;该函数的主要负责调度主循环上下文中准备好的事件源，一般在调用 &lt;code&gt;g_main_context_check&lt;/code&gt; 之后调用，确保事件源在准备好时得到适当的处理。在调度过程中，每个事件源的 &lt;code&gt;dispatch&lt;/code&gt; 函数将被调用，以执行与事件源关联的特定操作。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;zi-ding-yi-shi-jian-yuan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zi-ding-yi-shi-jian-yuan&quot; aria-label=&quot;Anchor link for: zi-ding-yi-shi-jian-yuan&quot;&gt;自定义事件源&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GMainLoop&lt;/code&gt; 除了内置的事件源类型外，还允许创建和使用自定义的事件源类型。自定义事件源必须将 glib 事件源作为&quot;基类&quot;，具体到实现上就是把 &lt;code&gt;GSource&lt;/code&gt; 作为自定义事件源结构体的第一个成员，在创建事件源时调用 &lt;code&gt;g_source_new()&lt;/code&gt; 函数并以参数的形式传入自定义事件源结构体的大小和函数表 &lt;code&gt;GSourceFuncs&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;自定义事件源一般通过两种方式与 &lt;code&gt;GMainContext&lt;/code&gt; 进行交互。&lt;code&gt;GSourceFuncs&lt;/code&gt; 函数表中的准备函数可以设置超时，以确定主循环在再次检查事件源之前的最长休眠时间。此外，自定义事件源还可以调用 &lt;code&gt;g_source_add_poll()&lt;/code&gt; 函数将文件描述符添加到 &lt;code&gt;GMainContext&lt;/code&gt; 的检查集合中。&lt;/p&gt;
&lt;h2 id=&quot;dai-ma-shi-li&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dai-ma-shi-li&quot; aria-label=&quot;Anchor link for: dai-ma-shi-li&quot;&gt;代码示例&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以上介绍了 glib 事件循环的一般流程以及自定义事件源的方法，我们需要做的就是将新的 &lt;code&gt;GSource&lt;/code&gt; 加入其中，glib 会负责处理 &lt;code&gt;GSource&lt;/code&gt; 上注册的各种事件源。glib 中有两个函数，分别实现将 &lt;code&gt;GSource&lt;/code&gt; 加入到 &lt;code&gt;GMainContext&lt;/code&gt; 和将 &lt;code&gt;fd&lt;/code&gt; 加入到 &lt;code&gt;GSource&lt;/code&gt; 的功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;g_source_attach()：&lt;/strong&gt; 将 &lt;code&gt;source-&amp;gt;poll_fds&lt;/code&gt; 中的文件描述符加入到 &lt;code&gt;context-&amp;gt;poll_records&lt;/code&gt; 中；&lt;code&gt;source&lt;/code&gt; 添加到 &lt;code&gt;context&lt;/code&gt; 的 &lt;code&gt;source&lt;/code&gt; 链表中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;g_source_add_poll()：&lt;/strong&gt; 将 &lt;code&gt;fd&lt;/code&gt; 加入到 &lt;code&gt;source-&amp;gt;poll_fds&lt;/code&gt; 中，然后再加入到 &lt;code&gt;context-&amp;gt;poll_records&lt;/code&gt; 中，设置 &lt;code&gt;context-&amp;gt;poll_changed&lt;/code&gt; 为 &lt;code&gt;TRUE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面将通过两个代码示例来具体说明，在使用 glib 库之前，首先使用以下命令安装开发包：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; apt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; libglib2.0-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后通过 pkg-config 工具查看 gcc 编译需要链接的动态库以及头文件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-libs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;-lglib-2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-cflags&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;-I/usr/include/glib-2.0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;I/usr/lib/x86_64-linux-gnu/glib-2.0/include&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;da-yin-biao-zhun-shu-ru-zhong-de-nei-rong-chang-du&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#da-yin-biao-zhun-shu-ru-zhong-de-nei-rong-chang-du&quot; aria-label=&quot;Anchor link for: da-yin-biao-zhun-shu-ru-zhong-de-nei-rong-chang-du&quot;&gt;打印标准输入中的内容长度&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本例通过注册自定义事件源回调函数实现了打印标准输入中读到的内容长度，具体代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;glib.h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gboolean &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;io_watch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GIOChannel &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;channel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; GIOCondition &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;condition&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; gpointer &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gsize len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gchar &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;buffer &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_io_channel_read_line&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;buffer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;len&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; len&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;buffer&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; TRUE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;[]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GMainLoop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;loop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_loop_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; FALSE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GIOChannel &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;channel &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_io_channel_unix_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_io_add_watch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; G_IO_IN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; io_watch&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_io_channel_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_loop_run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_context_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_main_loop_get_context&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_loop_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述代码中首先定义了回调函数 &lt;code&gt;io_watch&lt;/code&gt; 用于实现“打印标准输入中读到内容的长度”的功能。在程序的主函数中，首先通过 &lt;code&gt;g_main_loop_new&lt;/code&gt; 函数获取一个上下文的事件循环实例，接着调用 &lt;code&gt;g_io_channel_unix_new&lt;/code&gt; 函数将标准输入描述符转化成 &lt;code&gt;GIOChannel&lt;/code&gt; 以便操作，然后将针对 &lt;code&gt;channel&lt;/code&gt; 事件源的回调函数 &lt;code&gt;io_watch&lt;/code&gt; 注册到默认上下文，告诉 glib 需要关注 &lt;code&gt;channel&lt;/code&gt; 的输入 &lt;code&gt;G_IO_IN&lt;/code&gt;，当输入准备好之后，调用自己注册的回调函数，并传入参数 &lt;code&gt;NULL&lt;/code&gt;。在 &lt;code&gt;main&lt;/code&gt; 函数的最后，执行执行默认上下文的事件循环。&lt;/p&gt;
&lt;p&gt;使用如下命令编译上述代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; `&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-cflags&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; demo1.c&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; demo1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; `&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-libs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在终端运行 &lt;code&gt;demo1&lt;/code&gt; 程序所得结果如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ./demo1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;12&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;glib&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; event&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; loop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;^C&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;da-yin-zhi-ding-shu-ru-yuan-zhong-de-nei-rong-chang-du&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#da-yin-zhi-ding-shu-ru-yuan-zhong-de-nei-rong-chang-du&quot; aria-label=&quot;Anchor link for: da-yin-zhi-ding-shu-ru-yuan-zhong-de-nei-rong-chang-du&quot;&gt;打印指定输入源中的内容长度&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本例在上一例的基础上更进一步，添加了自定义事件源和自定义状态机回调函数，实现了打印指定输入源中读取的内容长度，具体代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;glib.h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; _MySource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSource _source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GIOChannel &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GPollFD fd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; MySource&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;watch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GIOChannel &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gsize len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gchar &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;buffer &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_io_channel_read_line&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;buffer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;len&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;len &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; len&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;buffer&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; TRUE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;prepare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; gint &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;timeout&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;timeout &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; FALSE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mysource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revents&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span&gt; mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; FALSE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; TRUE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; gboolean &lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;dispatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; GSourceFunc &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;callback&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; gpointer &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;user_data&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mysource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;callback&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        callback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; TRUE&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; finalize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;source&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mysource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_io_channel_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;[]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GError &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GMainLoop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;loop &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_main_loop_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; FALSE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSourceFuncs funcs &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;prepare&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; check&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; dispatch&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; finalize&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    GSource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;source &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_source_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MySource&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;mysource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;MySource &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_io_channel_new_file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Unable to get test file channel: &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; error&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_io_channel_unix_get_fd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; G_IO_IN&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_add_poll&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;mysource&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;fd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_set_callback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;GSourceFunc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;watch&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_set_priority&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; G_PRIORITY_DEFAULT_IDLE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_attach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_source_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_loop_run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_context_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;g_main_loop_get_context&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_main_loop_unref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;loop&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述代码首先定义了自定义事件源 &lt;code&gt;MySource&lt;/code&gt; 以及事件源回调函数 &lt;code&gt;watch&lt;/code&gt;，实现了“读出 &lt;code&gt;iochannel&lt;/code&gt; 中内容并打印其长度”的功能。接着，代码定义了四个状态机回调函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;prepare：&lt;/strong&gt; 状态机 prepare 阶段的回调函数，&lt;code&gt;timeout&lt;/code&gt; 等于 -1 告诉 poll 如果 IO 没有准备好，一直等待，即阻塞 IO。函数返回 &lt;code&gt;FALSE&lt;/code&gt; 表示需要 poll 来检查事件源是否准备好，返回 &lt;code&gt;TRUE&lt;/code&gt; 则表示跳过 poll&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;check：&lt;/strong&gt; 状态机 check 阶段的回调函数，检查自己感兴趣的 &lt;code&gt;fd&lt;/code&gt; 状态是否准备好，用户通过设置 &lt;code&gt;events&lt;/code&gt; 标志设置感兴趣的 &lt;code&gt;fd&lt;/code&gt; 状态（包括文件可读、可写、异常等），&lt;code&gt;revents&lt;/code&gt; 是 poll 的返回值，由内核设置，表明 &lt;code&gt;fd&lt;/code&gt; 哪些状态是准备好的。当感兴趣的状态和 poll 返回的状态不相同，则表示 &lt;code&gt;fd&lt;/code&gt; 没有准备好，函数返回 &lt;code&gt;FALSE&lt;/code&gt;，glib 不发起调度，反之函数返回 &lt;code&gt;TRUE&lt;/code&gt;，glib 发起调度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;diapatch：&lt;/strong&gt; 状态机 dispatch 阶段的回调函数，只要函数 &lt;code&gt;prepare&lt;/code&gt; 和 &lt;code&gt;check&lt;/code&gt; 中有一个返回 &lt;code&gt;TRUE&lt;/code&gt;，glib 就会直接调用此接口，执行用户注册的回调函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;finalize：&lt;/strong&gt; 当事件源不再被引用时的回调函数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面分析本例代码中主函数的执行逻辑：首先进行有关变量的初始化，包括从默认上下文获取事件循环实例、声明自定义的状态机回调函数以及定义自定义事件源。接着，创建一个文件类型的 &lt;code&gt;GIOChannel&lt;/code&gt;，获取 &lt;code&gt;GIOChannel&lt;/code&gt; 的 &lt;code&gt;fd&lt;/code&gt;，放到 &lt;code&gt;GPollFD&lt;/code&gt; 的 &lt;code&gt;fd&lt;/code&gt; 域中，并设置感兴趣的文件状态，本例中为文件可读状态。这里 &lt;code&gt;GIOChannel&lt;/code&gt; 是 glib 对文件描述符的封装，以实现平台可移植性，其 &lt;code&gt;fd&lt;/code&gt; 类型可以是文件、管道或套接字。最终传给 poll 的文件描述符结构体如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; GPollFD &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  	gint		fd&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;			//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; 文件描述符&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  	gushort 	events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;		//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; 感兴趣的文件状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  	gushort 	revents&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;	//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; 返回值，由内核设置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，程序将文件描述符添加到事件源中，设置事件源的回调函数和优先级，当位于同一个上下文中的多个事件源同时处于准备好了的状态时，优先级高的事件源会被 glib 优先调度。最后，glib 开始执行默认上下文的事件循环。&lt;/p&gt;
&lt;p&gt;使用如下命令编译上述代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;cc&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; `&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-cflags&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; demo2.c&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; demo2&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; `&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;pkg-config&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;-libs&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; glib-2.0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在终端直接运行 &lt;code&gt;demo2&lt;/code&gt; 程序所得结果如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ./demo2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;Unable&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; get&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; file&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; channel:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; No&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; such&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; file&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; or&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开另一终端窗口，新建 &lt;code&gt;test&lt;/code&gt; 文件，在前一窗口中再次运行 &lt;code&gt;demo2&lt;/code&gt; 程序，然后在当前窗口向 &lt;code&gt;test&lt;/code&gt; 文件中写入内容：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; touch&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; echo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;hello world&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; echo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;RISC-V Linux&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可在前一窗口中看到如下运行结果：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; ./demo2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;12&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;13&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;^C&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文为分析 QEMU 事件循环机制补充了前置知识，基于 glib v2.25.7 源码介绍了 glib 事件循环机制的基本原理，梳理了主要数据结构之间的关系，详细描述了 glib 事件循环的状态转移图，并通过两个具体的代码示例进一步说明了 glib 事件循环机制的运行流程。在下一篇文章中，我们将详细分析 QEMU 事件循环机制。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.gtk.org/glib/main-loop.html&quot;&gt;GLib – 2.0: The Main Event Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.gtk.org/glib/compiling.html&quot;&gt;GLib – 2.0: Compiling GLib Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 参数解析机制简析</title>
        <published>2023-07-15T00:00:00+00:00</published>
        <updated>2023-07-15T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-parameters/"/>
        <id>https://jjl9807.com/posts/qemu-system-parameters/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-parameters/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-parameters/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 使用命令行来配置模拟器的启动参数，本文将以 8.0.0 版本的 QEMU RISC-V (qemu-system-riscv64) 为例，简要梳理 QEMU 常用参数的含义与用法，重点分析 QEMU 的参数解析机制。&lt;/p&gt;
&lt;h2 id=&quot;chang-yong-can-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-yong-can-shu&quot; aria-label=&quot;Anchor link for: chang-yong-can-shu&quot;&gt;常用参数&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 各选项的具体用法可以通过指令 &lt;code&gt;qemu-system-riscv64 [options] help&lt;/code&gt; 查看。下面以在 QEMU 中启动 RISC-V Linux 内核的命令为例，简要介绍 QEMU 常用参数的含义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu-system-riscv64&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virt&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; 256M&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;nographic&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; linux-kernel/arch/riscv/boot/Image&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;drive&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; file=rootfs.img,format=raw,id=hd0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;  \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; virtio-blk-device,drive=hd0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;root=/dev/vda rw console=ttyS0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-M：&lt;/strong&gt; 指定模拟器运行时的设备类型，在上面的例子中指定了 &lt;code&gt;qemu-system-riscv64&lt;/code&gt; 的模拟设备为 &lt;code&gt;virt&lt;/code&gt;，即 RISC-V 架构下的“通用虚拟平台”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-m：&lt;/strong&gt; 指定虚拟机内部的内存大小&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-kernel：&lt;/strong&gt; 指定内核镜像&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-append：&lt;/strong&gt; 指定内核命令行代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-drive：&lt;/strong&gt; 定义磁盘，&lt;code&gt;file&lt;/code&gt; 表示磁盘镜像的文件路径，&lt;code&gt;format&lt;/code&gt; 表示磁盘格式，&lt;code&gt;id&lt;/code&gt; 表示磁盘号&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-device：&lt;/strong&gt; 添加设备到虚拟机中&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-shu-jie-xi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-shu-jie-xi&quot; aria-label=&quot;Anchor link for: can-shu-jie-xi&quot;&gt;参数解析&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;liu-cheng-gai-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#liu-cheng-gai-shu&quot; aria-label=&quot;Anchor link for: liu-cheng-gai-shu&quot;&gt;流程概述&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 的全部可用参数定义于项目目录下的 &lt;code&gt;qemu-options.hx&lt;/code&gt; 文件中，而参数解析的主体逻辑位于 &lt;code&gt;softmmu/vl.c&lt;/code&gt; 文件的 &lt;code&gt;qemu_init&lt;/code&gt; 函数中，主要分为两个阶段，第一阶段负责检查传入参数的合法性，并不具体解析，第二阶段执行具体的解析操作，并通过 &lt;code&gt;switch&lt;/code&gt; 语句跳转不同为分支完成对应选项的设置。QEMU 在不同的抽象层次上定义了多种数据结构来对不同的参数进行描述，这些数据结构都在参数解析之前完成初始化。&lt;/p&gt;
&lt;h3 id=&quot;shu-ju-jie-gou-ji-chu-shi-hua&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#shu-ju-jie-gou-ji-chu-shi-hua&quot; aria-label=&quot;Anchor link for: shu-ju-jie-gou-ji-chu-shi-hua&quot;&gt;数据结构及初始化&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 在 &lt;code&gt;softmmu/vl.c&lt;/code&gt; 文件中定义了 &lt;code&gt;QEMUOption&lt;/code&gt; 结构体来描述不同的命令行参数，其代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; QEMUOption &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; flags&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    uint32_t&lt;/span&gt;&lt;span&gt; arch_mask&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; QEMUOption&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;name&lt;/code&gt; 表示参数名称，&lt;code&gt;flags&lt;/code&gt; 表示参数属性，为 1 表示拥有子参数，为 0 则表示无子参数，&lt;code&gt;index&lt;/code&gt; 表示命令索引 (QEMU_OPTION_cmd)，&lt;code&gt;arch_mask&lt;/code&gt; 表示参数支持的架构。在 &lt;code&gt;softmmu/vl.c&lt;/code&gt; 文件中还定义了一个全局 &lt;code&gt;QEMUOption&lt;/code&gt; 数组 &lt;code&gt;qemu_options&lt;/code&gt; 来描述 QEMU 的全部可用参数，具体如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; QEMUOption qemu_options&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QEMU_OPTION_h&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QEMU_ARCH_ALL &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DEF&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; opt_arg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; opt_enum&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; opt_help&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; arch_mask&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;     \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;span&gt; option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; opt_arg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; opt_enum&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arch_mask &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; DEFHEADING&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;text&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ARCHHEADING&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;text&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; arch_mask&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;qemu-options.def&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; end of list &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，&lt;code&gt;qemu_options&lt;/code&gt; 数组中首先定义了一个参数 &lt;code&gt;h&lt;/code&gt;，其使用方法为 &lt;code&gt;qemu-system-riscv64 -h&lt;/code&gt;，作用是打印帮助信息。其余所有的可用参数都都通过 &lt;code&gt;DEF&lt;/code&gt; 宏定义在 &lt;code&gt;&amp;lt;qemu_build_dir&amp;gt;/qemu-options.def&lt;/code&gt; 文件中。需要注意的是，&lt;code&gt;qemu-options.def&lt;/code&gt; 文件是由 &lt;code&gt;scripts/hxtool&lt;/code&gt; 脚本在编译时根据 &lt;code&gt;qemu-options.hx&lt;/code&gt; 文件生成的，因此不在 QEMU 源代码目录中。&lt;/p&gt;
&lt;p&gt;对于含有多个子选项的参数，QEMU 在文件 &lt;code&gt;include/qemu/option_int.h&lt;/code&gt; 中定义了两个结构体 &lt;code&gt;QemuOpt&lt;/code&gt; 对子参数进行描述：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; QemuOpt &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span&gt; QemuOptDesc &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;desc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    union&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        bool&lt;/span&gt;&lt;span&gt; boolean&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        uint64_t&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; uint&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOpts     &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_ENTRY&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QemuOpt&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;QemuOpt&lt;/code&gt; 用于存储子选项，每个 &lt;code&gt;QemuOpt&lt;/code&gt; 结构体都有一个 &lt;code&gt;QemuOptDesc&lt;/code&gt; 类型的成员变量来描述子选项的信息。QEMU 在文件 &lt;code&gt;include/qemu/option.h&lt;/code&gt; 中定义了 &lt;code&gt;QemuOptsList&lt;/code&gt; 结构体用于进一步抽象描述一个参数的所有子选项，有关代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;enum&lt;/span&gt;&lt;span&gt; QemuOptType &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMU_OPT_STRING &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;  /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; no parsing (use string as-is) &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMU_OPT_BOOL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; on/off &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMU_OPT_NUMBER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;      /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; simple number &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QEMU_OPT_SIZE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; size, accepts (K)ilo, (M)ega, (G)iga, (T)era postfix &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; QemuOptDesc &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    enum&lt;/span&gt;&lt;span&gt; QemuOptType type&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;help&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;def_value_str&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; QemuOptDesc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; QemuOptsList &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;implied_opt_name&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    bool&lt;/span&gt;&lt;span&gt; merge_lists&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;  /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Merge multiple uses of option into a single list? &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_HEAD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QemuOpts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOptDesc desc&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;[]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述代码中，首先定义了枚举类型 &lt;code&gt;QemuOptType&lt;/code&gt; 用于描述不同的参数类型，包括字符串、布尔值、数字和空间大小四种。接着定义了结构体 &lt;code&gt;QemuOptDesc&lt;/code&gt; 用于存放对参数的描述信息，包括名称、类型、帮助信息和参数默认值。最后定义了结构体 &lt;code&gt;QemuOptsList&lt;/code&gt;，每一个 &lt;code&gt;QemuOptsList&lt;/code&gt; 结构体就对应了一个参数。但是，这里需要特别注意的是，&lt;code&gt;QemuOptsList&lt;/code&gt; 并不直接与 &lt;code&gt;QemuOpt&lt;/code&gt; 联系，中间需要通过结构体 &lt;code&gt;QemuOpts&lt;/code&gt; 进行转接：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;struct&lt;/span&gt;&lt;span&gt; QemuOpts &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Location loc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_HEAD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; QemuOpt&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    QTAILQ_ENTRY&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QemuOpts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样设计的目的在于避免发生参数混淆，QEMU 可以通过命令行指定创建两个相同的设备，这个时候这两个设备的选项都挂在 &lt;code&gt;QemuOptsList&lt;/code&gt; 上，但是分别属于两个独立的 &lt;code&gt;QemuOpts&lt;/code&gt;（&lt;code&gt;id&lt;/code&gt; 不同），每个 &lt;code&gt;QemuOpts&lt;/code&gt; 都维护自己的 &lt;code&gt;QemuOpt&lt;/code&gt; 链表，成员变量 &lt;code&gt;head&lt;/code&gt; 是 &lt;code&gt;QemuOpts&lt;/code&gt; 下的 &lt;code&gt;QemuOpt&lt;/code&gt; 链表头，成员变量 &lt;code&gt;next&lt;/code&gt; 用来连接同一 &lt;code&gt;QemuOptsList&lt;/code&gt; 下的其他 &lt;code&gt;QemuOpts&lt;/code&gt;，具体如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-parameters/./qemu-opts-list.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;QEMU 在 &lt;code&gt;util/qemu-config.c&lt;/code&gt; 中定义了一个全局的 &lt;code&gt;QemuOptsList&lt;/code&gt; 数组 &lt;code&gt;vm_config_groups&lt;/code&gt; 来储存所有可用的参数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;vm_config_groups&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;48&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;drive_config_groups&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这两行代码说明了 QEMU 最多支持 48 个参数，5 个驱动器参数。这两个全局数组由位于 &lt;code&gt;softmmu/vl.c&lt;/code&gt; 文件的 &lt;code&gt;qemu_init&lt;/code&gt; 函数负责初始化：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_drive_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_drive_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_legacy_drive_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_drive_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_common_drive_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_drive_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_drive_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_drive_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;bdrv_runtime_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_chardev_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_device_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_netdev_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_nic_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_net_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_rtc_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_global_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_mon_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_trace_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_plugin_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_option_rom_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_accel_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_mem_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_smp_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_boot_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_add_fd_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_object_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_tpmdev_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_overcommit_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_msg_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_name_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_numa_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_icount_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_semihosting_config_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_fw_cfg_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;qemu_action_opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中，&lt;code&gt;qemu_add_opts&lt;/code&gt; 函数的实现位于 &lt;code&gt;util/qemu-config.c&lt;/code&gt; 文件中，该函数主要负责将参数中传入的 &lt;code&gt;OemuOptsList&lt;/code&gt; 添加到全局数组 &lt;code&gt;vm_config_groups&lt;/code&gt; 中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_add_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;list&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entries &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; ARRAY_SIZE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vm_config_groups&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entries&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;--&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; keep list NULL terminated &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;vm_config_groups&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;            vm_config_groups&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    fprintf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;stderr&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;ran out of space in vm_config_groups&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    abort&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;di-yi-jie-duan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#di-yi-jie-duan&quot; aria-label=&quot;Anchor link for: di-yi-jie-duan&quot;&gt;第一阶段&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 参数解析的第一阶段，遍历参数数组，通过 &lt;code&gt;lookup_opt&lt;/code&gt; 函数来得到一个 &lt;code&gt;QEMUOption&lt;/code&gt;，判断这个 &lt;code&gt;QEMUOption&lt;/code&gt; 是否在之前初始化的的数组中。这一步骤的主要作用验证参数的合法性，下面结合源码具体分析：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; first pass of option parsing &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;argv&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;            /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; disk image &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            optind&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            const&lt;/span&gt;&lt;span&gt; QEMUOption &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            popt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; lookup_opt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;argc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            switch&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            case&lt;/span&gt;&lt;span&gt; QEMU_OPTION_nouserconfig&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                userconfig &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    machine_opts_dict &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qdict_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;userconfig&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qemu_read_default_config_file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先按照下标顺序依次读取终端传入的参数数组，跳过子选项，调用 &lt;code&gt;lookup_opt&lt;/code&gt; 函数查询读取的参数名称，然后初始化 &lt;code&gt;machine_opts_dict&lt;/code&gt; 数组，并根据实际情况加载用户配置。这里的 &lt;code&gt;machine_opts_dict&lt;/code&gt; 是一个字典结构，主要用于存储终端传入的参数数组中的虚拟机选项和参数，包括 CPU 数量、内存大小、设备配置等。&lt;code&gt;machine_opts_dict&lt;/code&gt; 的存在使得参数解析机制能够以一种结构化的方式管理和访问虚拟机参数，而不是使用分散的单独变量或者凌乱的数据结构。&lt;/p&gt;
&lt;p&gt;下面给出 &lt;code&gt;lookup_opt&lt;/code&gt; 函数的定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span&gt; QEMUOption &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;lookup_opt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;poptarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; int&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;poptind&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span&gt; QEMUOption &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;poptind&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;r &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argv&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    loc_set_cmdline&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; optind&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    optind&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; Treat --foo the same as -foo. &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;r&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    popt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; qemu_options&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;invalid option&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;strcmp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        popt&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;flags&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; HAS_ARG&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;requires an argument&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        optarg &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argv&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        loc_set_cmdline&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        optarg &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;poptarg &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; optarg&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    *&lt;/span&gt;&lt;span&gt;poptind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; optind&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; popt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lookup_opt&lt;/code&gt; 函数首先调用 &lt;code&gt;loc_set_cmdline&lt;/code&gt; 函数在终端传入的命令行参数中根据参数索引 &lt;code&gt;optind&lt;/code&gt; 进行定位，然后通过参数名称的比较在全局数组 &lt;code&gt;qemu_options&lt;/code&gt; 中寻找对应的 &lt;code&gt;QEMUOption&lt;/code&gt;。同时，&lt;code&gt;lookup_opt&lt;/code&gt; 函数会将参数后面的子选项保存到 &lt;code&gt;optarg&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;至此，我们不难发现，第一阶段的工作并没有涉及实际的参数解析，而是完成了从命令行读取用户的配置参数并对所有参数进行有效性验证，为第二阶段的正式解析做准备。QEMU 参数解析机制的两步设计，实现了验证逻辑和执行逻辑的有效分离，减少了出错的风险，使代码逻辑更加清晰。&lt;/p&gt;
&lt;h3 id=&quot;di-er-jie-duan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#di-er-jie-duan&quot; aria-label=&quot;Anchor link for: di-er-jie-duan&quot;&gt;第二阶段&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QEMU 参数解析的第二阶段，是真正解析具体参数并执行相应设置的阶段，主要逻辑如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    /*&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; second pass of option parsing &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;optind &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;argv&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            loc_set_cmdline&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; optind&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            drive_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IF_DEFAULT&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; argv&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; HD_OPTS&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            const&lt;/span&gt;&lt;span&gt; QEMUOption &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            popt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; lookup_opt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;argc&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; argv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;arch_mask&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; arch_type&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                error_report&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Option not supported for this target&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            switch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;popt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            case&lt;/span&gt;&lt;span&gt; QEMU_OPTION_cpu&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            default&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二阶段的逻辑就是按照下标顺序依次遍历终端传入的参数数组，调用 &lt;code&gt;lookup_opt&lt;/code&gt; 函数找到对应的 &lt;code&gt;QEMUOption&lt;/code&gt;，然后检查对应选项在当前架构下是否支持，最后使用 &lt;code&gt;switch&lt;/code&gt; 语句根据 &lt;code&gt;QEMUOption&lt;/code&gt; 的成员变量 &lt;code&gt;index&lt;/code&gt; 的不同来执行不同的分支完成具体的设置。&lt;/p&gt;
&lt;p&gt;下面将以不同的参数为例，详细说明参数解析第二阶段 &lt;code&gt;switch&lt;/code&gt; 语句中的分支执行流程。首先关注最为简单的 &lt;code&gt;-version&lt;/code&gt; 参数，其含义就是打印 QEMU 版本信息，然后退出程序，有关代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            case QEMU_OPTION_version:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                version&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，由于其含义最为简单，因此解析实现也非常简洁，直接调用 &lt;code&gt;version&lt;/code&gt; 函数打印版本信息，随后退出程序。接着分析 &lt;code&gt;-kernel&lt;/code&gt; 参数，通过对 &lt;code&gt;-kernel&lt;/code&gt; 参数解析流程的考察，我们可以一窥与机器设置有关的参数的解析机制。首先给出 &lt;code&gt;-kernel&lt;/code&gt; 参数在解析第二阶段分支执行的主要代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            case QEMU_OPTION_kernel:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                qdict_put_str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;machine_opts_dict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; optarg&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以发现，与机器设置有关的参数在整个解析过程中并不会真正执行具体设置，而是将对应的参数选项添加到 &lt;code&gt;machine_opts_dict&lt;/code&gt; 中，最终参数设置的落实工作由机器创建及初始化阶段的 &lt;code&gt;qemu_apply_legacy_machine_options&lt;/code&gt; 函数和 &lt;code&gt;qemu_apply_machine_options&lt;/code&gt; 函数完成，这一部分将在“QEMU 机器创建及初始化机制”的分析文章中具体阐述，本文不再赘述。下图给出了与与机器设置有关的参数从解析到落实的一般流程：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-parameters/./decode-parameters.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最后，观察 &lt;code&gt;-device&lt;/code&gt; 参数，同样给出分支执行代码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            case QEMU_OPTION_device:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;optarg&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    QObject &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;obj &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qobject_from_json&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;error_fatal&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    DeviceOption &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;opt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; g_new0&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DeviceOption&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    opt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qobject_to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QDict&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                    loc_save&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;loc&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                    assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                    QTAILQ_INSERT_TAIL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;device_opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; opt&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu_opts_parse_noisily&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu_find_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                                 optarg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                        exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分支执行的主要逻辑如下：首先检查 &lt;code&gt;optarg&lt;/code&gt;（&lt;code&gt;-device&lt;/code&gt; 选项的参数）是否以 &lt;code&gt;{&lt;/code&gt; 开始。如果是，说明 &lt;code&gt;optarg&lt;/code&gt; 是一个 JSON 对象，那么就需要调用 &lt;code&gt;qobject_from_json&lt;/code&gt; 函数将 JSON 对象转换为一个 &lt;code&gt;QObject&lt;/code&gt; 对象。然后，创建一个新的 &lt;code&gt;DeviceOption&lt;/code&gt; 对象，并将 &lt;code&gt;QObject&lt;/code&gt; 对象转换为一个 &lt;code&gt;QDict&lt;/code&gt; 并存储在 &lt;code&gt;DeviceOption&lt;/code&gt; 中，最后将 &lt;code&gt;DeviceOption&lt;/code&gt; 添加到 &lt;code&gt;device_opts&lt;/code&gt; 队列中。如果 &lt;code&gt;optarg&lt;/code&gt; 不是一个 JSON 对象，那么就调用 &lt;code&gt;qemu_opts_parse_noisily&lt;/code&gt; 函数将 &lt;code&gt;optarg&lt;/code&gt; 解析为一个 &lt;code&gt;QemuOpts&lt;/code&gt; 对象，并将这个对象添加到 &quot;device&quot; 选项的列表中。如果解析失败，则退出程序。下面我们重点关注 &lt;code&gt;else&lt;/code&gt; 分支的部分，首先给出 &lt;code&gt;qemu_find_opts&lt;/code&gt; 函数的定义，它位于 &lt;code&gt;util/qemu-config.c&lt;/code&gt; 文件中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;qemu_find_opts&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;group&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;local_err &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; find_list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vm_config_groups&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; group&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        error_report_err&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;local_err&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ret&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;qemu_find_opts&lt;/code&gt; 函数从全局数组 &lt;code&gt;vm_config_groups&lt;/code&gt; 中找到刚才插入的 &lt;code&gt;-device&lt;/code&gt; 选相对应的 &lt;code&gt;QemuOptsList&lt;/code&gt; 并返回，而 &lt;code&gt;qemu_opts_parse_noisily&lt;/code&gt; 函数只是简单调用了 &lt;code&gt;opts_parse&lt;/code&gt; 函数，后者会解析出一个 &lt;code&gt;QemuOpts&lt;/code&gt;，每一个大类的参数都会在相应的 &lt;code&gt;QemuOptsList&lt;/code&gt; 中构造 &lt;code&gt;QEMUOpts&lt;/code&gt;。继续分析 &lt;code&gt;opts_parse&lt;/code&gt; 函数：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span&gt; QemuOpts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;opts_parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QemuOptsList &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;params&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                            bool&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; permit_abbrev&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                            bool&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; warn_on_flag&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;help_wanted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;firstname&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;id &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; opts_parse_id&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOpts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    assert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;permit_abbrev &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;||&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;implied_opt_name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    firstname &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; permit_abbrev &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;?&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;implied_opt_name&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    opts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; qemu_opts_create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; !&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;merge_lists&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;opts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;opts_do_parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; params&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; firstname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                       warn_on_flag&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; help_wanted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        qemu_opts_del&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span&gt; opts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;opts_parse&lt;/code&gt; 函数代码中最重要的两行是对 &lt;code&gt;qemu_opts_create&lt;/code&gt; 函数和 &lt;code&gt;opts_do_parse&lt;/code&gt; 函数的调用，前者用来创建 &lt;code&gt;QemuOpts&lt;/code&gt; 并将它插入到对应的 &lt;code&gt;QemuOptsList&lt;/code&gt; 上，后者则负责解析出 &lt;code&gt;QemuOpt&lt;/code&gt;。函数 &lt;code&gt;opts_do_parse&lt;/code&gt; 的作用是解析参数的值，如本文开头例子中的命令行参数 &lt;code&gt;-device virtio-blk-device,drive=hd0&lt;/code&gt;。QEMU 的参数可能存在多种情况，比如上面的例子中 &lt;code&gt;virtio-blk-device&lt;/code&gt; 表示开启一个标志，也有可能类似于 &lt;code&gt;drive=hd0&lt;/code&gt; 的参数赋值语句。&lt;code&gt;opts_do_parse&lt;/code&gt; 函数需要处理各种情况，并对每一个值生成一个 &lt;code&gt;QemuOpt&lt;/code&gt;，关键代码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; opts_do_parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QemuOpts &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;params&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                          const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;firstname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                          bool&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; warn_on_flag&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;help_wanted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Error &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; char&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QemuOpt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt; params&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        p &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_opt_name_value&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; firstname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; warn_on_flag&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; help_wanted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;help_wanted &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; *&lt;/span&gt;&lt;span&gt;help_wanted&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        firstname &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;strcmp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            continue&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        opt &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; opt_create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opts&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; option&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        g_free&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;option&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;opt_validate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; errp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            qemu_opt_del&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;opts_do_parse&lt;/code&gt; 函数是 QEMU 参数解析过程的核心部分，它接受如下六个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;opts&lt;/code&gt; 是一个 &lt;code&gt;QemuOpts&lt;/code&gt; 对象，用于存储解析后的选项&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;params&lt;/code&gt; 是一个字符串，包含需要解析的参数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;firstname&lt;/code&gt; 是第一个选项的名字&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;warn_on_flag&lt;/code&gt; 是一个布尔值，如果为 &lt;code&gt;true&lt;/code&gt;，那么当遇到一个标志选项时，函数会打印一个警告消息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;help_wanted&lt;/code&gt; 是一个指向布尔值的指针，如果函数解析到一个 &lt;code&gt;help&lt;/code&gt; 选项，则设置 &lt;code&gt;*help_wanted&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;；&lt;code&gt;errp&lt;/code&gt; 是一个错误指针，如果函数遇到错误，则设置 &lt;code&gt;*errp&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;errp&lt;/code&gt; 是一个错误指针，如果函数遇到错误，那么它会设置 &lt;code&gt;*errp&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;opts_do_parse&lt;/code&gt; 函数使用一个 &lt;code&gt;for&lt;/code&gt; 循环一次遍历解析 &lt;code&gt;params&lt;/code&gt; 中的每个选项：首先调用 &lt;code&gt;get_opt_name_value&lt;/code&gt; 函数来获取下一个选项的名字和值，然后创建一个新的 &lt;code&gt;QemuOpt&lt;/code&gt; 对象并添加到 &lt;code&gt;opts&lt;/code&gt; 中，如果解析到一个 &lt;code&gt;help&lt;/code&gt; 选项，则会设置 &lt;code&gt;*help_wanted&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;，并立即返回 &lt;code&gt;false&lt;/code&gt;。注意，如果解析到的选项的名称是 &lt;code&gt;id&lt;/code&gt;，则会跳过这个选项，因为参数 &lt;code&gt;id&lt;/code&gt; 是用于设置 &lt;code&gt;QemuOpts&lt;/code&gt; 对象的 ID 的，不能当作普通参数解析为 &lt;code&gt;QemuOpt&lt;/code&gt;。最后，调用 &lt;code&gt;opt_validate&lt;/code&gt; 函数来验证新创建的 &lt;code&gt;QemuOpt&lt;/code&gt; 的有效性并返回解析结果。&lt;/p&gt;
&lt;p&gt;仍然以命令行参数 &lt;code&gt;-device virtio-blk-device,drive=hd0&lt;/code&gt; 为例，经过上述过程将解析出 2 个 &lt;code&gt;QemuOpt&lt;/code&gt; 并形成如下图所示的链表：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-parameters/./qemu-device-opts.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文以 QEMU 中引导 RISC-V 架构 Linux 内核启动的指令为例，总结归纳了 QEMU 常用参数的用法与含义，分析阐述了描述不同参数的各种数据结构的定义、作用以及相互关系，并按照 QEMU 的执行顺序详细梳理了数据结构初始化、参数解析第一阶段、参数解析第二阶段的代码逻辑。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/tinylab/riscv-linux/blob/master/articles/20220816-introduction-to-qemu-and-riscv-upstream-boot-flow.md&quot;&gt;《QEMU 启动方式分析（1）：QEMU 及 RISC-V 启动流程简介》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/system/invocation.html&quot;&gt;System Emulation: Invocation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;《QEMU/KVM 源码解析与应用》李强，机械工业出版社&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>QEMU 系统模式下指令解码模块简析：以 RISC-V 为例</title>
        <published>2023-07-08T00:00:00+00:00</published>
        <updated>2023-07-08T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/qemu-system-decode-analyse/"/>
        <id>https://jjl9807.com/posts/qemu-system-decode-analyse/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/qemu-system-decode-analyse/">&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-decode-analyse/./cover.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;qian-yan&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-yan&quot; aria-label=&quot;Anchor link for: qian-yan&quot;&gt;前言&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;QEMU 是一个通用的、开源的模拟器，通过纯软件方式实现硬件的虚拟化，模拟外部硬件，为用户提供抽象、虚拟的硬件环境。QEMU 亦可藉由硬件虚拟化变身为虚拟机。&lt;/p&gt;
&lt;p&gt;QEMU 支持以下两种方式进行模拟：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户模式（User Mode Emulation）：在一种架构的 CPU 上运行为另一种架构的 CPU 编译的程序。在该模式下，QEMU 作为进程级虚拟机，只模拟系统调用前的用户态代码，系统调用进入内核后，由宿主机操作系统原生执行，QEMU 提供不同架构系统调用映射的转换。&lt;/li&gt;
&lt;li&gt;系统模拟（System Emulation）：在该模式下，QEMU 作为系统级虚拟机提供运行客户机所需的完整环境，包括 CPU，内存和外围设备等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;gai-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gai-shu&quot; aria-label=&quot;Anchor link for: gai-shu&quot;&gt;概述&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;qemu-mo-ni-de-ji-ben-luo-ji&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qemu-mo-ni-de-ji-ben-luo-ji&quot; aria-label=&quot;Anchor link for: qemu-mo-ni-de-ji-ben-luo-ji&quot;&gt;QEMU 模拟的基本逻辑&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 提供两种 CPU 模拟实现方式，一种基于架构无关的中间码实现，另一种基于硬件虚拟化技术实现。&lt;/p&gt;
&lt;p&gt;第一种方式，QEMU 使用 &lt;code&gt;Tiny Code Generator&lt;/code&gt;（下文简称 &lt;code&gt;TCG&lt;/code&gt;）将客户机指令动态翻译为宿主机指令执行。这种方式的主要思想是使用纯软件的方法将客户机 CPU 指令先解码为架构无关的中间码（即 &lt;code&gt;Intermediate Representation&lt;/code&gt;），然后再把中间码翻译为宿主机 CPU 指令执行。其中，由客户机 CPU 指令解码为中间码的过程被称为前端，由中间码翻译为宿主机 CPU 指令的过程被称为后端。以 RISC-V 为例，指令的前端解码逻辑位于 &lt;code&gt;target/riscv&lt;/code&gt; 中，后端翻译逻辑位于 &lt;code&gt;tcg/&lt;/code&gt; 中，外设及其他硬件模拟代码位于 &lt;code&gt;hw/riscv&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;第二种方式，基于硬件虚拟化技术实现，直接使用宿主机 CPU 执行客户机指令，可以达到接近真实机器的运行性能。&lt;/p&gt;
&lt;p&gt;本文只关注系统模式下 TCG 方式的分析，不讨论基础硬件虚拟化技术的运行逻辑。&lt;/p&gt;
&lt;h2 id=&quot;qemu-fan-yi-zhi-xing-guo-cheng&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qemu-fan-yi-zhi-xing-guo-cheng&quot; aria-label=&quot;Anchor link for: qemu-fan-yi-zhi-xing-guo-cheng&quot;&gt;QEMU 翻译执行过程&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TCG 定义了一系列中间码，将已经翻译的代码以代码块的形式储存在 &lt;code&gt;Translation Block&lt;/code&gt; 中，通过跳转指令将宿主机 CPU 的指令集和客户机 CPU 的指令集链接。下图以 RISC-V 为例，给出了 QEMU v8.0.0 系统模拟的翻译执行流程。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-decode-analyse/./translation_and_execution_loop.svg&quot; alt=&quot;translation_and_execution_loop.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我们可以发现 TCG 前端解码和后端翻译都按照指令块的粒度进行，将一个客户机指令块翻译成中间码，然后把中间码翻译成宿主机 CPU 指令，整个过程动态执行。为了提高翻译效率，QEMU 将翻译成的宿主机 CPU 指令块做了缓存，即上文提到的 &lt;code&gt;Translation Block&lt;/code&gt;，CPU 执行的时候，先在缓存中查找对应的 &lt;code&gt;TB&lt;/code&gt;，如果查找成功就直接执行，否则进入翻译流程。&lt;/p&gt;
&lt;p&gt;从更加抽象的视角来看，TCG 模式下所谓客户机 CPU 的运行，实际上就是根据指令不断改变客户机 CPU 的状态，即改变描述客户机 CPU 的状态的数据结构中的有关变量。因为实际的代码执行过程是在宿主机 CPU 上完成的，因此客户机 CPU 的指令必须被翻译为宿主机 CPU 指令才能被执行，才能改变客户机 CPU 的数据状态。&lt;/p&gt;
&lt;p&gt;QEMU 为了解耦把客户机 CPU 指令先解码为中间码，中间码其实就是一组描述如何改变客户机 CPU 数据状态且架构无关的语句，所以目标 CPU 状态参数会被传入中间码描述语句。中间码实际上是改变客户机 CPU 状态的抽象的描述，对于部分难以抽象成一般描述的指令就用 &lt;code&gt;helper&lt;/code&gt; 函数进行补充。例如 RV32FD 指令集中的 &lt;code&gt;fadd.d rd, rs1, rs2&lt;/code&gt; 指令，表示双精度浮点加，将 &lt;code&gt;rs1&lt;/code&gt; 和 &lt;code&gt;rs2&lt;/code&gt; 寄存器中的双精度浮点数相加并将舍入后的结果送到 &lt;code&gt;rd&lt;/code&gt; 寄存器。对于该指令的行为，TCG 中间码并没有合适的描述，因此 QEMU 使用 &lt;code&gt;helper_fmadd_d&lt;/code&gt; 函数根据情况直接调用模拟 FPU 解决问题。最后，将中间码翻译为宿主机 CPU 代码时，TCG 后端使用 &lt;code&gt;tcg_gen_xxx&lt;/code&gt; 函数描述具体某条客户机 CPU 指令对客户机 CPU 数据状态的改变。&lt;/p&gt;
&lt;p&gt;翻译过程中 &lt;code&gt;gen_intermediate_code&lt;/code&gt; 函数负责前端解码，把客户机的指令翻译成中间码。而 &lt;code&gt;tcg_gen_code&lt;/code&gt; 负责后端翻译，将中间码翻译成宿主机 CPU 上的指令，其中 &lt;code&gt;tcg_out_xxx&lt;/code&gt; 函数执行具体的翻译工作。&lt;/p&gt;
&lt;h1 id=&quot;tcg-xi-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tcg-xi-jie&quot; aria-label=&quot;Anchor link for: tcg-xi-jie&quot;&gt;TCG 细节&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;qian-duan-jie-ma&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qian-duan-jie-ma&quot; aria-label=&quot;Anchor link for: qian-duan-jie-ma&quot;&gt;前端解码&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QEMU 定义了 &lt;code&gt;instruction pattern&lt;/code&gt; 来描述客户机 CPU 指令，一个 &lt;code&gt;instruction pattern&lt;/code&gt; 是指一组相同或相近的指令，RISC-V 架构的指令描述位于 &lt;code&gt;target/riscv&lt;/code&gt; 目录下的 &lt;code&gt;insn16.decode&lt;/code&gt;、&lt;code&gt;insn32.decode&lt;/code&gt; 文件中。&lt;/p&gt;
&lt;p&gt;QEMU 编译的时候会解析 &lt;code&gt;.decode&lt;/code&gt; 文件，使用脚本 &lt;code&gt;scripts/decodetree.py&lt;/code&gt; 生成对应指令描述函数的声明并存放于 &lt;code&gt;&amp;lt;qemu_build_dir&amp;gt;/libqemu-riscv64-softmmu.fa.p&lt;/code&gt; 目录下的 &lt;code&gt;decode-insn32.c.inc&lt;/code&gt; 和 &lt;code&gt;decode-insn16.c.inc&lt;/code&gt; 文件中。在这两个文件中还定义两个较为关键的解码函数 &lt;code&gt;decode_insn32&lt;/code&gt; 和 &lt;code&gt;decode_insn16&lt;/code&gt;，QEMU 将客户机指令翻译成中间码的时候需要调用这两个解码函数。需要注意的是，脚本 &lt;code&gt;scripts/decodetree.py&lt;/code&gt; 生成的只是 &lt;code&gt;trans_xxx&lt;/code&gt; 函数的声明，其定义需要开发者实现，RISC-V 对应的实现位于 &lt;code&gt;target/riscv/insn_trans/&lt;/code&gt; 目录中。&lt;/p&gt;
&lt;h2 id=&quot;decode-tree&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#decode-tree&quot; aria-label=&quot;Anchor link for: decode-tree&quot;&gt;Decode Tree&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;每种 &lt;code&gt;instruction pattern&lt;/code&gt; 都有固定位和固定掩码，它们的组合构成了模式匹配的条件：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;insn &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; fixedmask&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; ==&lt;/span&gt;&lt;span&gt; fixedbits&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于每种 &lt;code&gt;instruction pattern&lt;/code&gt;，&lt;code&gt;scripts/decodetree.py&lt;/code&gt; 脚本定义了具体描述形式，下面进行简要分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fields：&lt;/strong&gt; CPU 在解码的时候需要把指令中的特性 &lt;code&gt;field&lt;/code&gt; 中的数据取出作为传入参数（寄存器编号，立即数，操作码等），&lt;code&gt;field&lt;/code&gt; 描述一个指令编码中特定的字段，根据描述可以生成取对应字段的函数。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Input&lt;/th&gt;&lt;th&gt;Generated code&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;%disp 0:s16&lt;/td&gt;&lt;td&gt;sextract(i, 0, 16)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;%imm9 16:6 10:3&lt;/td&gt;&lt;td&gt;extract(i, 16, 6) &amp;lt;&amp;lt; 3 | extract(i, 10, 3)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;%disp12 0:s1 1:1 2:10&lt;/td&gt;&lt;td&gt;sextract(i, 0, 1) &amp;lt;&amp;lt; 11 | extract(i, 1, 1) &amp;lt;&amp;lt; 10 | extract(i, 2, 10)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;%shimm8 5:s8 13:1 !function=expand_shimm8&lt;/td&gt;&lt;td&gt;expand_shimm8(sextract(i, 5, 8) &amp;lt;&amp;lt; 1 | extract(i, 13, 1))&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;%sz_imm 10:2 sz:3 !function=expand_sz_imm&lt;/td&gt;&lt;td&gt;expand_sz_imm(extract(i, 10, 2) &amp;lt;&amp;lt; 3 | extract(a-&amp;gt;sz, 0, 3))&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;上表给出了一些例子，如第一行的 &lt;code&gt;%disp 0:s16&lt;/code&gt; 表示指令编码第 0 位起的 16 位构成了一个带符号数，因此生成代码 &lt;code&gt;sextract(i, 0, 16)&lt;/code&gt;，意即从指令 &lt;code&gt;i&lt;/code&gt; 的编码第 0 位开始取 16 位解释为带符号数返回。还有第三行的 &lt;code&gt;%disp12 0:s1 1:1 2:10&lt;/code&gt; 表示该立即数由三个部分拼接而成，因此生成的代码中就包含了相应的移位、拼接运算。由 &lt;code&gt;field&lt;/code&gt; 定义所生成的函数就负责完成这种与从指令编码中取数有关的计算。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Argument Sets：&lt;/strong&gt; 定义数据结构。比如，&lt;code&gt;target/riscv/insn32.decode&lt;/code&gt; 中定义的 &lt;code&gt;&amp;amp;b imm rs2 rs1&lt;/code&gt; 在编译后的 &lt;code&gt;decode-insn32.c.inc&lt;/code&gt; 中生成的数据结构如下，这个结构将作为 &lt;code&gt;trans_xxx&lt;/code&gt; 函数的传入参数。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;typedef&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; struct&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; imm&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; rs2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; rs1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; arg_b&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Formats：&lt;/strong&gt; 定义指令的格式，例如下面的例子是对一个 32-bit 指令编码的描述，其中 &lt;code&gt;.&lt;/code&gt; 表示一个 bit 位。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@opr    ...... ra:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;span&gt; rb:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;span&gt; ... &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;span&gt; ....... rc:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@opi    ...... ra:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;span&gt; lit:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;    1&lt;/span&gt;&lt;span&gt; ....... rc:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Patterns：&lt;/strong&gt; 用来定义具体指令。这里借助 RV32I 基础指令集中的 &lt;code&gt;lui&lt;/code&gt; 指令进行详细分析：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lui      ....................       ..... &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;110111&lt;/span&gt;&lt;span&gt; @u&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外列出相关的 format、argument、field 的定义，以便分析：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Argument sets:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;u    imm rd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Formats &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@u       ....................      ..... ....... &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;u      imm&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span&gt;imm_u          &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Fields:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span&gt;rd        &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;7&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# immediates:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;%&lt;/span&gt;&lt;span&gt;imm_u    &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;12&lt;/span&gt;&lt;span&gt;:s20                 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;!&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span&gt;ex_shift_12&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到 &lt;code&gt;lui&lt;/code&gt; 指令的操作码是 &lt;code&gt;0110111&lt;/code&gt;，指令的格式定义是 &lt;code&gt;@u&lt;/code&gt;，使用的参数定义是 &lt;code&gt;&amp;amp;u&lt;/code&gt;，而 &lt;code&gt;&amp;amp;u&lt;/code&gt; 就是 &lt;code&gt;trans_lui&lt;/code&gt; 函数的传入参数结构体里的变量定义，其中定义的变量名字是 &lt;code&gt;imm&lt;/code&gt;、&lt;code&gt;rd&lt;/code&gt;，这个 &lt;code&gt;imm&lt;/code&gt; 实际的格式是 &lt;code&gt;%imm_u&lt;/code&gt;，它是一个由指令编码 31-12 位定义的立即数，将指令编码 31-12 位的数值左移 12 位即可得到最终结果，&lt;code&gt;rd&lt;/code&gt; 实际的格式是 &lt;code&gt;%rd&lt;/code&gt;，是一个在指令编码 7-5 位定义的 &lt;code&gt;rd&lt;/code&gt; 寄存器的标号。&lt;/p&gt;
&lt;p&gt;可以看到 &lt;code&gt;target/riscv/insn_trans/trans_rvi.c.inc&lt;/code&gt; 中对应的 &lt;code&gt;trans_lui&lt;/code&gt; 函数的实现如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; trans_lui&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DisasContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arg_lui &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    gen_set_gpri&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;imm&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;trans-xxx-han-shu&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#trans-xxx-han-shu&quot; aria-label=&quot;Anchor link for: trans-xxx-han-shu&quot;&gt;trans_xxx 函数&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;trans_xxx&lt;/code&gt; 函数负责将具体的客户机指令转换为中间码指令，若转换成功则返回 &lt;code&gt;true&lt;/code&gt;，否则返回 &lt;code&gt;false&lt;/code&gt;。下面以 RISC-V 架构的 &lt;code&gt;add&lt;/code&gt; 指令为例进行分析。&lt;/p&gt;
&lt;p&gt;如下是 &lt;code&gt;target/riscv/insn_trans/trans_rvi.c.inc&lt;/code&gt; 文件中对 &lt;code&gt;add&lt;/code&gt; 指令的模拟。&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; trans_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DisasContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arg_add &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; gen_arith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; EXT_NONE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; tcg_gen_add_tl&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; tcg_gen_add2_tl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;函数 &lt;code&gt;gen_arith&lt;/code&gt; 被定义在文件 &lt;code&gt;target/riscv/translate.c&lt;/code&gt; 中：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; bool&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; gen_arith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DisasContext &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arg_r &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; DisasExtend &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ext&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                      void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;                      void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;*&lt;/span&gt;&lt;span&gt;f128&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TCGv dest &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; dest_gpr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TCGv src1 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_gpr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rs1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TCGv src2 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_gpr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rs2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ext&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;get_ol&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; MXL_RV128&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        func&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;dest&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        gen_set_gpr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; dest&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;f128 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TCGv src1h &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_gprh&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rs1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TCGv src2h &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; get_gprh&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rs2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TCGv desth &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; dest_gprh&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        f128&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;dest&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; desth&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src1h&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; src2h&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        gen_set_gpr128&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;rd&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; dest&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; desth&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意到函数中 &lt;code&gt;func&lt;/code&gt; 指向的函数是由 &lt;code&gt;trans_add&lt;/code&gt; 传入的 &lt;code&gt;tcg_gen_add_tl&lt;/code&gt; 函数，而此函数又在 &lt;code&gt;inluce/tcg/tcg-op.h&lt;/code&gt; 中以宏定义的形式被定义为 &lt;code&gt;tcg_gen_add_i64&lt;/code&gt; 或 &lt;code&gt;tcg_gen_add_i32&lt;/code&gt; 函数，下面给出 &lt;code&gt;tcg_gen_add_i64&lt;/code&gt; 函数的定义：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; tcg_gen_addi_i64&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TCGv_i64 &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;ret&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; TCGv_i64 &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;arg1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; int64_t&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; arg2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;arg2 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        tcg_gen_mov_i64&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arg1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;TCG_TARGET_REG_BITS &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 64&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        tcg_gen_add_i64&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; arg1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; tcg_constant_i64&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arg2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;        tcg_gen_add2_i32&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;TCGV_LOW&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; TCGV_HIGH&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ret&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                         TCGV_LOW&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arg1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; TCGV_HIGH&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arg1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;                         tcg_constant_i32&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arg2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; tcg_constant_i32&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arg2 &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RISC-V 的 &lt;code&gt;add&lt;/code&gt; 指令内容是从 CPU 的 &lt;code&gt;rs1&lt;/code&gt; 和 &lt;code&gt;rs2&lt;/code&gt; 寄存器中取操作数，相加后送入 &lt;code&gt;rd&lt;/code&gt; 寄存器中。宏观上看，&lt;code&gt;gen_arith&lt;/code&gt; 函数首先调用 &lt;code&gt;dest_gpr&lt;/code&gt; 和 &lt;code&gt;get_gpr&lt;/code&gt; 这两个寄存器操作封装函数获取 &lt;code&gt;rs1&lt;/code&gt; 和 &lt;code&gt;rs2&lt;/code&gt; 寄存器的值，并准备 &lt;code&gt;rd&lt;/code&gt; 寄存器。然后通过 &lt;code&gt;func(dest, src1, src2)&lt;/code&gt; 最终调用 &lt;code&gt;tcg_gen_addi_i64&lt;/code&gt; 函数完成两数相加，最后使用 &lt;code&gt;gen_set_gpr&lt;/code&gt; 将结果传送至 &lt;code&gt;rd&lt;/code&gt; 寄存器，完成 &lt;code&gt;add&lt;/code&gt; 指令解码。&lt;/p&gt;
&lt;p&gt;接着，我们针对 &lt;code&gt;gen_set_gpr&lt;/code&gt; 进行深入分析，以 RV32 指令为例，追踪该函数的调用链：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-decode-analyse/./gen_set_gpr.svg&quot; alt=&quot;gen_set_gpr.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分析上述调用链的参数可以发现最后生成了一条 &lt;code&gt;mov_i32 t0, t1&lt;/code&gt; 指令，意思是将 &lt;code&gt;t1&lt;/code&gt; 寄存器中的数移动到 &lt;code&gt;t0&lt;/code&gt; 寄存器中。该指令先被挂到了一个链表里，此后的后端翻译会把这些指令翻译成宿主机指令。到这里，前端解码的逻辑就基本上打通了。还有最后一个问题需要解决：&lt;code&gt;cpu_gpr[reg_num]&lt;/code&gt; 这个全局变量是如何索引到客户机 CPU 寄存器的？&lt;/p&gt;
&lt;p&gt;解决该问题的基本思路是，只要 TCG 前端和后端约定描述客户机 CPU 状态数据结构相同，确保 &lt;code&gt;cpu_gpr[reg_num]&lt;/code&gt; 指向的就是相关寄存器在这个数据结构中的位置即可，这一点在 &lt;code&gt;cpu_gpr[]&lt;/code&gt; 数组的初始化过程中具体体现：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; riscv_translate_init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;    //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;        cpu_gpr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; tcg_global_mem_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cpu_env&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;            offsetof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CPURISCVState&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; gpr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; riscv_int_regnames&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;        //&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt;	//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-3&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cpu_gpr[]&lt;/code&gt; 数组在初始化时调用 &lt;code&gt;tcg_global_mem_new&lt;/code&gt; 函数在 TCG 上下文 &lt;code&gt;tcg_ctx&lt;/code&gt; 中分配空间并返回其相对地址，而后段翻译时访问 &lt;code&gt;cpu_gpr[]&lt;/code&gt; 数组就是在访问 TCG 上下文中描述寄存器的变量，这样 &lt;code&gt;cpu_gpr[reg_name]&lt;/code&gt; 就在前端和后端之间建立了连接。&lt;/p&gt;
&lt;h2 id=&quot;hou-duan-fan-yi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hou-duan-fan-yi&quot; aria-label=&quot;Anchor link for: hou-duan-fan-yi&quot;&gt;后端翻译&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;后端的代码主要负责将中间码翻译成宿主机指令，本质上就是根据中间码的描述使用宿主机指令来改变内存中表示的客户机 CPU 的数据结构以及客户机内存的状态。考虑以下两条 RISC-V 汇编指令：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;addi            &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;,-&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sd              s0,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;24&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过前端解码，可以得到以下中间码：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add_i64 x2/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;,x2/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;$0xffffffffffffffe0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add_i64 tmp4,x2/&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;sp&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;$0x18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qemu_st_i64 x8/s0,tmp4,leq,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意到 &lt;code&gt;sd&lt;/code&gt; 指令被翻译成了两条中间码，第一条 &lt;code&gt;add_i64&lt;/code&gt; 是用来计算 &lt;code&gt;sd&lt;/code&gt; 指令的目标地址，计算结果保存在 &lt;code&gt;tmp4&lt;/code&gt; 这个虚拟寄存器里，第二条中间码把 &lt;code&gt;s0&lt;/code&gt; 的值储存到虚拟寄存器 &lt;code&gt;tmp4&lt;/code&gt; 描述的内存上。在中间码中，&lt;code&gt;x2/sp&lt;/code&gt; 和 &lt;code&gt;x8/s0&lt;/code&gt; 仍然是客户机 CPU 上寄存器的名字，但是逻辑上已经全部映射为 QEMU 虚拟寄存器。TCG 前端将 RISC-V 汇编指令解码为中间码和虚拟寄存器的表示，后端翻译则基于中间码和虚拟寄存器进行。再次审视上述两条指令，&lt;code&gt;addi&lt;/code&gt; 的中间码表示要把客户机的 &lt;code&gt;sp&lt;/code&gt; 寄存器加上 &lt;code&gt;-32&lt;/code&gt;，&lt;code&gt;sd&lt;/code&gt; 的中间码表示要将客户机的 &lt;code&gt;s0&lt;/code&gt; 寄存器中的值送到 &lt;code&gt;sp&lt;/code&gt; 寄存器加 24 后得到的地址处。对于这些中间码，在 ARM 架构的宿主机上可能被翻译为以下指令：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ldr      x20, [x19, #&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0x10&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;sub&lt;/span&gt;&lt;span&gt;      x20, x20, #&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0x20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;str&lt;/span&gt;&lt;span&gt;      x20, [x19, #&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0x10&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;add&lt;/span&gt;&lt;span&gt;      x21, x20, #&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0x18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ldr      x22, [x19, #&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt;0x40&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;str&lt;/span&gt;&lt;span&gt;      x22, [x21, xzr]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段指令主要进行了以下操作：把客户机 CPU 的 &lt;code&gt;sp&lt;/code&gt; 寄存器装载到宿主机 CPU 的 &lt;code&gt;x20&lt;/code&gt; 寄存器，使用 &lt;code&gt;sub&lt;/code&gt; 指令完成客户机 CPU &lt;code&gt;sp&lt;/code&gt; 寄存器值的计算并进行更新；使用 &lt;code&gt;add&lt;/code&gt; 指令计算客户机 CPU 的 &lt;code&gt;sd&lt;/code&gt; 指令的目标地址并保存到宿主机 CPU 的 &lt;code&gt;x21&lt;/code&gt; 寄存器，接着把客户机 CPU 的 &lt;code&gt;s0&lt;/code&gt; 寄存器装载到宿主机 CPU 的 &lt;code&gt;x22&lt;/code&gt; 寄存器，最后使用 &lt;code&gt;str&lt;/code&gt; 指令更新目标地址处的值。&lt;/p&gt;
&lt;p&gt;通过以上案例可以发现，TCG 后端主要完成三件事情：分配宿主机 CPU 寄存器、生成宿主机 CPU 指令以及宿主机 CPU 和客户机 CPU 之间的状态同步。其中，状态同步实际上通过两次映射完成：第一次是 TCG 前端解码时将客户机 CPU 寄存器映射为 QEMU 虚拟寄存器，第二次是 TCG 后端分配宿主机 CPU 寄存器时将 QEMU 虚拟寄存器映射为宿主机 CPU 的物理寄存器。&lt;/p&gt;
&lt;p&gt;下面仍然以 &lt;code&gt;add&lt;/code&gt; 指令为例，给出后端代码调用过程的详细分析：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jjl9807.com/posts/qemu-system-decode-analyse/./tcg_gen_code.svg&quot; alt=&quot;tcg_gen_code.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tcg_gen_code&lt;/code&gt; 是整个后端翻译的入口，负责寄存器和内存区域之间的同步逻辑并根据不同指令类型调用相关函数将中间码翻译为宿主机 CPU 指令。默认情况下，&lt;code&gt;tcg_gen_code&lt;/code&gt; 会调用 &lt;code&gt;tcg_reg_alloc_op&lt;/code&gt; 函数，该函数会生成用宿主机 CPU 指令描述的同步逻辑，存放在 &lt;code&gt;TB&lt;/code&gt; 中，最后调用不同架构的开发者提供的 &lt;code&gt;tcg_out_op&lt;/code&gt; 函数完成具体指令的翻译工作。针对 &lt;code&gt;add&lt;/code&gt; 指令，最终会调用 &lt;code&gt;tcg_out32()&lt;/code&gt; 函数，该函数负责将一个 32 位无符号整数 &lt;code&gt;v&lt;/code&gt; 写入到指针 &lt;code&gt;s-&amp;gt;code_ptr&lt;/code&gt; 对应的内存位置，并根据目标平台的指令单元大小更新该指针的值。&lt;/p&gt;
&lt;h1 id=&quot;zong-jie&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot;&gt;总结&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;本文主要分析了 QEMU 系统模式下指令解码模块。QEMU 将客户机 CPU 指令解码为中间码，中间码是对指令如何改变客户机 CPU 数据状态的抽象描述，TCG 后端将中间码翻译为宿主机 CPU 指令，也就是将中间码所描述的对客户机 CPU 数据状态的更改用宿主机 CPU 指令的形式进行描述，执行完成后就达到了模拟客户机 CPU 运行的效果。&lt;/p&gt;
&lt;p&gt;至此，从前端到后端，从解码到翻译的逻辑链条就完整了。&lt;/p&gt;
&lt;h1 id=&quot;can-kao-zi-liao&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#can-kao-zi-liao&quot; aria-label=&quot;Anchor link for: can-kao-zi-liao&quot;&gt;参考资料&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/devel/decodetree.html&quot;&gt;Decodetree Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.qemu.org/docs/master/devel/tcg-ops.html&quot;&gt;TCG Intermediate Representation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Markdown Test</title>
        <published>2023-06-23T00:00:00+00:00</published>
        <updated>2024-05-20T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://jjl9807.com/posts/markdown/"/>
        <id>https://jjl9807.com/posts/markdown/</id>
        
        <content type="html" xml:base="https://jjl9807.com/posts/markdown/">&lt;h1 id=&quot;h1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#h1&quot; aria-label=&quot;Anchor link for: h1&quot;&gt;H1&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;h2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#h2&quot; aria-label=&quot;Anchor link for: h2&quot;&gt;H2&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;h3&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#h3&quot; aria-label=&quot;Anchor link for: h3&quot;&gt;H3&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet sagittis id consectetur purus ut. In pellentesque massa placerat duis ultricies. Neque laoreet suspendisse interdum consectetur libero id. Justo nec ultrices dui sapien eget mi proin. Nunc consequat interdum varius sit amet mattis vulputate. Sollicitudin tempor id eu nisl nunc mi ipsum. Non odio euismod lacinia at quis. Sit amet nisl suscipit adipiscing. Amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Sit amet consectetur adipiscing elit pellentesque habitant. Ac placerat vestibulum lectus mauris. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. &lt;a rel=&quot;external&quot; href=&quot;https://www.google.com&quot;&gt;Google&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://markdown-here.com/img/icon256.png&quot; alt=&quot;Markdown Logo&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;code-block&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#code-block&quot; aria-label=&quot;Anchor link for: code-block&quot;&gt;Code Block&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ordered-list&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ordered-list&quot; aria-label=&quot;Anchor link for: ordered-list&quot;&gt;Ordered List&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;First item&lt;/li&gt;
&lt;li&gt;Second item&lt;/li&gt;
&lt;li&gt;Third item&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;unordered-list&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#unordered-list&quot; aria-label=&quot;Anchor link for: unordered-list&quot;&gt;Unordered List&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;List item&lt;/li&gt;
&lt;li&gt;Another item&lt;/li&gt;
&lt;li&gt;And another item&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;nested-list&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#nested-list&quot; aria-label=&quot;Anchor link for: nested-list&quot;&gt;Nested list&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fruit
&lt;ul&gt;
&lt;li&gt;Apple&lt;/li&gt;
&lt;li&gt;Orange&lt;/li&gt;
&lt;li&gt;Banana&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dairy
&lt;ul&gt;
&lt;li&gt;Milk&lt;/li&gt;
&lt;li&gt;Cheese&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;quote&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#quote&quot; aria-label=&quot;Anchor link for: quote&quot;&gt;Quote&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Two things are infinite: the universe and human stupidity; and I&#39;m not sure about the
universe.&lt;br&gt;
— &lt;cite&gt;Albert Einstein&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;table-inline-markdown&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#table-inline-markdown&quot; aria-label=&quot;Anchor link for: table-inline-markdown&quot;&gt;Table Inline Markdown&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Italics&lt;/th&gt;&lt;th&gt;Bold&lt;/th&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;StrikeThrough&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;italics&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;bold&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;del&gt;strikethrough&lt;/del&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;foldable-text&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#foldable-text&quot; aria-label=&quot;Anchor link for: foldable-text&quot;&gt;Foldable Text&lt;/a&gt;&lt;/h2&gt;
&lt;details&gt;
    &lt;summary&gt;Title 1&lt;/summary&gt;
    &lt;p&gt;IT&#39;S A SECRET TO EVERYBODY.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
    &lt;summary&gt;Title 2&lt;/summary&gt;
    &lt;p&gt;Stay awhile, and listen!&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id=&quot;code-tags&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#code-tags&quot; aria-label=&quot;Anchor link for: code-tags&quot;&gt;Code tags&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lorem ipsum &lt;code&gt;dolor&lt;/code&gt; sit amet, &lt;code&gt;consectetur adipiscing&lt;/code&gt; elit.
&lt;code&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;github-style-alerts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#github-style-alerts&quot; aria-label=&quot;Anchor link for: github-style-alerts&quot;&gt;GitHub-style alerts&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;Highlights information that users should take into account, even when skimming.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class=&quot;markdown-alert-tip&quot;&gt;
&lt;p&gt;Optional information to help a user be more successful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class=&quot;markdown-alert-important&quot;&gt;
&lt;p&gt;Crucial information necessary for users to succeed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class=&quot;markdown-alert-warning&quot;&gt;
&lt;p&gt;Critical content demanding immediate user attention due to potential risks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class=&quot;markdown-alert-caution&quot;&gt;
&lt;p&gt;Negative potential consequences of an action.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;extensions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#extensions&quot; aria-label=&quot;Anchor link for: extensions&quot;&gt;Extensions&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;mermaid&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#mermaid&quot; aria-label=&quot;Anchor link for: mermaid&quot;&gt;Mermaid&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This Theme supports &lt;a rel=&quot;external&quot; href=&quot;https://mermaid.js.org/&quot;&gt;mermaid&lt;/a&gt; markdown diagram rendering.&lt;/p&gt;
&lt;p&gt;To use mermaid diagrams in your posts, see the example in the raw markdown code.
https://raw.githubusercontent.com/not-matthias/apollo/refs/heads/main/content/posts/mermaid.md&lt;/p&gt;
&lt;script src=https://jjl9807.com/js/mermaid.js&gt;&lt;/script&gt;
&lt;pre class=&quot;mermaid&quot;&gt;

graph LR
    A[Start] --&gt; B[Initialize]
    B --&gt; C[Processing]
    C --&gt; D[Complete]
    D --&gt; E[Success]

    style A fill:#f9f,stroke:#333
    style E fill:#9f9,stroke:#333

&lt;/pre&gt;
&lt;h2 id=&quot;math-symbol&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#math-symbol&quot; aria-label=&quot;Anchor link for: math-symbol&quot;&gt;Math Symbol&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Note: This requires &lt;code&gt;mathjax = true&lt;/code&gt; in the page&#39;s &lt;code&gt;[extra]&lt;/code&gt; section (per-page) or in the site&#39;s &lt;code&gt;config.toml&lt;/code&gt; &lt;code&gt;[extra]&lt;/code&gt; section (global).&lt;/p&gt;
&lt;h3 id=&quot;inline-math&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#inline-math&quot; aria-label=&quot;Anchor link for: inline-math&quot;&gt;Inline Math&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;-&lt;/span&gt;&lt;span&gt; $(a+b)^2$ = $a^2 + 2ab + b^2$&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt;-&lt;/span&gt;&lt;span&gt; A polynomial P of degree d over $\mathbb{F}_p$ is an expression of the form&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $P(s) = a_0 + a_1 . s + a_2 . s^2 + ... + a_d . s^d$ for some&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  $a_0,..,a_d \in \mathbb{F}_p$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;$(a+b)^2$ = $a^2 + 2ab + b^2$&lt;/li&gt;
&lt;li&gt;A polynomial P of degree d over $\mathbb{F}_p$ is an expression of the form
$P(s) = a_0 + a_1 . s + a_2 . s^2 + ... + a_d . s^d$ for some
$a_0,..,a_d \in \mathbb{F}_p$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;displayed-math&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#displayed-math&quot; aria-label=&quot;Anchor link for: displayed-math&quot;&gt;Displayed Math&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$$&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;p := (\sum_{k∈I}{c_k.v_k} + \delta_v.t(x))·(\sum_{k∈I}{c_k.w_k} + \delta_w.t(x)) − (\sum_{k∈I}{c_k.y_k} + \delta_y.t(x))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$$
p := (\sum_{k∈I}{c_k.v_k} + \delta_v.t(x))·(\sum_{k∈I}{c_k.w_k} + \delta_w.t(x)) − (\sum_{k∈I}{c_k.y_k} + \delta_y.t(x))
$$&lt;/p&gt;
&lt;h2 id=&quot;line-highlighting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#line-highlighting&quot; aria-label=&quot;Anchor link for: line-highlighting&quot;&gt;Line Highlighting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section demonstrates Zola&#39;s &lt;a rel=&quot;external&quot; href=&quot;https://www.getzola.org/documentation/content/syntax-highlighting/&quot;&gt;code block annotations&lt;/a&gt; supported by the Apollo theme.&lt;/p&gt;
&lt;h3 id=&quot;line-numbers&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#line-numbers&quot; aria-label=&quot;Anchor link for: line-numbers&quot;&gt;Line Numbers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;linenos&lt;/code&gt; to enable line numbering.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;single-line-highlighting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#single-line-highlighting&quot; aria-label=&quot;Anchor link for: single-line-highlighting&quot;&gt;Single Line Highlighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;hl_lines=2&lt;/code&gt; to highlight a specific line.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos,hl_lines=2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;multi-line-highlighting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#multi-line-highlighting&quot; aria-label=&quot;Anchor link for: multi-line-highlighting&quot;&gt;Multi-Line Highlighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;hl_lines=2 3&lt;/code&gt; to highlight multiple lines.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos,hl_lines=2 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;range-highlighting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#range-highlighting&quot; aria-label=&quot;Anchor link for: range-highlighting&quot;&gt;Range Highlighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;hl_lines=1-3&lt;/code&gt; to highlight a range of lines.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos,hl_lines=1-3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l z-l-hl z-d-hl&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;custom-line-number-start&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#custom-line-number-start&quot; aria-label=&quot;Anchor link for: custom-line-number-start&quot;&gt;Custom Line Number Start&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;linenostart=10&lt;/code&gt; to start line numbers at a specific value.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos,linenostart=10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-6&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;hidden-lines&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hidden-lines&quot; aria-label=&quot;Anchor link for: hidden-lines&quot;&gt;Hidden Lines&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;hide_lines=2&lt;/code&gt; to hide specific lines from the output.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```rust,linenos,hide_lines=2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Hello World&amp;quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-7&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-4&quot;&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
</feed>
