Skip to main content

detcore_model/
virtual_timeout.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! Admission for a virtual bound whose scheduler must observe final signal delivery.
10
11use std::num::NonZeroU64;
12
13/// A debugger can suppress a fatal signal after Detcore has marked its process
14/// doomed. Until final delivery is reconciled, that combination cannot promise
15/// to stop a surviving guest at its virtual bound.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct VirtualTimeoutWithDebugger;
18
19impl std::fmt::Display for VirtualTimeoutWithDebugger {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.write_str(
22            "HERMIT_VIRTUAL_TIMEOUT_WITH_DEBUGGER: --virtual-timeout is not supported with \
23             --gdbserver or --dap-listen: a debugger can suppress a fatal signal after Detcore \
24             marks its process doomed; remove --virtual-timeout or the debugger option, or \
25             use --timeout for a wall-clock bound",
26        )
27    }
28}
29
30impl std::error::Error for VirtualTimeoutWithDebugger {}
31
32/// Refuse the combination before a guest or debugger is started. The caller
33/// includes a pending DAP listener in `debugger`, even before it is lowered to
34/// `Config::gdbserver`. Neither option alone changes its admission here.
35pub fn refuse_debugger(
36    bound: Option<NonZeroU64>,
37    debugger: bool,
38) -> Result<(), VirtualTimeoutWithDebugger> {
39    if bound.is_some() && debugger {
40        Err(VirtualTimeoutWithDebugger)
41    } else {
42        Ok(())
43    }
44}