1 #![cfg(not(miri))]
2
3 use crate::threads::engine;
4 use std::time::Instant;
5 use wasmtime::*;
6
7 #[test]
atomic_wait_timeout_length() -> Result<()>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]
atomic_wait_notify_basic() -> Result<()>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