You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/// Ensures that `kill()` reliably interrupts a running guest
1351
+
///
1352
+
/// The test works by:
1353
+
/// 1. Guest calls a host function which waits on a barrier, ensuring the guest is "in-progress" and that `kill()` is not called prematurely to be ignored.
1354
+
/// 2. Once the guest has passed that host function barrier, the host calls `kill()`. The `kill()` could be delivered at any time after this point, for example while guest is still in the host func, or returning into guest vm.
1355
+
/// 3. The guest enters an infinite loop, so `kill()` is the only way to stop it.
1356
+
///
1357
+
/// This is repeated across multiple threads and iterations to stress test the cancellation mechanism.
1358
+
///
1359
+
/// **Failure Condition:** If this test hangs, it means `kill()` failed to stop the guest, leaving it spinning forever.
1360
+
#[test]
1361
+
fninterrupt_infinite_loop_stress_test(){
1362
+
use std::sync::{Arc,Barrier};
1363
+
use std::thread;
1364
+
1365
+
constNUM_THREADS:usize = 50;
1366
+
constITERATIONS_PER_THREAD:usize = 500;
1367
+
1368
+
letmut handles = vec![];
1369
+
1370
+
for i in0..NUM_THREADS{
1371
+
handles.push(thread::spawn(move || {
1372
+
// Create a barrier for 2 threads:
1373
+
// 1. The guest (executing a host function)
1374
+
// 2. The killer thread
1375
+
let barrier = Arc::new(Barrier::new(2));
1376
+
let barrier_for_host = barrier.clone();
1377
+
1378
+
letmut uninit = new_uninit_rust().unwrap();
1379
+
1380
+
// Register a host function that waits on the barrier
1381
+
uninit
1382
+
.register("WaitForKill",move || {
1383
+
barrier_for_host.wait();
1384
+
Ok(())
1385
+
})
1386
+
.unwrap();
1387
+
1388
+
letmut sandbox = uninit.evolve().unwrap();
1389
+
// Take a snapshot to restore after each kill
1390
+
let snapshot = sandbox.snapshot().unwrap();
1391
+
1392
+
for j in0..ITERATIONS_PER_THREAD{
1393
+
let barrier_for_killer = barrier.clone();
1394
+
let interrupt_handle = sandbox.interrupt_handle();
1395
+
1396
+
// Spawn the killer thread
1397
+
let killer_thread = std::thread::spawn(move || {
1398
+
// Wait for the guest to call WaitForKill
1399
+
barrier_for_killer.wait();
1400
+
1401
+
// The guest is now waiting on the barrier (or just finished waiting).
1402
+
// We kill it immediately.
1403
+
interrupt_handle.kill();
1404
+
});
1405
+
1406
+
// Call the guest function "CallHostThenSpin" which calls "WaitForKill" once then spins
1407
+
// NOTE: If this test hangs, it means the guest was not successfully killed and is spinning forever.
1408
+
// This indicates a bug in the cancellation mechanism.
1409
+
let res = sandbox.call::<()>("CallHostThenSpin","WaitForKill".to_string());
0 commit comments