@@ -309,6 +309,11 @@ pub enum LoadSnapshotError {
309
309
ResumeMicrovm ( #[ from] VmmError ) ,
310
310
}
311
311
312
+ /// Shorthand type for a request containing a boxed VmmAction.
313
+ pub type ApiRequest = Box < VmmAction > ;
314
+ /// Shorthand type for a response containing a boxed Result.
315
+ pub type ApiResponse = Box < std:: result:: Result < VmmData , VmmActionError > > ;
316
+
312
317
impl < ' a > PrebootApiController < ' a > {
313
318
/// Constructor for the PrebootApiController.
314
319
pub fn new (
@@ -329,25 +334,20 @@ impl<'a> PrebootApiController<'a> {
329
334
}
330
335
331
336
/// Default implementation for the function that builds and starts a microVM.
332
- /// It takes two closures `recv_req` and `respond` as params which abstract away
333
- /// the message transport.
334
337
///
335
338
/// Returns a populated `VmResources` object and a running `Vmm` object.
336
339
#[ allow( clippy:: too_many_arguments) ]
337
- pub fn build_microvm_from_requests < F , G > (
340
+ pub fn build_microvm_from_requests (
338
341
seccomp_filters : & BpfThreadMap ,
339
342
event_manager : & mut EventManager ,
340
343
instance_info : InstanceInfo ,
341
- recv_req : F ,
342
- respond : G ,
344
+ from_api : & std:: sync:: mpsc:: Receiver < ApiRequest > ,
345
+ to_api : & std:: sync:: mpsc:: Sender < ApiResponse > ,
346
+ api_event_fd : & utils:: eventfd:: EventFd ,
343
347
boot_timer_enabled : bool ,
344
348
mmds_size_limit : usize ,
345
349
metadata_json : Option < & str > ,
346
- ) -> Result < ( VmResources , Arc < Mutex < Vmm > > ) , FcExitCode >
347
- where
348
- F : Fn ( ) -> VmmAction ,
349
- G : Fn ( Result < VmmData , VmmActionError > ) ,
350
- {
350
+ ) -> Result < ( VmResources , Arc < Mutex < Vmm > > ) , FcExitCode > {
351
351
let mut vm_resources = VmResources :: default ( ) ;
352
352
// Silence false clippy warning. Clippy suggests using
353
353
// VmResources { boot_timer: boot_timer_enabled, ..Default::default() }; but this will
@@ -386,11 +386,21 @@ impl<'a> PrebootApiController<'a> {
386
386
// The loop breaks when a microVM is successfully started, and a running Vmm is built.
387
387
while preboot_controller. built_vmm . is_none ( ) {
388
388
// Get request
389
- let req = recv_req ( ) ;
389
+ let req = from_api
390
+ . recv ( )
391
+ . expect ( "The channel's sending half was disconnected. Cannot receive data." ) ;
392
+
393
+ // Also consume the API event along with the message. It is safe to unwrap()
394
+ // because this event_fd is blocking.
395
+ api_event_fd
396
+ . read ( )
397
+ . expect ( "VMM: Failed to read the API event_fd" ) ;
398
+
390
399
// Process the request.
391
- let res = preboot_controller. handle_preboot_request ( req) ;
400
+ let res = preboot_controller. handle_preboot_request ( * req) ;
401
+
392
402
// Send back the response.
393
- respond ( res) ;
403
+ to_api . send ( Box :: new ( res) ) . expect ( "one-shot channel closed" ) ;
394
404
395
405
// If any fatal errors were encountered, break the loop.
396
406
if let Some ( exit_code) = preboot_controller. fatal_error {
@@ -1827,60 +1837,6 @@ mod tests {
1827
1837
) ;
1828
1838
}
1829
1839
1830
- #[ test]
1831
- fn test_build_microvm_from_requests ( ) {
1832
- // Use atomics to be able to use them non-mutably in closures below.
1833
- use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
1834
-
1835
- let cmd_step = AtomicUsize :: new ( 0 ) ;
1836
- let commands = || {
1837
- cmd_step. fetch_add ( 1 , Ordering :: SeqCst ) ;
1838
- match cmd_step. load ( Ordering :: SeqCst ) {
1839
- 1 => VmmAction :: FlushMetrics ,
1840
- 2 => VmmAction :: Pause ,
1841
- 3 => VmmAction :: Resume ,
1842
- 4 => VmmAction :: StartMicroVm ,
1843
- _ => unreachable ! ( ) ,
1844
- }
1845
- } ;
1846
-
1847
- let resp_step = AtomicUsize :: new ( 0 ) ;
1848
- let expected_resp = |resp : Result < VmmData , VmmActionError > | {
1849
- resp_step. fetch_add ( 1 , Ordering :: SeqCst ) ;
1850
- let expect = match resp_step. load ( Ordering :: SeqCst ) {
1851
- 1 => Err ( VmmActionError :: OperationNotSupportedPreBoot ) ,
1852
- 2 => Err ( VmmActionError :: OperationNotSupportedPreBoot ) ,
1853
- 3 => Err ( VmmActionError :: OperationNotSupportedPreBoot ) ,
1854
- 4 => Ok ( VmmData :: Empty ) ,
1855
- _ => unreachable ! ( ) ,
1856
- } ;
1857
- assert_eq ! ( resp, expect) ;
1858
- } ;
1859
-
1860
- let ( vm_res, _vmm) = PrebootApiController :: build_microvm_from_requests (
1861
- & BpfThreadMap :: new ( ) ,
1862
- & mut EventManager :: new ( ) . unwrap ( ) ,
1863
- InstanceInfo :: default ( ) ,
1864
- commands,
1865
- expected_resp,
1866
- false ,
1867
- HTTP_MAX_PAYLOAD_SIZE ,
1868
- Some ( r#""magic""# ) ,
1869
- )
1870
- . unwrap ( ) ;
1871
-
1872
- assert_eq ! (
1873
- vm_res
1874
- . mmds
1875
- . as_ref( )
1876
- . unwrap( )
1877
- . lock( )
1878
- . unwrap( )
1879
- . data_store_value( ) ,
1880
- Value :: String ( "magic" . to_string( ) )
1881
- ) ;
1882
- }
1883
-
1884
1840
fn check_runtime_request < F > ( request : VmmAction , check_success : F )
1885
1841
where
1886
1842
F : FnOnce ( Result < VmmData , VmmActionError > , & MockVmm ) ,
0 commit comments