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  )