github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/integration_test/engine/testdata/threads/mutex.wat (about) 1 (module 2 (memory 1 1 shared) 3 4 (func $tryLockMutex32 5 (param $mutexAddr i32) (result i32) 6 ;; Attempt to grab the mutex. The cmpxchg operation atomically 7 ;; does the following: 8 ;; - Loads the value at $mutexAddr. 9 ;; - If it is 0 (unlocked), set it to 1 (locked). 10 ;; - Return the originally loaded value. 11 (i32.atomic.rmw.cmpxchg 12 (local.get $mutexAddr) ;; mutex address 13 (i32.const 0) ;; expected value (0 => unlocked) 14 (i32.const 1)) ;; replacement value (1 => locked) 15 16 ;; The top of the stack is the originally loaded value. 17 ;; If it is 0, this means we acquired the mutex. We want to 18 ;; return the inverse (1 means mutex acquired), so use i32.eqz 19 ;; as a logical not. 20 (i32.eqz) 21 ) 22 23 ;; Lock a mutex at the given address, retrying until successful. 24 (func $lockMutex32 25 (param $mutexAddr i32) 26 (block $done 27 (loop $retry 28 ;; Try to lock the mutex. $tryLockMutex returns 1 if the mutex 29 ;; was locked, and 0 otherwise. 30 (call $tryLockMutex32 (local.get $mutexAddr)) 31 (br_if $done) 32 33 ;; Wait for the other agent to finish with mutex. 34 (memory.atomic.wait32 35 (local.get $mutexAddr) ;; mutex address 36 (i32.const 1) ;; expected value (1 => locked) 37 (i64.const -1)) ;; infinite timeout 38 39 ;; memory.atomic.wait32 returns: 40 ;; 0 => "ok", woken by another agent. 41 ;; 1 => "not-equal", loaded value != expected value 42 ;; 2 => "timed-out", the timeout expired 43 ;; 44 ;; Since there is an infinite timeout, only 0 or 1 will be returned. In 45 ;; either case we should try to acquire the mutex again, so we can 46 ;; ignore the result. 47 (drop) 48 49 ;; Try to acquire the lock again. 50 (br $retry) 51 ) 52 ) 53 ) 54 55 ;; Unlock a mutex at the given address. 56 (func $unlockMutex32 57 (param $mutexAddr i32) 58 ;; Unlock the mutex. 59 (i32.atomic.store 60 (local.get $mutexAddr) ;; mutex address 61 (i32.const 0)) ;; 0 => unlocked 62 63 ;; Notify one agent that is waiting on this lock. 64 (drop 65 (memory.atomic.notify 66 (local.get $mutexAddr) ;; mutex address 67 (i32.const 1))) ;; notify 1 waiter 68 ) 69 70 (func (export "run32") 71 (call $lockMutex32 (i32.const 0)) 72 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 73 (call $unlockMutex32 (i32.const 0)) 74 ) 75 76 ;; Below functions are the same as above with different integer sizes so 77 ;; have comments elided see above to understand logic. 78 79 (func $tryLockMutex64 80 (param $mutexAddr i32) (result i32) 81 (i64.atomic.rmw.cmpxchg 82 (local.get $mutexAddr) 83 (i64.const 0) 84 (i64.const 1)) 85 (i64.eqz) 86 ) 87 (func $lockMutex64 88 (param $mutexAddr i32) 89 (block $done 90 (loop $retry 91 (call $tryLockMutex64 (local.get $mutexAddr)) 92 (br_if $done) 93 (memory.atomic.wait64 94 (local.get $mutexAddr) 95 (i64.const 1) 96 (i64.const -1)) 97 (drop) 98 (br $retry) 99 ) 100 ) 101 ) 102 (func $unlockMutex64 103 (param $mutexAddr i32) 104 (i64.atomic.store 105 (local.get $mutexAddr) 106 (i64.const 0)) 107 (drop 108 (memory.atomic.notify 109 (local.get $mutexAddr) 110 (i32.const 1))) 111 ) 112 (func (export "run64") 113 (call $lockMutex64 (i32.const 0)) 114 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 115 (call $unlockMutex64 (i32.const 0)) 116 ) 117 118 (func $tryLockMutex32_8 119 (param $mutexAddr i32) (result i32) 120 (i32.atomic.rmw8.cmpxchg_u 121 (local.get $mutexAddr) 122 (i32.const 0) 123 (i32.const 1)) 124 (i32.eqz) 125 ) 126 (func $lockMutex32_8 127 (param $mutexAddr i32) 128 (block $done 129 (loop $retry 130 (call $tryLockMutex32_8 (local.get $mutexAddr)) 131 (br_if $done) 132 (memory.atomic.wait32 133 (local.get $mutexAddr) 134 (i32.const 1) 135 (i64.const -1)) 136 (drop) 137 (br $retry) 138 ) 139 ) 140 ) 141 (func $unlockMutex32_8 142 (param $mutexAddr i32) 143 (i32.atomic.store8 144 (local.get $mutexAddr) 145 (i32.const 0)) 146 (drop 147 (memory.atomic.notify 148 (local.get $mutexAddr) 149 (i32.const 1))) 150 ) 151 (func (export "run32_8") 152 (call $lockMutex32_8 (i32.const 0)) 153 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 154 (call $unlockMutex32_8 (i32.const 0)) 155 ) 156 157 (func $tryLockMutex32_16 158 (param $mutexAddr i32) (result i32) 159 (i32.atomic.rmw16.cmpxchg_u 160 (local.get $mutexAddr) 161 (i32.const 0) 162 (i32.const 1)) 163 (i32.eqz) 164 ) 165 (func $lockMutex32_16 166 (param $mutexAddr i32) 167 (block $done 168 (loop $retry 169 (call $tryLockMutex32_16 (local.get $mutexAddr)) 170 (br_if $done) 171 (memory.atomic.wait32 172 (local.get $mutexAddr) 173 (i32.const 1) 174 (i64.const -1)) 175 (drop) 176 (br $retry) 177 ) 178 ) 179 ) 180 (func $unlockMutex32_16 181 (param $mutexAddr i32) 182 (i32.atomic.store16 183 (local.get $mutexAddr) 184 (i32.const 0)) 185 (drop 186 (memory.atomic.notify 187 (local.get $mutexAddr) 188 (i32.const 1))) 189 ) 190 (func (export "run32_16") 191 (call $lockMutex32_16 (i32.const 0)) 192 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 193 (call $unlockMutex32_16 (i32.const 0)) 194 ) 195 196 (func $tryLockMutex64_8 197 (param $mutexAddr i32) (result i32) 198 (i64.atomic.rmw8.cmpxchg_u 199 (local.get $mutexAddr) 200 (i64.const 0) 201 (i64.const 1)) 202 (i64.eqz) 203 ) 204 (func $lockMutex64_8 205 (param $mutexAddr i32) 206 (block $done 207 (loop $retry 208 (call $tryLockMutex64_8 (local.get $mutexAddr)) 209 (br_if $done) 210 (memory.atomic.wait64 211 (local.get $mutexAddr) 212 (i64.const 1) 213 (i64.const -1)) 214 (drop) 215 (br $retry) 216 ) 217 ) 218 ) 219 (func $unlockMutex64_8 220 (param $mutexAddr i32) 221 (i64.atomic.store8 222 (local.get $mutexAddr) 223 (i64.const 0)) 224 (drop 225 (memory.atomic.notify 226 (local.get $mutexAddr) 227 (i32.const 1))) 228 ) 229 (func (export "run64_8") 230 (call $lockMutex64_8 (i32.const 0)) 231 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 232 (call $unlockMutex64_8 (i32.const 0)) 233 ) 234 235 (func $tryLockMutex64_16 236 (param $mutexAddr i32) (result i32) 237 (i64.atomic.rmw16.cmpxchg_u 238 (local.get $mutexAddr) 239 (i64.const 0) 240 (i64.const 1)) 241 (i64.eqz) 242 ) 243 (func $lockMutex64_16 244 (param $mutexAddr i32) 245 (block $done 246 (loop $retry 247 (call $tryLockMutex64_16 (local.get $mutexAddr)) 248 (br_if $done) 249 (memory.atomic.wait64 250 (local.get $mutexAddr) 251 (i64.const 1) 252 (i64.const -1)) 253 (drop) 254 (br $retry) 255 ) 256 ) 257 ) 258 (func $unlockMutex64_16 259 (param $mutexAddr i32) 260 (i64.atomic.store16 261 (local.get $mutexAddr) 262 (i64.const 0)) 263 (drop 264 (memory.atomic.notify 265 (local.get $mutexAddr) 266 (i32.const 1))) 267 ) 268 (func (export "run64_16") 269 (call $lockMutex64_16 (i32.const 0)) 270 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 271 (call $unlockMutex64_16 (i32.const 0)) 272 ) 273 274 (func $tryLockMutex64_32 275 (param $mutexAddr i32) (result i32) 276 (i64.atomic.rmw32.cmpxchg_u 277 (local.get $mutexAddr) 278 (i64.const 0) 279 (i64.const 1)) 280 (i64.eqz) 281 ) 282 (func $lockMutex64_32 283 (param $mutexAddr i32) 284 (block $done 285 (loop $retry 286 (call $tryLockMutex64_32 (local.get $mutexAddr)) 287 (br_if $done) 288 (memory.atomic.wait64 289 (local.get $mutexAddr) 290 (i64.const 1) 291 (i64.const -1)) 292 (drop) 293 (br $retry) 294 ) 295 ) 296 ) 297 (func $unlockMutex64_32 298 (param $mutexAddr i32) 299 (i64.atomic.store32 300 (local.get $mutexAddr) 301 (i64.const 0)) 302 (drop 303 (memory.atomic.notify 304 (local.get $mutexAddr) 305 (i32.const 1))) 306 ) 307 (func (export "run64_32") 308 (call $lockMutex64_32 (i32.const 0)) 309 (i32.store (i32.const 8) (i32.load (i32.const 8)) (i32.add (i32.const 1))) 310 (call $unlockMutex64_32 (i32.const 0)) 311 ) 312 )