fix(core): linearize session publication
This commit is contained in:
@@ -742,6 +742,7 @@ fn signer_callback_rejects_every_stateful_api_across_handles() {
|
||||
let other = create(&mut other_ctx);
|
||||
|
||||
let mut ctx = Context::default();
|
||||
ctx.reentry_cancel.store(OK, Ordering::SeqCst);
|
||||
ctx.reentry_target.store(other as usize, Ordering::SeqCst);
|
||||
let mut cfg = config(&mut ctx);
|
||||
cfg.sign_admission = Some(sign_admission_probes_global_reentry);
|
||||
|
||||
@@ -204,25 +204,52 @@ pub(crate) struct Ready {
|
||||
}
|
||||
|
||||
pub(crate) struct Oracle {
|
||||
_serial: std::sync::MutexGuard<'static, ()>,
|
||||
child: Child,
|
||||
directory: std::path::PathBuf,
|
||||
pub(crate) ready: Ready,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn production_oracles_can_run_concurrently_with_isolated_state() {
|
||||
let (first_ready_tx, first_ready_rx) = std::sync::mpsc::channel();
|
||||
let (release_tx, release_rx) = std::sync::mpsc::channel();
|
||||
let first = thread::spawn(move || {
|
||||
let oracle = Oracle::start("");
|
||||
first_ready_tx.send(()).expect("first ready");
|
||||
release_rx.recv().expect("release first oracle");
|
||||
drop(oracle);
|
||||
});
|
||||
first_ready_rx
|
||||
.recv_timeout(Duration::from_secs(20))
|
||||
.expect("first oracle ready");
|
||||
let (second_ready_tx, second_ready_rx) = std::sync::mpsc::channel();
|
||||
let second = thread::spawn(move || {
|
||||
let oracle = Oracle::start("");
|
||||
second_ready_tx.send(()).expect("second ready");
|
||||
drop(oracle);
|
||||
});
|
||||
let concurrent = second_ready_rx.recv_timeout(Duration::from_secs(5)).is_ok();
|
||||
release_tx.send(()).expect("release first");
|
||||
first.join().expect("first oracle");
|
||||
second.join().expect("second oracle");
|
||||
assert!(concurrent, "second isolated oracle was globally serialized");
|
||||
}
|
||||
|
||||
impl Oracle {
|
||||
pub(crate) fn start(mode: &str) -> Self {
|
||||
static SERIAL: Mutex<()> = Mutex::new(());
|
||||
static NEXT: AtomicUsize = AtomicUsize::new(1);
|
||||
let serial = SERIAL
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let directory = std::env::temp_dir().join(format!(
|
||||
"versevdi-rust-gateway-oracle-{}-{}",
|
||||
std::process::id(),
|
||||
NEXT.fetch_add(1, Ordering::Relaxed)
|
||||
));
|
||||
fs::create_dir(&directory).expect("create oracle directory");
|
||||
let directory = loop {
|
||||
let candidate = std::env::temp_dir().join(format!(
|
||||
"versevdi-rust-gateway-oracle-{}-{}",
|
||||
std::process::id(),
|
||||
NEXT.fetch_add(1, Ordering::Relaxed)
|
||||
));
|
||||
match fs::create_dir(&candidate) {
|
||||
Ok(()) => break candidate,
|
||||
Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {}
|
||||
Err(error) => panic!("create oracle directory: {error}"),
|
||||
}
|
||||
};
|
||||
let source = directory.join("main.go");
|
||||
let ready_path = directory.join("ready.json");
|
||||
let stop_path = directory.join("stop");
|
||||
@@ -242,7 +269,6 @@ impl Oracle {
|
||||
if let Ok(bytes) = fs::read(&ready_path) {
|
||||
if let Ok(ready) = serde_json::from_slice(&bytes) {
|
||||
return Self {
|
||||
_serial: serial,
|
||||
child,
|
||||
directory,
|
||||
ready,
|
||||
@@ -522,6 +548,8 @@ unsafe extern "C" {
|
||||
struct AbiSigners {
|
||||
admission: Arc<dyn SigningKey>,
|
||||
tls: Arc<dyn SigningKey>,
|
||||
admission_threads: Mutex<Vec<thread::ThreadId>>,
|
||||
tls_threads: Mutex<Vec<thread::ThreadId>>,
|
||||
}
|
||||
unsafe extern "C" fn abi_admission(raw: *mut c_void, input: AbiBytes, output: *mut u8) -> u32 {
|
||||
unsafe { abi_sign(raw, input, output, true) }
|
||||
@@ -531,6 +559,15 @@ unsafe extern "C" fn abi_tls(raw: *mut c_void, input: AbiBytes, output: *mut u8)
|
||||
}
|
||||
unsafe fn abi_sign(raw: *mut c_void, input: AbiBytes, output: *mut u8, admission: bool) -> u32 {
|
||||
let context = unsafe { &*raw.cast::<AbiSigners>() };
|
||||
let threads = if admission {
|
||||
&context.admission_threads
|
||||
} else {
|
||||
&context.tls_threads
|
||||
};
|
||||
threads
|
||||
.lock()
|
||||
.expect("signer threads")
|
||||
.push(thread::current().id());
|
||||
let bytes = unsafe { std::slice::from_raw_parts(input.data, input.length) };
|
||||
let key = if admission {
|
||||
&context.admission
|
||||
@@ -552,6 +589,8 @@ fn real_abi_exports_connect_send_cancel_and_destroy_the_go_gateway_session() {
|
||||
let mut signers = Box::new(AbiSigners {
|
||||
admission: test_key(&oracle.ready.admission_key),
|
||||
tls: test_key(&oracle.ready.client_key),
|
||||
admission_threads: Mutex::new(Vec::new()),
|
||||
tls_threads: Mutex::new(Vec::new()),
|
||||
});
|
||||
let config = AbiConfig {
|
||||
struct_size: size_of::<AbiConfig>() as u32,
|
||||
@@ -579,7 +618,20 @@ fn real_abi_exports_connect_send_cancel_and_destroy_the_go_gateway_session() {
|
||||
length: oracle.ready.credential.len(),
|
||||
},
|
||||
};
|
||||
let calling_thread = thread::current().id();
|
||||
assert_eq!(unsafe { verse_core_connect_v1(core, &request) }, 0);
|
||||
assert_eq!(
|
||||
signers
|
||||
.admission_threads
|
||||
.lock()
|
||||
.expect("admission threads")
|
||||
.as_slice(),
|
||||
[calling_thread]
|
||||
);
|
||||
assert_eq!(
|
||||
signers.tls_threads.lock().expect("TLS threads").as_slice(),
|
||||
[calling_thread]
|
||||
);
|
||||
let mut values = [0; 12];
|
||||
values[0] = 1;
|
||||
values[2] = 30;
|
||||
|
||||
Reference in New Issue
Block a user