@@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
1010use std:: os:: unix:: net:: UnixStream ;
1111use std:: ptr;
1212
13- use serde:: Deserialize ;
13+ use serde:: { Deserialize , Serialize } ;
1414use userfaultfd:: { Error , Event , Uffd } ;
1515use utils:: get_page_size;
1616use utils:: sock_ctrl_msg:: ScmSocket ;
@@ -22,7 +22,7 @@ use utils::sock_ctrl_msg::ScmSocket;
2222///
2323/// E.g. Guest memory contents for a region of `size` bytes can be found in the backend
2424/// at `offset` bytes from the beginning, and should be copied/populated into `base_host_address`.
25- #[ derive( Clone , Debug , Deserialize ) ]
25+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
2626pub struct GuestRegionUffdMapping {
2727 /// Base host virtual address where the guest memory contents for this region
2828 /// should be copied/populated.
@@ -292,3 +292,92 @@ fn create_mem_regions(mappings: &Vec<GuestRegionUffdMapping>) -> Vec<MemRegion>
292292
293293 mem_regions
294294}
295+
296+ #[ cfg( test) ]
297+ mod tests {
298+ use std:: mem:: MaybeUninit ;
299+ use std:: os:: unix:: net:: UnixListener ;
300+
301+ use utils:: tempdir:: TempDir ;
302+ use utils:: tempfile:: TempFile ;
303+
304+ use super :: * ;
305+
306+ unsafe impl Send for Runtime { }
307+
308+ #[ test]
309+ fn test_runtime ( ) {
310+ let tmp_dir = TempDir :: new ( ) . unwrap ( ) ;
311+ let dummy_socket_path = tmp_dir. as_path ( ) . join ( "dummy_socket" ) ;
312+ let dummy_socket_path_clone = dummy_socket_path. clone ( ) ;
313+
314+ let mut uninit_runtime = Box :: new ( MaybeUninit :: < Runtime > :: uninit ( ) ) ;
315+ // We will use this pointer to bypass a bunch of Rust Safety
316+ // for the sake of convenience.
317+ let runtime_ptr = uninit_runtime. as_ptr ( ) as * const Runtime ;
318+
319+ let runtime_thread = std:: thread:: spawn ( move || {
320+ let tmp_file = TempFile :: new ( ) . unwrap ( ) ;
321+ tmp_file. as_file ( ) . set_len ( 0x1000 ) . unwrap ( ) ;
322+ let dummy_mem_path = tmp_file. as_path ( ) ;
323+
324+ let file = File :: open ( dummy_mem_path) . expect ( "Cannot open memfile" ) ;
325+ let listener =
326+ UnixListener :: bind ( dummy_socket_path) . expect ( "Cannot bind to socket path" ) ;
327+ let ( stream, _) = listener. accept ( ) . expect ( "Cannot listen on UDS socket" ) ;
328+ // Update runtime with actual runtime
329+ let runtime = uninit_runtime. write ( Runtime :: new ( stream, file) ) ;
330+ runtime. run ( |_: & mut UffdHandler | { } ) ;
331+ } ) ;
332+
333+ // wait for runtime thread to initialize itself
334+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
335+
336+ let stream =
337+ UnixStream :: connect ( dummy_socket_path_clone) . expect ( "Cannot connect to the socket" ) ;
338+
339+ let dummy_memory_region = vec ! [ GuestRegionUffdMapping {
340+ base_host_virt_addr: 0 ,
341+ size: 0x1000 ,
342+ offset: 0 ,
343+ } ] ;
344+ let dummy_memory_region_json = serde_json:: to_string ( & dummy_memory_region) . unwrap ( ) ;
345+
346+ let dummy_file_1 = TempFile :: new ( ) . unwrap ( ) ;
347+ let dummy_fd_1 = dummy_file_1. as_file ( ) . as_raw_fd ( ) ;
348+ stream
349+ . send_with_fd ( dummy_memory_region_json. as_bytes ( ) , dummy_fd_1)
350+ . unwrap ( ) ;
351+ // wait for the runtime thread to process message
352+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
353+ unsafe {
354+ assert_eq ! ( ( * runtime_ptr) . uffds. len( ) , 1 ) ;
355+ }
356+
357+ let dummy_file_2 = TempFile :: new ( ) . unwrap ( ) ;
358+ let dummy_fd_2 = dummy_file_2. as_file ( ) . as_raw_fd ( ) ;
359+ stream
360+ . send_with_fd ( dummy_memory_region_json. as_bytes ( ) , dummy_fd_2)
361+ . unwrap ( ) ;
362+ // wait for the runtime thread to process message
363+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
364+ unsafe {
365+ assert_eq ! ( ( * runtime_ptr) . uffds. len( ) , 2 ) ;
366+ }
367+
368+ // there is no way to properly stop runtime, so
369+ // we send a message with an incorrect memory region
370+ // to cause runtime thread to panic
371+ let error_memory_region = vec ! [ GuestRegionUffdMapping {
372+ base_host_virt_addr: 0 ,
373+ size: 0 ,
374+ offset: 0 ,
375+ } ] ;
376+ let error_memory_region_json = serde_json:: to_string ( & error_memory_region) . unwrap ( ) ;
377+ stream
378+ . send_with_fd ( error_memory_region_json. as_bytes ( ) , dummy_fd_2)
379+ . unwrap ( ) ;
380+
381+ runtime_thread. join ( ) . unwrap_err ( ) ;
382+ }
383+ }
0 commit comments