mirror of
https://github.com/facebookexperimental/reverie.git
synced 2025-01-23 05:06:23 +00:00
5df280b851
Summary: If an RPC fails to send, there isn't much that can be done to handle it. In all call sites so far, they all just unwrap the error because it can't be handled properly. If an RPC fails, it is a programmer error (because the request/response failed to serialize/deserialize) and indicates a bug in our code. Differential Revision: D37563857 fbshipit-source-id: 267072709f4230732a13989aaf74b50fd0908337
111 lines
2.9 KiB
Rust
111 lines
2.9 KiB
Rust
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
use reverie::Errno;
|
|
use reverie::GlobalTool;
|
|
use reverie::Guest;
|
|
use reverie::Rdtsc;
|
|
use reverie::RdtscResult;
|
|
use reverie::Subscription;
|
|
use reverie::Tid;
|
|
use reverie::Tool;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::sync::atomic::AtomicUsize;
|
|
use std::sync::atomic::Ordering;
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
|
struct GlobalState {
|
|
tsc: AtomicUsize,
|
|
}
|
|
|
|
#[reverie::global_tool]
|
|
impl GlobalTool for GlobalState {
|
|
type Request = Rdtsc;
|
|
type Response = RdtscResult;
|
|
|
|
async fn init_global_state(_: &Self::Config) -> Self {
|
|
GlobalState {
|
|
tsc: AtomicUsize::new(19200),
|
|
}
|
|
}
|
|
|
|
async fn receive_rpc(&self, _from: Tid, args: Rdtsc) -> RdtscResult {
|
|
let tsc = self.tsc.load(Ordering::Relaxed);
|
|
self.tsc.store(1 + tsc, Ordering::Relaxed);
|
|
match args {
|
|
Rdtsc::Tsc => RdtscResult {
|
|
tsc: tsc as u64,
|
|
aux: None,
|
|
},
|
|
Rdtsc::Tscp => RdtscResult {
|
|
tsc: tsc as u64,
|
|
aux: Some(0),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
|
struct LocalState {}
|
|
|
|
#[reverie::tool]
|
|
impl Tool for LocalState {
|
|
type GlobalState = GlobalState;
|
|
|
|
fn subscriptions(_cfg: &()) -> Subscription {
|
|
let mut s = Subscription::none();
|
|
s.rdtsc();
|
|
s
|
|
}
|
|
|
|
async fn handle_rdtsc_event<T: Guest<Self>>(
|
|
&self,
|
|
guest: &mut T,
|
|
request: Rdtsc,
|
|
) -> Result<RdtscResult, Errno> {
|
|
let tsc = guest.send_rpc(request).await;
|
|
println!("handle_rdtsc: returned {:?}", tsc);
|
|
Ok(tsc)
|
|
}
|
|
}
|
|
|
|
#[cfg(all(not(sanitized), test))]
|
|
mod tests {
|
|
use super::*;
|
|
use reverie_ptrace::testing::check_fn;
|
|
|
|
#[allow(unused_mut)]
|
|
#[inline(never)]
|
|
unsafe fn rdtscp() -> (u64, u32) {
|
|
let mut aux_val = core::mem::MaybeUninit::uninit();
|
|
let tsc = core::arch::x86_64::__rdtscp(aux_val.as_mut_ptr());
|
|
(tsc, aux_val.assume_init())
|
|
}
|
|
|
|
#[test]
|
|
fn run_guest_func_rdtsc_intercepted_test() {
|
|
let state = check_fn::<LocalState, _>(|| {
|
|
let tsc1 = unsafe { core::arch::x86_64::_rdtsc() };
|
|
let tsc2 = unsafe { core::arch::x86_64::_rdtsc() };
|
|
assert_eq!(1 + tsc1, tsc2);
|
|
});
|
|
assert_ne!(state.tsc.load(Ordering::Relaxed), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn run_guest_func_rdtscp_intercepted_test() {
|
|
let state = check_fn::<LocalState, _>(move || {
|
|
let (tsc1, _) = unsafe { rdtscp() };
|
|
let (tsc2, _) = unsafe { rdtscp() };
|
|
assert_eq!(1 + tsc1, tsc2);
|
|
});
|
|
assert_ne!(state.tsc.load(Ordering::Relaxed), 0);
|
|
}
|
|
}
|