1 #![cfg(not(miri))] 2 3 use crate::threads::engine; 4 use std::time::Instant; 5 use wasmtime::*; 6 7 #[test] 8 fn atomic_wait_timeout_length() -> Result<()> { 9 let sleep_nanoseconds = 500000000; 10 let wat = format!( 11 r#"(module 12 (import "env" "memory" (memory 1 1 shared)) 13 14 (func (export "func1") (result i32) 15 (memory.atomic.wait32 (i32.const 0) (i32.const 0) (i64.const {sleep_nanoseconds})) 16 ) 17 18 (data (i32.const 0) "\00\00\00\00") 19 )"# 20 ); 21 let Some(engine) = engine() else { 22 return Ok(()); 23 }; 24 let module = Module::new(&engine, wat)?; 25 let mut store = Store::new(&engine, ()); 26 let shared_memory = SharedMemory::new(&engine, MemoryType::shared(1, 1))?; 27 let instance = Instance::new(&mut store, &module, &[shared_memory.clone().into()])?; 28 let now = Instant::now(); 29 let func_ret = instance 30 .get_typed_func::<(), i32>(&mut store, "func1") 31 .unwrap() 32 .call(&mut store, ()) 33 .unwrap(); 34 let duration = now.elapsed(); 35 assert!( 36 duration.as_nanos() >= sleep_nanoseconds, 37 "duration: {duration:?} < {sleep_nanoseconds:?}" 38 ); 39 assert_eq!(func_ret, 2); 40 Ok(()) 41 } 42 43 #[test] 44 fn atomic_wait_notify_basic() -> Result<()> { 45 let wat = r#"(module 46 (import "env" "memory" (memory 1 1 shared)) 47 48 (func (export "first_thread") (result i32) 49 (drop (memory.atomic.wait32 (i32.const 4) (i32.const 0) (i64.const -1))) 50 (i32.atomic.store (i32.const 0) (i32.const 42)) 51 (drop (memory.atomic.notify (i32.const 0) (i32.const -1))) 52 (i32.atomic.load (i32.const 0)) 53 ) 54 55 (func (export "second_thread") (result i32) 56 (i32.atomic.store (i32.const 4) (i32.const 21)) 57 (drop (memory.atomic.notify (i32.const 4) (i32.const -1))) 58 (drop (memory.atomic.wait32 (i32.const 0) (i32.const 0) (i64.const -1))) 59 (i32.atomic.load (i32.const 0)) 60 ) 61 62 (data (i32.const 0) "\00\00\00\00") 63 (data (i32.const 4) "\00\00\00\00") 64 )"#; 65 let Some(engine) = engine() else { 66 return Ok(()); 67 }; 68 let module = Module::new(&engine, wat)?; 69 let mut store = Store::new(&engine, ()); 70 let shared_memory = SharedMemory::new(&engine, MemoryType::shared(1, 1))?; 71 let instance1 = Instance::new(&mut store, &module, &[shared_memory.clone().into()])?; 72 73 let thread = { 74 let engine = engine.clone(); 75 let module = module.clone(); 76 let shared_memory = shared_memory.clone(); 77 std::thread::spawn(move || { 78 let mut store = Store::new(&engine, ()); 79 let instance2 = Instance::new(&mut store, &module, &[shared_memory.into()]).unwrap(); 80 81 let instance2_first_word = instance2 82 .get_typed_func::<(), i32>(&mut store, "second_thread") 83 .unwrap() 84 .call(&mut store, ()) 85 .unwrap(); 86 87 assert_eq!(instance2_first_word, 42); 88 }) 89 }; 90 91 let instance1_first_word = instance1 92 .get_typed_func::<(), i32>(&mut store, "first_thread") 93 .unwrap() 94 .call(&mut store, ()) 95 .unwrap(); 96 assert_eq!(instance1_first_word, 42); 97 98 thread.join().unwrap(); 99 100 let data = shared_memory.data(); 101 // Verify that the memory is the same in all shared locations. 102 let shared_memory_first_word = i32::from_le_bytes(unsafe { 103 [ 104 *data[0].get(), 105 *data[1].get(), 106 *data[2].get(), 107 *data[3].get(), 108 ] 109 }); 110 assert_eq!(shared_memory_first_word, 42); 111 112 let shared_memory_second_word = i32::from_le_bytes(unsafe { 113 [ 114 *data[4].get(), 115 *data[5].get(), 116 *data[6].get(), 117 *data[7].get(), 118 ] 119 }); 120 assert_eq!(shared_memory_second_word, 21); 121 Ok(()) 122 } 123