Skip to content

Remove hypervisor_handler thread #533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ Make sure that you keep commits small and focused. Each commit should represent
Make sure that you arrange your commits in a logical order. You can use `git rebase -i` to do this.
If you update your PR branch with new commits, make sure to rebase your branch on top of the main branch. This will help keep the commit history clean and make it easier to review your changes.
Make sure that you do not have any merge commits in your PR.
If when running tests you receive an Error like this "Error("No Hypervisor was found for Sandbox, Hypervisor Handler Message Receive Timedout")" then the real error is the string inside the brackets before the comma, so in this example
the error is "No Hypervisor was found for Sandbox".
If you see the error "No Hypervisor was found for Sandbox" then you if you are running on Linux you should check to see if there is a device called "kvm" or "mshv" in `/dev` and if it is present you should also check to see if you have rw access to it. You should ensure that you output the results of these checks for diagnostic purposes.
This repository requires commits to be signed you should ensure that any commits that you create are done with `commit.gpgsign=true`. Also commits should also be signed with the `--signoff` option to comply with the DCO requirement.

Expand Down
6 changes: 2 additions & 4 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,12 @@ test-unit target=default-target features="":
test-isolated target=default-target features="":
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_trace_trace --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- hypervisor::hypervisor_handler::tests::create_1000_sandboxes --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::create_1000_sandboxes --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- sandbox::outb::tests::test_log_outb_log --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- mem::shared_mem::tests::test_drop --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --test integration_test -- log_message --exact --ignored
@# metrics tests
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact --ignored
cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact --ignored

cargo test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact
# runs integration tests. Guest can either be "rust" or "c"
test-integration guest target=default-target features="":
@# run execute_on_heap test with feature "executable_heap" on and off
Expand Down
7 changes: 3 additions & 4 deletions docs/how-to-debug-a-hyperlight-guest.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,14 @@ To replicate the above behavior using VSCode follow the below steps:
## How it works

The gdb feature is designed to work like a Request - Response protocol between
a thread that accepts commands from a gdb client and the hypervisor handler over
a communication channel.
a thread that accepts commands from a gdb client and main thread of the sandbox.

All the functionality is implemented on the hypervisor side so it has access to
the shared memory and the vCPU.

The gdb thread uses the `gdbstub` crate to handle the communication with the gdb client.
When the gdb client requests one of the supported features mentioned above, a request
is sent over the communication channel to the hypervisor handler for the sandbox
is sent over the communication channel to the main thread for the sandbox
to resolve.

Below is a sequence diagram that shows the interaction between the entities
Expand All @@ -161,7 +160,7 @@ involved in the gdb debugging of a Hyperlight guest running inside a **KVM** or
│ Hyperlight Sandbox │
USER │ │
┌────────────┐ │ ┌──────────────┐ ┌───────────────────────────┐ ┌────────┐ │
│ gdb client │ │ │ gdb thread │ │ hypervisor handler thread │ │ vCPU │ │
│ gdb client │ │ │ gdb thread │ │ main sandbox thread │ │ vCPU │ │
└────────────┘ │ └──────────────┘ └───────────────────────────┘ └────────┘ │
| │ | create_gdb_thread | | │
| │ |◄─────────────────────────────────────────┌─┐ vcpu stopped ┌─┐ │
Expand Down
3 changes: 0 additions & 3 deletions src/hyperlight_host/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

use std::time::Duration;

use criterion::{criterion_group, criterion_main, Criterion};
use hyperlight_host::sandbox::{MultiUseSandbox, SandboxConfiguration, UninitializedSandbox};
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
Expand Down Expand Up @@ -68,7 +66,6 @@ fn guest_call_benchmark(c: &mut Criterion) {
let mut config = SandboxConfiguration::default();
config.set_input_data_size(2 * SIZE + (1024 * 1024)); // 2 * SIZE + 1 MB, to allow 1MB for the rest of the serialized function call
config.set_heap_size(SIZE as u64 * 15);
config.set_max_execution_time(Duration::from_secs(10));

let sandbox = UninitializedSandbox::new(
GuestBinary::FilePath(simple_guest_as_string().unwrap()),
Expand Down
20 changes: 18 additions & 2 deletions src/hyperlight_host/examples/logging/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.
#![allow(clippy::disallowed_macros)]
extern crate hyperlight_host;

use std::sync::{Arc, Barrier};

use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
use hyperlight_host::sandbox_state::transition::Noop;
Expand Down Expand Up @@ -82,15 +84,29 @@ fn main() -> Result<()> {
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();

let mut multiuse_sandbox = usandbox.evolve(no_op)?;
let interrupt_handle = multiuse_sandbox.interrupt_handle();
let barrier = Arc::new(Barrier::new(2));
let barrier2 = barrier.clone();
const NUM_CALLS: i32 = 5;
let thread = std::thread::spawn(move || {
for _ in 0..NUM_CALLS {
barrier2.wait();
// Sleep for a short time to allow the guest function to run.
std::thread::sleep(std::time::Duration::from_millis(500));
// Cancel the host function call.
interrupt_handle.kill();
}
});

// Call a function that gets cancelled by the host function 5 times to generate some log entries.

for _ in 0..5 {
for _ in 0..NUM_CALLS {
let mut ctx = multiuse_sandbox.new_call_context();

barrier.wait();
ctx.call::<()>("Spin", ()).unwrap_err();
multiuse_sandbox = ctx.finish().unwrap();
}
thread.join().unwrap();

Ok(())
}
21 changes: 19 additions & 2 deletions src/hyperlight_host/examples/metrics/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/
#![allow(clippy::disallowed_macros)]
extern crate hyperlight_host;
use std::sync::{Arc, Barrier};
use std::thread::{spawn, JoinHandle};

use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
Expand Down Expand Up @@ -95,12 +96,27 @@ fn do_hyperlight_stuff() {
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();

let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox");
let interrupt_handle = multiuse_sandbox.interrupt_handle();

const NUM_CALLS: i32 = 5;
let barrier = Arc::new(Barrier::new(2));
let barrier2 = barrier.clone();

let thread = std::thread::spawn(move || {
for _ in 0..NUM_CALLS {
barrier2.wait();
// Sleep for a short time to allow the guest function to run after the `wait`.
std::thread::sleep(std::time::Duration::from_millis(500));
// Cancel the host function call.
interrupt_handle.kill();
}
});

// Call a function that gets cancelled by the host function 5 times to generate some metrics.

for _ in 0..5 {
for _ in 0..NUM_CALLS {
let mut ctx = multiuse_sandbox.new_call_context();

barrier.wait();
ctx.call::<()>("Spin", ()).unwrap_err();
multiuse_sandbox = ctx.finish().unwrap();
}
Expand All @@ -109,6 +125,7 @@ fn do_hyperlight_stuff() {
let result = join_handle.join();
assert!(result.is_ok());
}
thread.join().unwrap();
}

fn fn_writer(_msg: String) -> Result<i32> {
Expand Down
32 changes: 21 additions & 11 deletions src/hyperlight_host/examples/tracing-otlp/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,15 @@ limitations under the License.
#![allow(clippy::disallowed_macros)]
//use opentelemetry_sdk::resource::ResourceBuilder;
use opentelemetry_sdk::trace::SdkTracerProvider;
use rand::Rng;
use tracing::{span, Level};
use tracing_opentelemetry::OpenTelemetryLayer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
extern crate hyperlight_host;
use std::error::Error;
use std::io::stdin;
use std::sync::{Arc, Mutex};
use std::thread::{self, spawn, JoinHandle};
use std::sync::{Arc, Barrier, Mutex};
use std::thread::{spawn, JoinHandle};

use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
Expand Down Expand Up @@ -157,8 +156,23 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> {
}

// Call a function that gets cancelled by the host function 5 times to generate some log entries.

for i in 0..5 {
const NUM_CALLS: i32 = 5;
let barrier = Arc::new(Barrier::new(2));
let barrier2 = barrier.clone();

let interrupt_handle = multiuse_sandbox.interrupt_handle();

let thread = std::thread::spawn(move || {
for _ in 0..NUM_CALLS {
barrier2.wait();
// Sleep for a short time to allow the guest function to run.
std::thread::sleep(std::time::Duration::from_millis(500));
// Cancel the host function call.
interrupt_handle.kill();
}
});

for i in 0..NUM_CALLS {
let id = Uuid::new_v4();
// Construct a new span named "hyperlight tracing call cancellation example thread" with INFO level.
let span = span!(
Expand All @@ -169,15 +183,11 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> {
);
let _entered = span.enter();
let mut ctx = multiuse_sandbox.new_call_context();

barrier.wait();
ctx.call::<()>("Spin", ()).unwrap_err();
multiuse_sandbox = ctx.finish().unwrap();
}
let sleep_for = {
let mut rng = rand::rng();
rng.random_range(500..3000)
};
thread::sleep(std::time::Duration::from_millis(sleep_for));
thread.join().expect("Thread panicked");
}
Ok(())
});
Expand Down
22 changes: 19 additions & 3 deletions src/hyperlight_host/examples/tracing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
#![allow(clippy::disallowed_macros)]
use tracing::{span, Level};
extern crate hyperlight_host;
use std::sync::{Arc, Barrier};
use std::thread::{spawn, JoinHandle};

use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
Expand Down Expand Up @@ -110,10 +111,24 @@ fn run_example() -> Result<()> {
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();

let mut multiuse_sandbox = usandbox.evolve(no_op)?;
let interrupt_handle = multiuse_sandbox.interrupt_handle();

// Call a function that gets cancelled by the host function 5 times to generate some log entries.

for i in 0..5 {
const NUM_CALLS: i32 = 5;
let barrier = Arc::new(Barrier::new(2));
let barrier2 = barrier.clone();

let thread = std::thread::spawn(move || {
for _ in 0..NUM_CALLS {
barrier2.wait();
// Sleep for a short time to allow the guest function to run.
std::thread::sleep(std::time::Duration::from_millis(500));
// Cancel the host function call.
interrupt_handle.kill();
}
});

for i in 0..NUM_CALLS {
let id = Uuid::new_v4();
// Construct a new span named "hyperlight tracing call cancellation example thread" with INFO level.
let span = span!(
Expand All @@ -124,7 +139,7 @@ fn run_example() -> Result<()> {
);
let _entered = span.enter();
let mut ctx = multiuse_sandbox.new_call_context();

barrier.wait();
ctx.call::<()>("Spin", ()).unwrap_err();
multiuse_sandbox = ctx.finish().unwrap();
}
Expand All @@ -133,6 +148,7 @@ fn run_example() -> Result<()> {
let result = join_handle.join();
assert!(result.is_ok());
}
thread.join().unwrap();

Ok(())
}
16 changes: 0 additions & 16 deletions src/hyperlight_host/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,22 +122,6 @@ pub enum HyperlightError {
#[error("HostFunction {0} was not found")]
HostFunctionNotFound(String),

/// An attempt to communicate with or from the Hypervisor Handler thread failed
/// (i.e., usually a failure call to `.send()` or `.recv()` on a message passing
/// channel)
#[error("Communication failure with the Hypervisor Handler thread")]
HypervisorHandlerCommunicationFailure(),

/// An attempt to cancel a Hypervisor Handler execution failed.
/// See `terminate_hypervisor_handler_execution_and_reinitialise`
/// for more details.
#[error("Hypervisor Handler execution cancel attempt on a finished execution")]
HypervisorHandlerExecutionCancelAttemptOnFinishedExecution(),

/// A Receive for a Hypervisor Handler Message Timedout
#[error("Hypervisor Handler Message Receive Timedout")]
HypervisorHandlerMessageReceiveTimedout(),

/// Reading Writing or Seeking data failed.
#[error("Reading Writing or Seeking data failed {0:?}")]
IOError(#[from] std::io::Error),
Expand Down
8 changes: 5 additions & 3 deletions src/hyperlight_host/src/func/call_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ limitations under the License.

use tracing::{instrument, Span};

use super::guest_dispatch::call_function_on_guest;
use super::{ParameterTuple, SupportedReturnType};
use crate::{MultiUseSandbox, Result};
/// A context for calling guest functions.
Expand Down Expand Up @@ -69,8 +68,11 @@ impl MultiUseGuestCallContext {
// !Send (and !Sync), we also don't need to worry about
// synchronization

let ret =
call_function_on_guest(&mut self.sbox, func_name, Output::TYPE, args.into_value());
let ret = self.sbox.call_guest_function_by_name_no_reset(
func_name,
Output::TYPE,
args.into_value(),
);
Output::from_value(ret?)
}

Expand Down
Loading