Skip to main content

Config

Struct Config 

Source
pub struct Config {
Show 118 fields pub virtualize_time: bool, pub virtualize_cpuid: bool, pub cpu_profile: CpuProfile, pub cpu_profile_host: Option<HostXstate>, pub cpu_profile_source: Option<usize>, pub backend: BackendCapabilities, pub guest_may_inherit_a_terminal: bool, pub in_guest_detlog_forward_policy: Option<String>, pub in_guest_site_patching_off: bool, pub in_guest_reserved_signals: u64, pub in_guest_refuses_host_timed_producers: bool, pub launch_image: Option<LaunchImage>, pub inherited_seccomp: InheritedSeccomp, pub epoch: DateTime<Utc>, pub seed: u64, pub rng_seed: Option<u64>, pub fuzz_seed: Option<u64>, pub clock_multiplier: Option<f64>, pub virtualize_metadata: bool, pub mountinfo_root_rewrites: Vec<MountInfoRootRewrite>, pub mountinfo_device_rewrites: Vec<(u64, u64)>, pub mountinfo_mount_ids: Vec<u64>, pub mountinfo_mount_ids_captured: bool, pub mountinfo_mount_namespace: Option<MountNamespaceIdentity>, pub mount_id_assignment_order: Vec<u64>, pub container_mount_table: Option<ContainerMountTable>, pub directory_placeholder: Option<PathBuf>, pub container_procfs: bool, pub sequentialize_threads: bool, pub runs_post_fork: RunsPostFork, pub passthru_opt: bool, pub imprecise_timers: bool, pub eager_lone_preemptions: bool, pub signal_state_copy: bool, pub signal_delivery_check_fatal: bool, pub chaos: bool, pub chaos_timeslice_range: Option<TimesliceRange>, pub chaos_timeslice_draw: ChaosTimesliceDraw, pub chaos_timeslice: Option<NonZeroU64>, pub fuzz_futexes: bool, pub chaos_target_races: bool, pub chaos_per_thread_slowdown: bool, pub chaos_slowdown_max_factor: f64, pub chaos_epoch_length_ns: u64, pub record_preemptions: bool, pub strict_schedule_boundaries: bool, pub record_preemptions_to: Option<PathBuf>, pub replay_preemptions_from: Option<PathBuf>, pub replay_schedule_from: Option<PathBuf>, pub replay_exhausted_panic: bool, pub die_on_desync: bool, pub replay_edited_preemptions: bool, pub replay_continue_fairly: bool, pub stacktrace_event: Vec<(u64, Option<PathBuf>)>, pub stacktrace_signal: Option<SigWrapper>, pub access_trace: Option<PathBuf>, pub access_trace_from: u64, pub access_trace_max_records: Option<u64>, pub access_trace_max_bytes: Option<u64>, pub preemption_stacktrace: bool, pub preemption_stacktrace_log_file: Option<PathBuf>, pub deterministic_io: bool, pub panic_on_unsupported_syscalls: bool, pub exit_on_unsupported_syscall: bool, pub shutdown_on_unsupported_syscall: bool, pub unsupported_syscall_report_fd: Option<i32>, pub panic_on_rcb_overshoot: bool, pub has_uts_namespace: bool, pub notice_host_network_abstract_binds: bool, pub guest_ids: GuestIds, pub standard_stream_aliases: Option<[u8; 3]>, pub replay_data: Option<PathBuf>, pub kill_daemons: bool, pub gdbserver: bool, pub gdbserver_port: u16, pub max_timeslice: MaybeTimeslice, pub target_timeslice: Option<NonZeroU64>, pub target_timeslice_syscalls_only: bool, pub futex_wake_yields: bool, pub pipe_wake_latency: Option<u64>, pub expired_wait_charge: Option<ExpiredWaitCharge>, pub work_span_report: Option<PathBuf>, pub scheduler_turn_cost: Option<NonZeroU64>, pub cap_preemption_charge: bool, pub virtual_timeout: Option<NonZeroU64>, pub sigint_instakill: bool, pub warn_non_zero_binds: bool, pub sched_heuristic: SchedHeuristic, pub sched_seed: Option<u64>, pub network_trace: NetworkTraceConfig, pub sched_sticky_random_param: f64, pub recordreplay_modes: bool, pub replaying: bool, pub stop_after_turn: Option<u64>, pub stop_after_iter: Option<u64>, pub signal_at: Option<SignalAt>, pub debug_externalize_sockets: bool, pub debug_futex_mode: BlockingMode, pub no_rcb_time: bool, pub detlog_heap: bool, pub detlog_stack: bool, pub detlog_anon: Option<DetlogAnon>, pub detlog_regs: bool, pub detlog_io_buffers: bool, pub detlog_regs_cadence: u64, pub sysinfo_uptime_offset: u64, pub memory: u64, pub virtual_cpus: Option<NonZeroU32>, pub proc_level: ProcLevel, pub interrupt_at: Vec<(DetTid, u64)>, pub happens_before: Option<HappensBeforeProgram>, pub record_host_inputs: bool, pub host_input_log: Option<PathBuf>, pub host_input_snapshots: Vec<HostInputSnapshot>, pub untraced_code_range: Option<(u64, u64)>, pub fatal_core_capture: Option<FatalCoreCapture>, pub in_guest_signal_delivery: bool, pub annotated_priority_replay: bool,
}
Expand description

Configuration options for detcore.

Fields§

§virtualize_time: bool

Disable virtual/logical time. Note that virtual time is required for virtual metadata.

§virtualize_cpuid: bool

Disable virtual cpuid

§cpu_profile: CpuProfile

The CPU the guest sees: virtual x86-64-v2/v3 or intercepted host features without hardware randomness. The long help states each profile’s host requirements and determinism limits. Like HERMIT_EPOCH, HERMIT_CPU_PROFILE supplies the value when the flag is absent; an explicit flag wins, unset means x86-64-v2, and a value that names no profile is refused. Admission is the same either way.

§cpu_profile_host: Option<HostXstate>

The host facts a v3 guest’s leaf 0xD and xstate answers come from, set by the CLI after the host qualifies; None under v2. Neither profile field enters the legacy form the DBT runtime reads (DBT refuses v3).

§cpu_profile_source: Option<usize>

Native CPUID source for host-no-rdrand, selected during admission from the caller’s original allowed CPU set, before container placement. The ptrace launch pins its actual tracer to this CPU. Never restored from recording metadata: host-profile recording/replay is refused.

§backend: BackendCapabilities

How the execution backend runs the guest, as the backend reports it through Reverie (reverie::Backend::capabilities).

Detcore reads facts about the backend only from here, never from the backend’s name, so a new backend is modelled correctly by reporting its capabilities. The host copies the running backend’s answer into this field before the run starts. The default, DEFAULT_BACKEND_CAPABILITIES, describes a ptrace-hosted guest, the backend Detcore’s own tests use, with the three host-set facts and reports_sigreturns off.

JSON that the guest can see is written by to_legacy_backend_json, which carries this field as the separate keys used before it existed; from_legacy_backend_json reads them back.

§guest_may_inherit_a_terminal: bool

The guest may start with a terminal: one of the launcher’s standard descriptors is a terminal, the launcher has a controlling terminal that the guest inherits with its session, or the launcher could not tell. Such a terminal makes Linux send signals at moments the host sets: SIGHUP and SIGCONT when it hangs up, SIGINT, SIGQUIT and SIGTSTP for its interrupt, quit and suspend characters, SIGWINCH when it is resized, and SIGTTIN and SIGTTOU for a background process group’s reads and writes. The guest makes no traced call that arms them, so where Detcore treats such signals as reaching the guest from the host (BackendCapabilities::host_timed_signals_are_physical) the scheduler records all eight as host-timed for every process before the guest’s first instruction, and no gated wait ends for them (https://github.com/rrnewton/hermit/issues/3146).

The host sets it while it prepares the backend configuration. It has no legacy key: to_legacy_backend_json leaves it out and from_legacy_backend_json reads it back as false.

§in_guest_detlog_forward_policy: Option<String>

The forwarding policy (detcore::detlog::ForwardPolicy::encode) every in-guest Tool must forward its DETLOG records with, on the socket Hermit passed it (hermit run --verify under SaBRe or in-guest LiteInst); None when no socket is passed.

The host sets it, not a flag, and every Tool image receives it in the configuration handshake on its coordinator connection, which guest code cannot change. A Tool image whose forwarder is missing, or forwards by another policy (guest code that ran first changed its private forwarding variables, so some records would be dropped before they are counted), then reports every forwarded-record count as UNCOUNTED (detcore::detlog::require_forwarding), so verification refuses the run instead of accepting a log without those records. Like guest_may_inherit_a_terminal, it has no legacy key.

§in_guest_site_patching_off: bool

Whether every in-guest Tool image must run with syscall site patching off and collect its exit statistics (hermit --backend=in-guest-trap).

The host sets it, not a flag, and every Tool image receives it in the configuration handshake on its coordinator connection, which guest code cannot change. The in-guest LiteInst runtime takes both settings from the guest environment, which guest code running before or during its installation could change, so once installation returns a Tool image compares the settings the runtime actually captured with this one and refuses to run the program when they differ (detcore::in_guest_site_patching). Like in_guest_detlog_forward_policy, it has no legacy key.

§in_guest_reserved_signals: u64

The signals an in-guest runtime keeps for itself, which a guest may not send to another process or arm as a notification signal: bit n - 1 for signal n, as Detcore’s other signal sets are kept.

Such a signal sent from one process to another would run the target’s runtime handler on a thread that does not hold the scheduler’s turn (A5 step 3c, design section 16.30, https://github.com/rrnewton/hermit/issues/4485). So Detcore answers a send of one of these signals to a process other than the caller’s own (kill, tkill, tgkill, rt_sigqueueinfo, rt_tgsigqueueinfo, pidfd_send_signal), and any arming of one (fcntl(F_SETSIG), timer_create, prctl(PR_SET_PDEATHSIG)), with EPERM and a WARN (Config::reserves_in_guest_signal). A send to the caller’s own process is unchanged. Empty (0), the default, changes nothing.

The host sets it, not a flag, when it prepares an in-guest run on the default route: SIGSYS, SIGSEGV while the runtime subscribes instructions, and SIGTRAP while LiteInst’s guard router may be installed: on --backend=liteinst, never with in_guest_site_patching_off (a liteinst image whose environment turns patching off has no router but keeps SIGTRAP reserved, a known over-refusal). Every other backend, and the in-guest loader route, leave it empty. Every Tool image receives it in the configuration handshake, which guest code cannot change. Like in_guest_site_patching_off, it has no legacy key.

§in_guest_refuses_host_timed_producers: bool

Whether Detcore refuses the guest calls that would let the kernel send a guest process a signal at a moment host timing decides (A5 step 3c, slice 0b; design sections 16.30, D28 and D28a, https://github.com/rrnewton/hermit/issues/4485).

While the in-guest runtime runs its own code, ordinary signals are blocked, and Linux keeps a blocked signal pending even under SIG_IGN, so such a signal could become pending at a host-timed moment whatever the guest’s action. So where this is set, Detcore answers with EPERM and a WARN the operation that completes such a producer: an owner for a socket or for a descriptor with O_ASYNC (F_SETOWN, F_SETOWN_EX, FIOSETOWN, SIOCSPGRP), O_ASYNC for a descriptor with an owner (F_SETFL, FIOASYNC), a lease (F_SETLEASE) and a directory notification (F_NOTIFY). It holds a parent-death signal it can send itself, as it does on ptrace, and refuses the run by name (pdeathsig-would-fire) if one would fire; it refuses with EPERM one it cannot hold. A SIGKILL parent-death signal keeps the kernel’s path. False, the default, changes nothing.

The host sets it, not a flag, when it prepares an in-guest run on the default route, where it also clears the physical RLIMIT_CPU soft limit and refuses an inherited descriptor that is already such a producer (D25). Every other backend, and the in-guest loader route, leave it false. Every Tool image receives it in the configuration handshake, which guest code cannot change. Like in_guest_site_patching_off, it has no legacy key.

§launch_image: Option<LaunchImage>

The guest’s first image, as its /proc/self/exe link names it, and the image the kernel exec’d in its place where a launcher loads the guest (LaunchImage). Detcore answers that link from it until the guest’s next exec, which Detcore resolves itself. None leaves the first image’s link to the kernel.

The host sets it, not a flag, from the program it launches. Like in_guest_detlog_forward_policy it has no legacy key, so DBT’s legacy form never carries it.

§inherited_seccomp: InheritedSeccomp

The seccomp state the guest inherits from the thread that starts it (InheritedSeccomp). The caller that starts the guest states it, as only the caller knows the filters its launch installs, such as those of a pre_exec callback; hermit run measures it. Not stated, it is unknown. Nothing reads it. Whether a guest may start under an inherited filter is decided by the hermit command, before it starts the guest, from its own reading of /proc/self/status (host_seccomp::admit). It has no legacy key: to_legacy_backend_json leaves it out and from_legacy_backend_json reads it back as unknown.

§epoch: DateTime<Utc>

Epoch of the logical time.

This is the datetime from which all time and date modtimes begin and monotonically increase. It is in RFC3339 format such as 2026-01-01T00:00:00Z. The stable default here is for library callers and wire-format fixtures; the hermit run and hermit oci run commands replace an omitted CLI default with one host wall-clock sample taken before backend dispatch.

A guest that checks TLS certificates over the host network (--network=host or --record-networking) checks them against this clock, so an epoch outside a server certificate’s validity fails the HTTPS connections to that server: curl exits 60 with “SSL certificate problem: certificate is not yet valid” (or “certificate has expired”), and a libcurl caller sees “SSL peer certificate or SSH remote key was not OK”. For such a run omit --epoch: hermit run then starts the clock at the current time and saves it in the run’s manifest, and hermit run --from last-run repeats the run with that epoch.

§seed: u64

Use this number to seed the PRNG randomness for both RNG and scheduler. This acts as a global fallback in case either sched_seed or rng-seed are not explicitly specified

§rng_seed: Option<u64>

Use this number to seed the PRNG that supplies randomness to the guest. This supplies guest system calls that expose randomness, as well as the /dev/[u]random files. It does not affect the rdrand instruction, which is disabled in the guest.

§fuzz_seed: Option<u64>

Seeds the PRNG which drives syscall response fuzzing (i.e. chaotically exercising syscall nondeterminism). Like other seeds, this is initialized from the --seed if not specifically provided.

§clock_multiplier: Option<f64>

Logical clock multiplier. Values above one make time appear to go faster within the sandbox.

§virtualize_metadata: bool

Disable substitution of virtual (deterministic) file metadata in lieu of the real metadata returned by stat/statx. This also preserves raw mountinfo device numbers so those interfaces continue to agree. Raw device values are host/filesystem observations and are not promised to reproduce across machines. Virtual metadata implies virtualize_time.

§mountinfo_root_rewrites: Vec<MountInfoRootRewrite>

Proven Hermit-owned mount roots to hide from /proc/*/mountinfo.

This is runtime provenance, not a user option. serde(default) keeps older serialized configurations compatible and makes backends which do not use the common container setup explicitly receive no rewrite claim.

§mountinfo_device_rewrites: Vec<(u64, u64)>

Backend-proven pairs of (mountinfo raw device, stat/statx raw device).

A backend may synthesize mountinfo independently from its pathname metadata implementation. These pairs state that the two raw numbers describe the same filesystem, so Detcore can feed both surfaces through one device identity. The pairs are runtime provenance, not a user option; an absent pair must never be inferred from numeric coincidence.

§mountinfo_mount_ids: Vec<u64>

Recording/container namespace mount IDs in canonical row order.

Detcore validates every /proc/*/mountinfo view against this order. It does not number mount IDs by position in it; see mount_id_assignment_order. It is runtime provenance rather than a user option; replay retains recording-time raw IDs because its read events contain recording-time kernel bytes.

§mountinfo_mount_ids_captured: bool

Whether mountinfo_mount_ids is an exact producer-owned snapshot.

The distinction matters for an empty mountinfo file: an absent snapshot asks Detcore to observe the completed guest namespace, while a captured empty snapshot must remain empty during replay.

§mountinfo_mount_namespace: Option<MountNamespaceIdentity>

The mount namespace mountinfo_mount_ids was captured in (MountNamespaceIdentity). A backend that checks its provenance (KVM) requires its own namespace to be this one, instead of recapturing the namespace’s rows: a host can detach a copied host mount from a private namespace at any time by removing that mount’s directory, so two captures of one namespace need not agree. None when nothing was captured, and in recordings. Runtime provenance, not a user option.

§mount_id_assignment_order: Vec<u64>

Raw mount IDs in the order Detcore numbered them for the guest.

Detcore numbers a raw mount ID when the guest first observes it through /proc/*/mountinfo or /proc/*/fdinfo/*; mountinfo_mount_ids only validates mountinfo views. A live run starts empty. Recording persists the completed order so replay gives every raw ID its recorded number rather than deriving one from its fresh namespace or launch descriptor shape.

§container_mount_table: Option<ContainerMountTable>

The guest’s container mount table, which Detcore renders as every spelling of /proc/<pid>/mountinfo and /proc/<pid>/mounts on every backend (crate::container_mounts, https://github.com/rrnewton/hermit/issues/4213). hermit-cli builds it once, in the completed container namespace before the guest starts, or, for --no-namespace and a library caller on KVM that built no container, in the namespace the guest runs in (its launch mounts and base mountpoints); a recording carries it, so its replay renders the recorded table. None (a library caller on a backend other than KVM, whose command may chroot or mount where Hermit cannot see, and every older configuration) leaves both files to the kernel, sanitized as before. Runtime provenance, not a user option.

§directory_placeholder: Option<PathBuf>

The guest path of the empty, read-only directory hermit-cli mounted in the guest’s container for Detcore’s placeholder directories where the guest’s procfs is not the kernel’s (KVM: the backend provides process signal control, procfs_inode::tool_can_name_guest_descriptors): a tmpfs at /proc/fs/nfsd, procfs’s own permanently empty mount point, which Detcore’s --proc level table hides from the guest at every level, and which the guest’s mount table leaves out. Each descriptor Detcore serves there for /proc itself or the caller’s own /proc/<pid>/fd is open on this directory, and Detcore answers every call through it from its model; an open, stat or statx of the guest’s that reaches the directory otherwise fails as /proc/fs does. None where the guest’s procfs is the kernel’s (ptrace, the in-guest backends: nothing is mounted, see Self::container_procfs), and where hermit-cli mounted none or a later mount covers it: --no-namespace, --namespace-only, record and replay, a user mount over the placeholder, every library caller, and every older configuration. On KVM, Detcore then serves no placeholder directory, and an open of /proc or a descriptor directory is refused (EACCES). Runtime provenance, not a user option.

§container_procfs: bool

Whether the guest runs in hermit-cli’s container, whose procfs mount at /proc is its own (every container hermit-cli runs a guest in, not --no-namespace, not a library caller, not an older configuration). Where the guest’s procfs is the kernel’s (ptrace), Detcore serves /proc itself and the caller’s own /proc/<pid>/fd then, each on a descriptor on that procfs’s root, and serves neither without it. Runtime provenance, not a user option.

§sequentialize_threads: bool

Sequentialize thread execution deterministically.

§runs_post_fork: RunsPostFork

Choose which side of an ordinary fork/clone runs first after the child is registered. Random choices are deterministic under --sched-seed.

§passthru_opt: bool

Use the optimized partial syscall subscription set instead of intercepting every syscall. This permits unlisted syscalls to bypass Detcore and therefore weakens deterministic accounting; leave it disabled for fail-closed execution.

§imprecise_timers: bool

In chaos mode, uses much cheaper approximate preemption timers. Only makes sense when recording preemptions for later (precise) replay.

§eager_lone_preemptions: bool

Stop the guest at every timeslice end, including one where no other guest thread could run. By default Hermit does not stop a thread that is the only one able to run before it next enters Detcore (every other thread waits on a futex without a timeout, on a child or in rt_sigsuspend; no timer, sleeper, poll deadline or host call is pending): it processes those timeslice ends when the thread next enters Detcore, at the same branch counts and in the same order, so the schedule, the virtual clock and the chaos draws are the same either way and only the stops are saved. This option turns that off, for comparison.

§signal_state_copy: bool

Turn off Detcore’s own copy of each guest thread’s signal dispositions and masks (A5, docs/SIGNAL_STATE_CHECK.md). The copy is on by default where it can run (ptrace with serialized threads): it is checked against the kernel, and decisions A5 converted read it in place of the kernel’s /proc view. With it off, those decisions read /proc, and no handler return is reported. A recorded schedule states the setting it ran under, and replaying it under the other setting is refused.

§signal_delivery_check_fatal: bool

Whether a signal delivery that the kernel contradicts, where Detcore’s copy and the kernel are both certain (A5 step 3.2), ends the run as an internal failure (HERMIT_INTERNAL_FAILURE class=signal-delivery-check) rather than being logged as a divergence that drops the copy. It is a Detcore defect either way. hermit run --strict sets it; nothing else does, and it changes nothing while the copy matches the kernel.

The host sets it. It has no legacy key: to_legacy_backend_json leaves it out and from_legacy_backend_json reads it back as false.

§chaos: bool

Schedule threads chaotically.

The behavior of this flag is subject to change. Current behavior is to randomize thread priorities at every logical timeslice. Other randomization strategies are possible with --sched-heuristic.

Thread scheduling remains deterministic, determined by the random seed.

§chaos_timeslice_range: Option<TimesliceRange>

Draw the mean of each chaos slice from MIN..MAX virtual nanoseconds (both included), log-uniformly, instead of using --max-timeslice as every slice’s mean, and cap every slice at MAX. Slices stay exponentially distributed around the drawn mean, so some fall below MIN. Races differ in the slice scale they need: some need a preemption in a short window, others a long uninterrupted run of one thread, and a seed sweep under one timeslice explores only one scale. Under a range every run mixes all the scales in it. The draws come from the scheduler seed’s chaos stream, so a seed reproduces them, and a preemption record pins every slice end as usual. Sets the run’s --max-timeslice to MAX: requires --chaos and PMU-backed preemption, and conflicts with an explicit --max-timeslice, with --target-timeslice and with hermit run --chaos-seeded-timeslice. A small MIN makes runs slower. Example: 1000..200000000.

§chaos_timeslice_draw: ChaosTimesliceDraw

How --chaos-timeslice-range draws. slice (the default) draws each slice’s mean from the range. run instead draws the run’s --max-timeslice once, log-uniformly from the range as a pure function of the scheduler seed, and the run is then an ordinary chaos run under it: a sweep’s seeds spread over the scales of the range, each seed at one scale. That reaches a race needing one scale throughout in more seeds, at a higher cost per run for the fine draws. The drawn value is printed in --summary-json (preemption.max_timeslice_ns) and stored in a --record-preemptions-to record, from which a replay takes it. Without an explicit range, run uses RECOMMENDED_CHAOS_TIMESLICE_RANGE; slice still requires a range.

§chaos_timeslice: Option<NonZeroU64>

The --max-timeslice this run drew under --chaos-timeslice-draw=run, or took from the preemption record it replays. hermit run sets it, and max_timeslice to the same value, before the run starts; the run’s own preemption record stores it. When set, no slice draws its mean from --chaos-timeslice-range.

§fuzz_futexes: bool

Uses the --fuzz-seed to generate randomness and fuzz nondeterminism in the futex semantics.

§chaos_target_races: bool

Targeted chaos: bias scheduling toward known concurrency race patterns instead of exploring interleavings uniformly. At the scheduler’s existing nondeterminism points it uses --fuzz-seed to (a) deliver a process-directed signal to a randomly chosen thread in the group (signal timing races) and (b) randomize the requeue position of a force-unblocked thread (lock-ordering / wakeup races). Only takes effect with --chaos; like the rest of chaos mode it remains reproducible under a fixed seed.

§chaos_per_thread_slowdown: bool

Reproducible per-thread slowdown factors for chaos mode. A factor greater than one makes each RCB consume proportionally more virtual time, while a factor below one makes it consume less. Thus scheduling deadlines and the guest-visible virtual clock describe the same slowed execution rather than applying an out-of-band scheduling bias. The factor is a pure function of scheduler seed, stable deterministic thread id, and chaos epoch. A fixed seed therefore reproduces both timing and interleavings.

§chaos_slowdown_max_factor: f64

Maximum ratio between the slowest and fastest per-thread slowdown factor for --chaos-per-thread-slowdown. Each thread’s factor is drawn log-uniformly from [1/R, R] where R is this value. Must fit the Q32 virtual-time representation and be >= 1.0; 1.0 disables the spread.

§chaos_epoch_length_ns: u64

Length of a deterministic slowdown epoch in elapsed per-thread logical nanoseconds. At the first scheduler commit at or after each boundary the factor is redrawn as factor(seed, stable_dettid, epoch). This is never wall time. 0 means one epoch for the entire run, making constant slowdown the single-epoch special case. Recorded preemption artifacts carry exact epoch transitions and factors for replay. Inert without chaos slowdown.

§record_preemptions: bool

Record the timing of preemption events for future replay or experimentation. This is only useful in chaos modes.

§strict_schedule_boundaries: bool

Record and replay the complete slice-boundary protocol used by strict trace verification. This mode refuses mismatches, extra observations, incomplete replay and legacy schedule files; it does not resynchronize. Ordinary recording/replay and schedule editing retain their legacy mode.

§record_preemptions_to: Option<PathBuf>

File to write the record of preemptions (in JSON). Implies --record-preemptions.

§replay_preemptions_from: Option<PathBuf>

JSON file to read recorded preemptions from. When --chaos mode is activated, these recorded preemption points take the place of randomized scheduling decisions.

§replay_schedule_from: Option<PathBuf>

File to read recorded schedule trace from. This execution will replay the schedule verbatim from the file.

§replay_exhausted_panic: bool

If we run out of events while replaying a schedule, treat that as a fatal event and panic, rather than continuing execution.

§die_on_desync: bool

When playing a schedule trace from disk, bail out on the first time we desynchronize from the event sequence specified in the trace.

§replay_edited_preemptions: bool

The preemption record --replay-preemptions-from reads is not the recording of this run’s schedule but an edited one, for example one hermit analyze knocked preemptions out of. A thread then can reach recorded slices that have already ended, which a faithful replay never does: the replay skips them and goes on with the first recorded slice still ahead, at its priority, instead of stopping the run. (At a thread’s start the record’s first priority, which the scheduler has already applied, holds until that slice ends.)

§replay_continue_fairly: bool

Once the schedule replayed from --replay-schedule-from runs out, order the threads queued in turn at each priority by the virtual time each has run since then, least first, and equal run times by least recent selection, instead of in queue order. A thread’s run time is what its own clock has advanced since that point; a thread seen for the first time, or runnable again after it was not, starts at no less than the least run time of the runnable threads. That is all it changes: a selected thread still runs until its slice ends, there is no preemption on wakeup, and threads pushed to the front of the queue (a timed wake) and pollers keep their places. Without it threads of equal priority take turns, so a thread that only computes or reads the clock keeps the CPU for a whole timeslice at each committing call of another. It reads nothing from the recording and draws nothing at random, so the rest of the run is as neutral as without it: what happens there depends only on the replayed prefix.

§stacktrace_event: Vec<(u64, Option<PathBuf>)>

Given schedule events traced on recording or replaying, print the stack trace at the moment after the Nth event in the trace. Optionally, provide an output file into which the stack trace will be printed, otherwise it goes to stderr. With a recorded or replayed schedule, N counts every traced event, polling retries and events the schedule does not hold included, as the desync and missed-stack-trace lines do; the event number a schedule release reports leaves polling retries out, so it is not such an index. Under --strict-schedule-boundaries, N is instead a position in the complete boundary stream, TimesliceEnd records included: a replay requires it to lie inside the stored stream, while a recording counts the stream as it writes it.

§stacktrace_signal: Option<SigWrapper>

Internal feature used to signal the guest with SIGINT at every --stacktrace-event, this is in-lieu of using hermit’s internal stacktrace printing facility, to instead have an external debugger handle it. Accepts either signal names or numbers.

§access_trace: Option<PathBuf>

Write an access trace to this path as the run records its schedule; its end line is written when the run ends, and a trace without it was cut short. The trace is JSON Lines with one record per syscall (its prehook and posthook positions in the recorded schedule, the thread, the thread’s syscall count, the arguments, the result, and the resources it used: descriptor slots and the open files behind them, file contents, pipes, sockets, futex words, memory ranges, timers, threads and processes), one per signal delivery (its code, fault address and sender), and the first 256 bytes of each write to fd 1 or 2. It records resource accesses beside the schedule for inspection and comparison. An observer: it adds no scheduler request and moves no virtual time, so the schedule and the guest’s results are those of a run without it, except that Hermit’s own command line, which a guest can read as PID 1’s, shows the option, and that the trace file itself is inside the container: it exists from before the guest’s first instruction and grows during the run, so a guest that lists or watches its directory sees it. Needs a recorded schedule (--record-preemptions-to or --record-preemptions), whose positions the records name, sequentialized threads and the ptrace backend. The format is detcore_model::access_trace.

§access_trace_from: u64

With --record-access-trace-to, leave out the records whose last schedule event comes before this position. 0, the default, keeps every record. Resource state from before the position, such as which open file a descriptor number names, is then only partly visible in the trace.

§access_trace_max_records: Option<u64>

With --record-access-trace-to, write at most this many records from --access-trace-from on. Past it the trace stops, without its end line, so a reader sees it cut short; a run whose records all fit still ends with it. Unlimited by default.

§access_trace_max_bytes: Option<u64>

With --record-access-trace-to, write at most this many bytes of header and records. The record that would pass it is not written: the trace stops there, without its end line, so a reader sees it cut short, and Hermit says so once on stderr. Defaults to 1073741824 (1 GiB, detcore_model::access_trace::ACCESS_TRACE_DEFAULT_MAX_BYTES), about three million records at their typical 350 bytes, so a long run cannot fill the disk by default; pass a larger count for a longer trace.

§preemption_stacktrace: bool

Deprecated: Print a stacktrace each time the program is preempted. Only makes sense in --chaos mode and typically goes with preemption recording/replaying.

§preemption_stacktrace_log_file: Option<PathBuf>

File to write preemption stacktraces to. Implies --preemption-stacktrace. If a log file is not specified, preemption stacktraces are printed to stderr by default.

§deterministic_io: bool

Enable deterministic IO by reassuring we always read/write the maximum possible bytes from IO syscalls. There might be cases that read/write syscalls return less bytes than requests. Detcore, makes an effort to request additional bytes until we reach the ones requested or EOF.

§panic_on_unsupported_syscalls: bool

Fail immediately on unsupported syscalls instead of forwarding them. Ordinary hermit run enables this policy; compatibility requires the explicit --allow-unsupported-syscalls opt-out.

§exit_on_unsupported_syscall: bool

Return a typed Tool error instead of unwinding through a backend callback.

§shutdown_on_unsupported_syscall: bool

Terminate the whole tracer when an unsupported syscall is observed.

§unsupported_syscall_report_fd: Option<i32>

Internal inherited file descriptor used to aggregate unsupported syscalls.

§panic_on_rcb_overshoot: bool

Panic when a precise PMU timer overshoots its expected RCB target instead of logging an error and continuing through normal timer handling. Intended for Detcore debugging.

§has_uts_namespace: bool

Internal: Set to true if we’re inside a UTS namespace.

§notice_host_network_abstract_binds: bool

Internal: Print a one-time notice on Hermit’s standard error when the guest binds an abstract AF_UNIX name, or fails to with EADDRINUSE. hermit run sets it for a run that asked for --network=host on the ptrace backend: the guest then shares the host’s network namespace, and with it the abstract names of every program on the host, other Hermit runs included, and Detcore runs in Hermit’s own process, so the notice reaches Hermit’s stderr and never the guest’s. Nothing the guest observes depends on it. The DBT backend’s runtime reads the frozen legacy form (to_legacy_backend_json), which leaves this field out.

§guest_ids: GuestIds

How the guest’s process and thread IDs are numbered (GuestIds). The host sets it, not a flag: hermit run from --no-namespace and --pid-base. Recorded schedules store it, and a replay under another numbering is refused.

§standard_stream_aliases: Option<[u8; 3]>

Internal: For each of the guest’s standard streams 0, 1 and 2, the lowest of them that is one open file description with it, as kcmp(KCMP_FILE) answered for the descriptors the launcher hands the guest (Hermit’s KVM launch, where the guest’s output is not captured: the stdin it reserved, and its own standard output and error, which the executor passes through). None where that is not known (any other launch, a captured or replaced stream, or a kernel that refuses kcmp): each stream is then a description of its own. Detcore’s lock ledger takes the streams of one group as the one description they are (package K slice K8-h). The backend’s own answer, a provider query naming which guest descriptors are one host description, would also cover descriptors no launcher hands over; no backend offers one yet. The DBT backend’s runtime reads the frozen legacy form (to_legacy_backend_json), which leaves this field out.

§replay_data: Option<PathBuf>

Internal: Path to the replay data folder.

§kill_daemons: bool

Kill all remaining tasks iff daemons are the only ones left. Disabled by default.

§gdbserver: bool

Serve the guest to one gdb client on 127.0.0.1:--gdbserver-port, and wait for it before the guest runs; attach with gdb -ex 'target remote 127.0.0.1:PORT' PROGRAM. The port is bound in the host’s network namespace, so the guest keeps the network --network gives it, and a --strict run can be debugged with every strict refusal in force. The debugger is an input of the run: breakpoints, writes to the guest’s memory or registers and the signals it sends all change it. With a gdbserver, Detcore also takes no reports of the guest’s signal-handler returns, so a multithreaded guest whose handlers take scheduler turns can be scheduled differently than without one (docs/SIGNAL_STATE_CHECK.md). Only the ptrace backend (the default, and --backend=e9patch, whose rewritten guest runs under it) serves gdb: --backend=kvm, dbt, sabre, liteinst and in-guest-trap, and --namespace-only, refuse --gdbserver and --dap-listen.

§gdbserver_port: u16

The loopback TCP port --gdbserver serves on; 0 lets the system pick a free one, which the run prints.

§max_timeslice: MaybeTimeslice

Configure the maximum time a guest thread may run without returning to Detcore. This is measured in virtual nanoseconds and enforced with retired conditional branch (RCB) counting. --preemption-timeout is retained as a deprecated alias.

Set this to disabled or 0 to disable PMU-backed preemption. Positive values must be at least one RCB (10 virtual nanoseconds at the default clock multiplier) and require user-space hardware performance counters.

Small values are expensive. A thread that computes without returning to Detcore is stopped by a PMU timer event at the end of every timeslice, and on the ptrace backend a precise timer (the default) is placed by stepping the guest through up to the last skid margin of the slice: 100 to 10000 RCBs depending on the processor, or the --skid-margin override. A slice no longer than the margin is stepped through whole. A CPU-bound guest can run thousands of times slower than at the default (a pipeline test took 0.3 s at the default and 994 s at 1000), and a --timeout that expires may mean a slow run rather than a hung one. hermit run, hermit analyze and hermit bisect say so on stderr when a slice is at most ten skid margins long, so that at least a tenth of it is stepped (1000000 virtual nanoseconds at the default clock multiplier on a processor with a 10000-RCB margin); a preemption replay, whose recording sets the slices, and --imprecise-timers, which steps nothing, say nothing. --summary reports how many timeslices the run had.

§target_timeslice: Option<NonZeroU64>

Target logical timeslice, in virtual nanoseconds, checked at syscall boundaries and the other points where the guest returns control to Detcore: signals, timer events, and trapped rdtsc and cpuid instructions unless --target-timeslice-syscalls-only is given. This avoids PMU preemption for workloads that enter the kernel frequently. Omit this option to use only --max-timeslice.

§target_timeslice_syscalls_only: bool

Do not end an expired --target-timeslice at a trapped rdtsc or cpuid while a PMU maximum (--max-timeslice) is armed; end it at the next syscall, signal or timer event, or at the PMU maximum. A trapped instruction can sit inside a user-space spinlock: QEMU’s multi-threaded TCG reads the host TSC while holding its vm_clock_lock, and a vCPU that yields there leaves the other vCPUs spinning for whole PMU slices. Has no effect without --target-timeslice, or with --max-timeslice disabled, where the trap is the only way out of a busy-wait on the TSC.

§futex_wake_yields: bool

After a FUTEX_WAKE or FUTEX_WAKE_BITSET that woke at least one waiter, move the waker to the back of its priority band and have it yield, so that woken threads of its priority run before it continues. Without it, a thread that releases a contended lock keeps running until its slice ends and can re-take the lock many times before the waiter is scheduled: QEMU’s multi-threaded TCG vCPUs starve its main loop of the big QEMU lock this way. The yield is a scheduler turn of its own: the waker’s timeslice keeps its deadlines. Each extra thread switch is charged scheduler time that the guest can observe (see --scheduler-turn-cost), and costs wall time: a two-vCPU QEMU boot took 5% to 48% longer with it. The waker keeps its priority, so a woken thread of a lower priority still runs after it; --chaos redraws threads’ priorities from their chaos PRNG, which can put a woken thread in a lower band; and a random --sched-heuristic does not select first in, first out. In those cases a woken thread is not guaranteed to run first. Applies to the precise futex mode while threads are sequentialized, on the ptrace backend (including e9patch preprocessing, which runs on it); replay applies it as the recorded run did.

§pipe_wake_latency: Option<u64>

Hand the turn to a thread polling a pipe or FIFO once another thread’s action has readied it (https://github.com/rrnewton/hermit/issues/4380), within this many virtual nanoseconds of the acting thread’s own time. A write that moves bytes into a scheduler-managed pipe, a read that makes room in one, an explicit close of one end, or an open of a FIFO end readies the threads polling for that: the scheduler restores their priority, and once the acting thread’s time is this far past its first readying action, at the next point where it returns to Detcore (a syscall’s entry or exit, or a signal or trapped instruction), it is moved behind them and yields, so they run before it continues. A poller is restored to its own priority and the acting thread moves only within its band, so where --chaos has drawn a poller a lower priority than the acting thread, that poller still runs after it and is not guaranteed to run first. 0 hands off at the end of the readying syscall. Unset (the default), nothing changes: a polled thread whose peer is ready waits for the acting thread’s slice to end, as before. Each hand-off adds at least two charged scheduler turns that the guest can observe as time (see --scheduler-turn-cost). A thread that computes after its write without returning to Detcore delays the hand-off until it next does, or its slice ends; an implicit close (an exit, an O_CLOEXEC exec) readies nothing; and an end reopened by path (/proc/self/fd/N, as /dev/fd/N process substitution does) is a channel of its own, so the other side’s actions do not ready it. Recorded schedules store the value, and a replay under another value is refused. Refused without sequentialized threads, on the DBT, KVM and LiteInst backends, with --namespace-only, --strace-only or --debug-externalize-sockets, and under a --sched-heuristic that does not select by priority; never applied in record mode.

§expired_wait_charge: Option<ExpiredWaitCharge>

How a run of consecutive scheduler turns that each end an expired timed wait (a futex wait answered ETIMEDOUT, or a sleep already due) is charged while another thread is queued: once, one scheduler turn for the whole run, or each, a turn per wait. Unset, each under --chaos or a --sched-heuristic that does not select by priority, where the time each charge adds stretches short waits as race search relies on, and once otherwise, so that a thread polling with waits shorter than a turn charge blocks and lets other threads run. A replay of a schedule or of preemptions that leaves this unset takes the value its record stores (a record that stores none, written before the option existed or by an each run, charged each wait), and an explicit value that disagrees with the record is refused. hermit analyze and hermit bisect run every trial under the value of the recording they start from, or each when analyze records its own chaos target. Under hermit record and hermit replay every wait is charged, whatever the value.

§work_span_report: Option<PathBuf>

Write a work/span report of the run’s schedule to this path as JSON when the run ends normally: work (the sum of every thread’s guest CPU time, in virtual nanoseconds), a lower span over the scheduler’s certain happens-before edges (program order, spawn, a child’s exit to the wait that reaps it, conflicting resources), and an upper span that also orders a thread that waited after everything other threads did meanwhile. The report lists the dependencies it does not model: what a wait waited for and who sent a signal, so the lower span can be optimistic; and what passes without a wait (data, an end of file or a peer’s close found on a channel, a pending signal taken by sigtimedwait, shared memory, files and devices), which neither span orders; and the CPU time of a call a thread was running outside the schedule when it was killed. An observer: no scheduling decision reads it, so the schedule and the guest’s results are those of a run without it, except that Hermit’s own command line, which a guest can read as PID 1’s, shows the option. Needs sequentialized threads and the ptrace backend. Unset (the default), nothing is gathered.

§scheduler_turn_cost: Option<NonZeroU64>

Virtual nanoseconds that each committed scheduler turn adds to the global clock, before --clock-multiplier (default 500000). The charge keeps time moving while threads take turns without running. Every thread observes it as a jump in time across a thread switch, so a guest that times short intervals while another thread runs, such as a QEMU guest kernel calibrating its TSC against the emulated PIT, can see a gap far larger than any work done. A smaller charge makes those jumps smaller; a finite poll or futex timeout then takes more turns to expire. The charge, after the multiplier, must be between 1 and 1000000000. If a charged turn would pass the end of representable virtual time, the run stops with HERMIT_VIRTUAL_CLOCK_EXHAUSTED and exit status 125.

§cap_preemption_charge: bool

Charge a scheduler turn that ends a timeslice because its time ran out (a preemption) at most the virtual time its thread ran since its previous turn, instead of the full turn charge (--scheduler-turn-cost, default 500000 virtual nanoseconds). Without it, every preemption adds the full charge however short the slice was, so a small --max-timeslice, or a short --chaos draw, multiplies the guest-visible time of CPU-bound work by about 1 + charge / slice: 501 times at --max-timeslice=1000, enough for a test’s own timeouts to expire before it reaches the code under test. With it the factor is at most 2, what a slice one full charge long already costs. A preemption whose thread ran at least one full charge since its previous turn is charged as before; a thread’s turns include its syscalls, so one that follows a syscall by less is charged only the time since that syscall, however long the slice. A capped turn is charged at least one virtual nanosecond, unless its full charge after --clock-multiplier is zero. An explicit sched_yield, and every turn that does not end a timeslice, keep the full charge. This changes what the guest reads from clock_gettime(CLOCK_MONOTONIC) and the other virtual clocks, and so when its timers and timeouts expire: recorded schedules store the setting, and a replay under the other is refused. Refused where no timeslice ends by expiry (--max-timeslice=disabled without --target-timeslice) or no Detcore scheduler orders the threads (--namespace-only, --strace-only, --no-sequentialize-threads), and with the DBT backend; never applied in record mode.

§virtual_timeout: Option<NonZeroU64>

End the run in virtual time: once the run’s virtual clock is more than this many virtual nanoseconds past the run’s start, Hermit grants no further scheduler turn and the run ends with exit status 124 and the stderr line HERMIT_RUN_TIMEOUT class=virtual-timeout bound_ns=N. The clock is Detcore’s global virtual time since the run began, the same virtual time --summary reports as elapsed (virttime_elapsed in --summary-json); it is checked each time the scheduler commits it at the start of a turn, before the turn’s thread runs, and the check never moves it. A guest that has already exited, or whose remaining processes a committed exit, kill, in-flight exec or fatal signal has marked doomed, is not stopped by it. A failed exec clears its in-flight mark before the old image resumes. Process-group SIGKILL marks are conservative: if a marked process survives a failed group kill, the bound does not stop it. Unlike --timeout, a wall-clock bound in seconds that fires wherever the guest has got to when the host’s clock runs out (class=run-timeout), for a guest whose input all comes from inside the container this bound fires at the same point of the same schedule on every host and in every run, so the output written before it, --summary and a --verify comparison are reproducible. A stopped run is not a guest result, so --verify compares it only under --verify-allow=failure or both; the default success refuses run 1, as it refuses a deadlock under Hermit’s model. A thread that polls something outside the container, such as a pipe a host process feeds, advances virtual time with each retry, and the number of retries depends on the host, so such a run can stop at another turn; --verify --verify-strict reports that as a divergence. Virtual time does not pass while every thread is blocked in a call outside the container, so bound such a wait with --timeout. On the ptrace backend the run is then finished as for a guest that exited: its output is kept and --summary says the bound fired. On the kvm backend the run exits 124 without a summary, and --verify with the bound is refused there. Needs sequentialized threads and virtual time: refused with --no-sequentialize-threads, --namespace-only, --strace-only or --no-virtualize-time, and on the dbt, liteinst, in-guest-trap and sabre backends, where it has not been qualified. Also refused before guest or debugger startup with --gdbserver or --dap-listen: a debugger can suppress a fatal signal after Detcore marks its process doomed, leaving a survivor outside the bound. Remove the debugger option or the virtual bound, or use --timeout for a wall-clock bound instead.

§sigint_instakill: bool

Shut down immediately upon SIGINT, rather than letting the guest handle it.

§warn_non_zero_binds: bool

Warn if binds are non-zero.

§sched_heuristic: SchedHeuristic

Apply a specialized scheduling heuristic which may help exercise certain bugs.

§sched_seed: Option<u64>

Use this number to seed the PRNG that supplies randomness to the scheduler.

§network_trace: NetworkTraceConfig

External network record or replay, set by hermit run --record-networking or --replay-networking; Off otherwise, in which case Detcore never consults it. Its perturbation seed has no fallback to seed or sched_seed.

§sched_sticky_random_param: f64

Configure the probability for the Sticky Random scheduler to stay in a thread. For value 0.0, we are behaving like Random. For value 1.0, we are behaving like a DFS, where the same thread is always picked as long as it is available in the Run queue. After this thread is exhausted, the next thread will be chosen randomly. For value 0.5, we have a 50/50 chance to pick the same thread.

§recordreplay_modes: bool

Internal: An internal flag for indicating to Detcore whether we are in hermit record or hermit replay mode. This is necessary because there are DIFFERENT global invariants in record mode (e.g. files dont exist). If we move to a chroot model and reproduce more, recording less, then this flag should become obsolete.

§replaying: bool

Internal: Set only by hermit replay, alongside recordreplay_modes. Replay serves socket reads, writes, accepts and connects, and poll, ppoll, select and pselect6, from the recording, so they cannot block. They still run as backgrounded blocking I/O, as during recording, but Detcore’s scheduler commits no other turn until they finish. Otherwise the descriptor-table changes of different threads could interleave differently from one replay to the next.

It never enters the legacy form (to_legacy_backend_json), so a standalone DBT run’s HERMIT_DBT_DETCONFIG reads it as false. Record and replay run only on the ptrace backend.

§stop_after_turn: Option<u64>

Internal: debugging option to stop execution after a specific scheduler commit, aka turn number (non-negative integer). This only makes sense if --sequentialize-threads is specified, as the scheduler is otherwise not engaged.

§stop_after_iter: Option<u64>

Internal: debugging option to stop execution after a scheduler loop iteration (non-negative integer). This only makes sense if --sequentialize-threads is specified, as the scheduler is otherwise not engaged.

§signal_at: Option<SignalAt>

Send SIGNAL to the run’s root process once the scheduler has committed turn N, as a timer expiry is sent (turn=N:SIGNAL, SIGNAL a name such as SIGUSR1 or a number, not SIGKILL or SIGSTOP). It is sent before the next turn is selected, after the first COMMIT turn M with M >= N: turn numbers also count the turns the scheduler skips, so if turn N was skipped, after the next commit. The turn is a deterministic point of the run, so a process in the run that waits for the signal acts at the same point every time: for example a controller that stops QEMU and saves a snapshot there. The run itself goes on. Only with --sequentialize-threads, where the scheduler numbers turns.

§debug_externalize_sockets: bool

Internal: Debugging option to treat all sockets as mysterious external, nondeterministic entities, rather than container-internal and determinstically scheduled.

§debug_futex_mode: BlockingMode

Internal: Debugging option to change how futexes are implemented, either precisely modeled by hermit, by polling the kernel with non-blocking futex operations, or treated as external (nondeterministic) operations which unblock at imprecise times.

§no_rcb_time: bool

Do not count the retired conditional branches (RCBs) of each thread towards its logical time. Instead, count each checkin with the scheduler as a fixed increment to logical time. Even when this option is set, HW RCB performance counters may still be enabled if a max-timeslice is specified.

§detlog_heap: bool

An option to enable logging the hash of heap memory maps for the purpose of determinism checking

§detlog_stack: bool

An option to enable logging the hash of stack memory maps for the purpose of determinism checking

THIS HASH COVERS argv AND THE ENVIRONMENT, which the kernel places at the top of the initial process stack. Two runs whose command lines differ by a single character therefore produce different stack hashes from the first sample, even when the command lines are the same LENGTH and every stack address matches. Measured: equal-length-but-different argv diverged the hash 14 records in, while byte-identical argv held it for 5023 records.

Holding a run-directory name to a fixed WIDTH is a sufficient control when only addresses matter, and is NOT sufficient here. Comparing two runs under this flag requires byte-identical argv and environment; otherwise the first divergence you find is your own input.

§detlog_anon: Option<DetlogAnon>

Log a hash of every private, writable anonymous mapping at each syscall, for memory determinism checking: allocator arenas (scudo’s, jemalloc’s, glibc’s mmap chunks), thread stacks and TLS blocks, none of which --detlog-heap (the brk heap) or --detlog-stack (the main thread’s stack) covers. A mapping named by PR_SET_VMA_ANON_NAME ([anon:<name>]) counts as anonymous. --detlog-anon=pages adds a short digest for each 4 KiB page that is not all zero, to find the page where two runs part.

ptrace backend only (also with e9patch preprocessing): the mappings come from the guest task’s own /proc/<tid>/maps, which an in-guest tool shares and a VMM’s does not hold. Other backends refuse the flag. EXPENSIVE: every byte of every such mapping is read at every syscall, in 1 MiB pieces, so a guest with a large heap pays for its whole size each time; a mapping over 256 MiB (a sanitizer’s shadow, a heap reserved up front) is recorded by its size alone. Reading an untouched page maps the shared zero page there, which mincore then reports resident, as with --detlog-heap and --detlog-stack. A thread stack holds thread IDs and, below its stack pointer, the scratch Hermit writes when it injects a call, so runs whose IDs differ differ there legitimately. Page indices count from the mapping’s start, so a mapping that merges or moves renumbers its pages.

§detlog_regs: bool

Log a hash of the guest REGISTER FILE at guest-logical-control points, for determinism checking. stdout, the INFO log, the stack and the heap are all hashed today; the register file is not, so two backends can differ in register state and every existing check still reports parity.

SAMPLED ONLY AT GUEST-LOGICAL-CONTROL POINTS – see Detcore::detlog_registers. Registers are NOT sampled inside a tool handler: a backend running its handler in-guest executes code the ptrace reference never executes, so a difference there is correct behaviour, not a determinism bug.

§detlog_io_buffers: bool

Log a hash of each syscall’s OUTPUT BUFFER, taken at the syscall boundary from the address and length in the syscall’s own arguments.

WHAT IT SEES THAT THE MAPPING HASHES DO NOT. --detlog-heap and --detlog-stack hash a whole named mapping, so their coverage is decided by where the guest happened to ALLOCATE a buffer. Measured, three runs per cell, same netlink exchange with only the receive buffer’s home changed: a [stack] buffer is missed by --detlog-heap, a [heap] buffer is missed by --detlog-stack, and a BSS/static or anonymous-mmap buffer is missed by BOTH even with both enabled. Anonymous mmap is where glibc puts any malloc above the 128 KiB M_MMAP_THRESHOLD. Reading the extent out of the syscall arguments makes the buffer’s home irrelevant.

WHY IT IS NOT REDUNDANT WITH --verify. A syscall whose buffer is a bare pointer in Reverie prints the ADDRESS, not the contents, so a recvmsg returning a stable Ok(1468) whose payload varies produces a character-identical record and --verify reports bitwise_parity: true. 44.1% of the syscalls in a QEMU/Linux boot move bytes through such a buffer.

COST is proportional to bytes actually moved, NOT to syscall count or mapping size: ~0.75 s per GB of guest I/O. A QEMU/Linux boot moves 139.1 MB through these buffers, against the 10.9 TB --detlog-heap hashes over the same run.

NAME IS PROVISIONAL: io-buffers is the owner’s candidate and is not settled.

ON BY DEFAULT. It was opt-in until 2026-08-24, and opt-in made the determinism gate weaker than its name: with the hash absent, the netlink recvmsg above compares equal and --verify reports success. A check that must be requested is not a standard. The opt-out exists for the deliberate case (bulk I/O where the cost matters and content parity is not the question), not as the ordinary setting.

COST OF THE DEFAULT, measured 2026-08-24 on a 316-core x86_64 Linux build host: a typical small test guest pays about ONE MILLISECOND (/bin/true 0.029s -> 0.030s, /bin/ls 0.041s -> 0.041s, 8 runs each). 64 MiB through cat costs +0.07-0.10s in a RELEASE build, which is the ~1.1-1.6 s/GB matching the figure quoted above. The same workload in a DEBUG build costs +3.4s, roughly 50x more, because the hash loop is unoptimized – so a debug-built node moving tens of megabytes is the one place the default is felt.

§detlog_regs_cadence: u64

Sampling cadence for --detlog-regs: hash every Nth guest-logical-control point.

COST TIER. 1 (the default) is the FULL tier – every control point hashed – and is what a short test should use. Measured cost at this scale is within run-to-run noise: /bin/true (49 control points), wc -l /etc/passwd (135) and a 5-iteration shell loop (195) were 0.04-0.07s with the flag on and the same with it off. A larger N is the SPOT-CHECK tier for runs where full hashing is too expensive; it trades detection latency for cost, since a divergence is only seen at the next sampled point. Every emitted line records the tier it was produced under, so a cell can state which tier it met instead of leaving it implicit.

§sysinfo_uptime_offset: u64

Configure a time offset (in seconds) between a container OS considered booted and a guest is executed This primarily affects ‘sysinfo’ syscall’s ‘uptime’ field reporting

§memory: u64

Configure memory available for the container. Takes a number of bytes, or shorthand (e.g. “1GB”). Right now this doesn’t enforce an upper bound, but does affect the amount of memory reported to the guest.

§virtual_cpus: Option<NonZeroU32>

Present a machine with this many CPUs, 1 to 128, so that nproc, sysconf(_SC_NPROCESSORS_ONLN/CONF) and thread pools size themselves to it. Threads still run one at a time. The affinity mask, getcpu, CPUID’s APIC IDs, /proc/cpuinfo, /proc/stat, a task’s Cpus_allowed and /sys/devices/system/cpu (its CPU lists, cpuN directories, topology and cache files) all describe the same N single-core sockets on one NUMA node. sched_setaffinity follows Linux: a mask with none of the N CPUs is EINVAL. The host must list at least N CPUs under /sys/devices/system/cpu. Without this flag the guest sees Hermit’s historical single CPU, whose sched_setaffinity accepts any mask.

§proc_level: ProcLevel

How much of /proc the guest sees. Every level is the same on every backend and host. minimal (the default) shows a small set, modelled on gVisor’s; standard shows every system-wide name Detcore serves or plans to serve. A system-wide or /proc/sys name outside the chosen level does not exist: lookups give ENOENT and listings leave it out. So does a name in a process’s or a thread’s directory, except a few that Hermit still leaves to the kernel (mem, uid_map, gid_map, setgroups), as are whether a process exists and the entries of its fd, fdinfo, ns and net. A spelling through a symbolic link or .. is checked only when it opens a file.

§interrupt_at: Vec<(DetTid, u64)>

Configure extra interrupt points based on thread id and rcb counter. Detcore will raise a precise timer for this RCB whenever it detects that current current thread timeslice intercects any of the interrupt points specified

§happens_before: Option<HappensBeforeProgram>

Resolved happens-before program: deterministic ordering edges between anchored events (see detcore_model::happens_before). This is populated programmatically by hermit-cli after loading and resolving a --happens-before spec against the guest binary; it is not a direct CLI flag and is not serialized (it is reconstructed from the spec file each run, so #[serde(skip)] avoids requiring serde on Sysno-bearing positions and keeps save-config output stable). The scheduler enforces these edges only when sequentialize_threads is set.

§record_host_inputs: bool

Whether Detcore records the host identity of each file the guest opens, sending each record to the global state, which writes the run’s records to Self::host_input_log when the run ends (see crate::host_input). hermit run --verify sets it, so that a divergence caused by a host file replaced during a run can be named. The records are never part of the compared log. Serialized, so that it reaches the Detcore tool on every backend, including one that runs inside the guest and receives this Config over RPC; never a CLI flag.

§host_input_log: Option<PathBuf>

Where the global state writes the run’s host-input records, one crate::host_input::HostInputRecord JSON line each and a crate::host_input::HostInputLogEnd line, when the run ends. hermit run --verify sets a private file. A host path, read only by the global state, which every backend that hosts it builds from this Config in-process; so set programmatically, like happens_before, and never serialized.

§host_input_snapshots: Vec<HostInputSnapshot>

Captured inputs that the launcher copied into private container files. Only the host global state consumes these identities, just like host_input_log; guest-side tools still report the actual open’s stat. Never serialized: every backend constructs that global state from this in-process config. Physical identities remain necessary for deferred content checks even when records publish the captured input’s origin.

§untraced_code_range: Option<(u64, u64)>

A guest address range, [start, end), holding code whose syscalls the backend lets through without Detcore seeing them, which the guest cannot otherwise use without faulting. With Self::record_host_inputs set, a guest call that may change the memory there (a fixed mapping over it, a protection or advice change or unmapping that covers it, an open of a process-memory file for writing) is reported as a change at /, so no host input change is named in that run (see crate::host_input). The backend that hosts Detcore in-process sets it, so set programmatically, like happens_before, and never serialized.

§fatal_core_capture: Option<FatalCoreCapture>

Opt-in capture of a core file for a guest thread killed by a signal whose default action dumps core; None, the default, writes nothing. A host path and host-side limits, read only by the global state at a fatal exit stop, so set programmatically, like host_input_log, and never serialized.

§in_guest_signal_delivery: bool

Whether the in-guest runtime delivers the guest’s signals through Detcore’s schedule (A5 step 3c.1, gate D35 of the design, https://github.com/rrnewton/hermit/issues/4485): while its code runs it blocks every signal it does not reserve, and at each return to guest code it predicts the kernel’s deliveries, reports them in two phases, and makes a predicted death a scheduled one. Detcore answers Reverie’s Tool::in_guest_signal_delivery from it.

The host sets it, not a flag, when it prepares an in-guest run on the default route, and only where every condition of the gate holds: site patching off, sequentialized threads, no configuration in which the two-phase protocol cannot be kept (detcore::two_phase_refusal), and a scheduler that runs as the init of the guest’s PID namespace, which only hermit run’s container launch knows. Preparing any run clears it first, so a caller’s configuration cannot carry it in; the in-guest loader route never sets it. Every Tool image receives it in the configuration handshake, which guest code cannot change. False, the default, changes nothing. Like in_guest_reserved_signals, it has no legacy key.

§annotated_priority_replay: bool

Whether --replay-preemptions-from names a record that carries callback checkpoints, so priority-history replay ends each annotated row at its recorded callback endpoint instead of at the first stop that reaches the row’s RCB count (https://github.com/rrnewton/hermit/issues/4082).

The host sets it, not a flag, from the validated record before the scheduler or any Tool reads the configuration, and refuses a configuration it does not qualify for such a record (preemption_admission::refuse_unqualified_annotated_replay). Preparing any run sets it from the record, so a caller’s configuration cannot carry it in; Detcore refuses a record whose checkpoints disagree with it. A record so annotated was made with --record-preemptions, so the replay observes schedule events as its recording did (observes_schedevents). False, the default, changes nothing. Like in_guest_signal_delivery, it has no legacy key.

Implementations§

Source§

impl Config

Source

pub fn virtual_cpu_count(&self) -> u32

How many CPUs the guest sees: --virtual-cpus, or Hermit’s historical one.

Source

pub fn models_signal_targets(&self) -> bool

Whether the scheduler models which thread the kernel gives a signal, from the signal masks it reads from the kernel, and keeps the per-process ledger of signals discarded at send time; the guest side publishes a waiting thread’s mask and records handler-restored real-time signals for it (publish_wait_mask, record_handler_restore_mask). It needs serialized threads, so that a mask it reads cannot change before the kernel acts on it, and a backend whose kernel signal targets a tool can predict (BackendCapabilities::kernel_signal_targets_are_predictable).

Source

pub fn reserves_in_guest_signal(&self, signal: i64) -> bool

Whether signal is one of Config::in_guest_reserved_signals. Never signal 0 (an existence check sends nothing), nor a number outside 1 to 64, which Linux refuses with EINVAL before any target is named. Always false while the set is empty, which it is on every backend but the in-guest ones’ default route.

Source

pub fn with_backend(self, change: impl FnOnce(&mut BackendCapabilities)) -> Self

This configuration with change applied to its backend capabilities. [BackendCapabilities] cannot be built field by field outside Reverie, so a caller that needs to adjust individual facts starts from the value already here.

Source

pub fn has_default_epoch(&self) -> bool

Whether the epoch is the stable library default omitted by Display.

Source

pub fn capture_epoch_from_host_time(&mut self, now: SystemTime)

Replace the stable library/test default with the host wall clock captured by the outer hermit run invocation. The caller owns the single host-clock read boundary; all guest clock and metadata observations consume the resulting concrete epoch.

Source

pub fn largest_nanos_per_rcb(&self) -> f64

Virtual nanoseconds one RCB takes at this clock multiplier and, under a chaos per-thread slowdown, at its largest factor: the most any thread’s RCB takes, so a timeslice of n virtual nanoseconds is at least n / largest_nanos_per_rcb() RCBs for every thread.

The two multipliers are combined first and then applied to NANOS_PER_RCB, the order of the one-RCB PMU epsilon that Detcore’s post-hook compares with the end of the maximum (post_handler_hook_observed and callback_checkpoint_expiry_due in detcore/src/lib.rs), which Self::minimum_max_timeslice_nanos bounds. Floating-point multiplication is not associative: at a clock multiplier of 2.5 and a largest factor of 4.4, (10 * 2.5) * 4.4 is one unit in the last place above 110, which would raise that minimum to 111.

Source

pub fn minimum_max_timeslice_nanos(&self) -> u64

Smallest PMU-backed maximum representable by one RCB at this clock multiplier.

Source

pub fn validate_invariants(&self)

Check invariants that must hold at every execution boundary without mutating the config.

Source

pub fn validate(&mut self)

Sanity check the flags, and update any wherever flag B is implied by A.

Source

pub fn use_preemption_timer(&self) -> bool

Whether configured preemption can use this backend’s timer mechanism.

This is independent of RCB accounting and does not certify a clock.

Source

pub fn replays_lone_preemptions(&self) -> bool

Whether a thread that is the only one able to run may skip its timeslice-end stops and have them processed when it next enters Detcore (see Config::eager_lone_preemptions). Only where a timeslice end reads nothing from the guest but its branch count, and nothing but the thread’s next entry could act before the next one: precise PMU timers keyed to retired branches at one virtual-time rate, no recorded or replayed schedule or preemptions (they capture guest state at each end), no slice-boundary protocol, no stack traces at preemptions or events, no turn-numbered triggers (--stop-after-turn, --stop-after-iter, --signal-at), no happens-before program, no manual interrupt points and no syscall-boundary deadline (--target-timeslice). Never with a gdbserver either: a debugger is served at the stops, and between skipped ends it would see Detcore’s slice bookkeeping lag the guest’s program counter.

Source

pub fn use_rcb_time(&self) -> bool

Should we use RCB in computing logical time?

The answer is NO either if --no-rcb-time is specified or if HW counters are disabled by setting --max-timeslice=disabled.

Source

pub fn yields_after_futex_wake(&self, woken: u64) -> bool

Whether a FUTEX_WAKE that woke woken waiters makes the waker yield to them (--futex-wake-yields).

A thread that releases a contended lock usually keeps running: the waiter it woke is queued behind it, and the waker can re-take the lock, uncontended, many times before that waiter runs. glibc and Rust mutexes both let a releasing thread barge back in, and on real hardware the woken thread wins on another CPU within the release window. Under sequentialized threads it never gets one, so QEMU’s multi-threaded TCG vCPUs starved its main loop of the big QEMU lock for whole PMU slices at a time (https://github.com/rrnewton/hermit/issues/3874). When this holds, the scheduler moves the waker to the back of its priority band, and the waker takes a yield turn at the syscall’s post-hook, so woken threads of its priority run before it continues (it keeps its band; --chaos can redraw priorities, and a random heuristic does not select first in, first out). The yield leaves the waker’s timeslice alone.

A thread switch is not free in virtual time: every scheduler decision is charged, so a policy that switches more often moves time that the guest observes. A QEMU guest kernel that calibrates its TSC against the emulated PIT failed that calibration with this policy, because the main loop now ran in the middle of it.

The decision reads only the configuration and the wake’s result, the number of waiters the scheduler took off the futex in the waker’s turn, which is already deterministic. A wake that woke no one keeps the slice. Replay applies the policy exactly as the recorded run did: a preemption record holds slice ends but not this queue order, so the requeue and the yield must happen again for the replayed run to reach the same schedule. Because the yield consumes no slice end and draws nothing from the thread’s chaos PRNG, making it again keeps the replay aligned with its record.

Source

pub fn scheduler_turn_charge(&self) -> Result<u64, String>

The virtual nanoseconds each committed scheduler turn adds to the global clock: --scheduler-turn-cost (default NANOS_PER_SCHED) times --clock-multiplier, truncated as it always was. A configured cost must give a charge of at least one nanosecond, because the charge is what advances the clock through turns that run no guest code, such as the retries of a finite poll; a scaled charge of zero would leave such a timeout unable to expire. A configured cost, or its scaled charge, above MAX_SCHEDULER_TURN_COST is refused too, so that a configured charge never exceeds one second per turn.

Source

pub fn pipe_wake_latency_in_effect(&self) -> Option<u64>

The --pipe-wake-latency in effect (https://github.com/rrnewton/hermit/issues/4380): the option’s value in run mode, with sequentialized threads and a heuristic that selects by priority; None everywhere else, so nothing of the hand-off runs.

Source

pub fn expired_wait_runs_charged_once(&self) -> bool

Whether a run of consecutive turns that each end an expired timed wait is charged one scheduler turn (--expired-wait-charge): the explicit value, or by default outside race search (--chaos, or a --sched-heuristic that does not select by priority). Never under hermit record and hermit replay. A replay that leaves the option unset takes its record’s value instead (Scheduler::new).

Source

pub fn use_nonblocking_sockets(&self) -> bool

Should we convert sockets to SOCK_NONBLOCK?

Source

pub fn should_trace_schedevent(&self) -> bool

Should we call trace_schedevent to trace each SchedEvent? This applies to both record and replay for scheduled events.

Source

pub fn observes_schedevents(&self) -> bool

Whether this run produces and traces schedule events: the decision should_trace_schedevent makes for recording and schedule replay, and also replay of a callback-annotated priority history (annotated_priority_replay). Such a record was made with --record-preemptions, so its replay makes every decision this gates as its recording did, whether or not it writes a record, and its callback checkpoints compare against the progress those events count.

Source

pub fn annotated_priority_replay_unqualified(&self) -> Option<&'static str>

Why this effective configuration cannot replay a callback-annotated priority history, or None when it can. Its row ends are actual callback endpoints at exact RCB counts, guarded one RCB past each: that needs the backend’s own Detcore preemption timer events (delivers_preemption_timer_events), sequentialized threads (the scheduler that grants each history and acknowledges each row), an active maximum timeslice, precise timers and RCB time. The answer names the first unmet requirement. It reads capabilities, never a backend’s name, and never changes the configuration.

Source

pub fn interrupts_for_thread(&self, thread_id: DetTid) -> BTreeSet<u64>

Returns manual interuption points for a given thread

Source§

impl Config

Source

pub fn from_env() -> Self

Construct the config using environment variables only, not CLI args.

Source

pub fn rng_seed(&self) -> u64

Returns effective “rng-seed” parameter taking in account “seed” parameter if former isn’t specified

Source

pub fn fuzz_seed(&self) -> u64

Returns the fuzz_seed, as specified by the user or defaulting to the primary seed if unspecified.

Source

pub fn sched_seed(&self) -> u64

Returns effective “sched-seed” parameter taking in account “seed” parameter if former isn’t specified

Trait Implementations§

Source§

impl Args for Config

Source§

fn group_id() -> Option<Id>

Report the [ArgGroup::id][crate::ArgGroup::id] for this set of arguments
Source§

fn augment_args<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via [FromArgMatches::from_arg_matches_mut] Read more
Source§

fn augment_args_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via [FromArgMatches::update_from_arg_matches_mut] Read more
Source§

impl Clone for Config

Source§

fn clone(&self) -> Config

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl CommandFactory for Config

Source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
Source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
Source§

impl Debug for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Config

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Config

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl FromArgMatches for Config

Source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

impl Parser for Config

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where I: IntoIterator<Item = T>, T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where I: IntoIterator<Item = T>, T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where I: IntoIterator<Item = T>, T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where I: IntoIterator<Item = T>, T: Into<OsString> + Clone,

Update from iterator, return Err on error.
Source§

impl Serialize for Config

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more