Skip to content

Commit cd03664

Browse files
committed
runtime: fix js/wasm lock implementation
Trybots started failing on js/wasm after golang.org/cl/175797 landed, but it seemed completely unrelated. It would fail very consistently on the heapsampling.go test. Digging deeper it was very difficult to ascertain what was going wrong, but clearly m.locks for some m was non-zero when calling into the scheduler. The failure comes from the fact that lock calls into gosched, but it's unclear how exactly we got there in the first place; there should be no preemption in this single-threaded context. Furthermore, lock shouldn't be calling gosched_m at all because in a single-threaded context, the thread shouldn't be preempted until it actually unlocks. But, digging further it turns out the implementation in lock_js.go never incremented or decremented m.locks. This is definitely wrong because many parts of the runtime depend on that value being set correctly. So, this change removes the loop which calls into gosched_m (which should be unnecessary) and increments and decrements m.locks appropriately. This appears to fix the aforementioned failure. Change-Id: Id214c0762c3fb2b405ff55543d7e2a78c17443c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/176297 Run-TryBot: Michael Knyszek <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 0a2f72b commit cd03664

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

src/runtime/lock_js.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
)
1212

1313
// js/wasm has no support for threads yet. There is no preemption.
14-
// Waiting for a mutex is implemented by allowing other goroutines
15-
// to run until the mutex gets unlocked.
1614

1715
const (
1816
mutex_unlocked = 0
@@ -28,16 +26,28 @@ const (
2826
)
2927

3028
func lock(l *mutex) {
31-
for l.key == mutex_locked {
32-
mcall(gosched_m)
29+
if l.key == mutex_locked {
30+
// js/wasm is single-threaded so we should never
31+
// observe this.
32+
throw("self deadlock")
3333
}
34+
gp := getg()
35+
if gp.m.locks < 0 {
36+
throw("lock count")
37+
}
38+
gp.m.locks++
3439
l.key = mutex_locked
3540
}
3641

3742
func unlock(l *mutex) {
3843
if l.key == mutex_unlocked {
3944
throw("unlock of unlocked lock")
4045
}
46+
gp := getg()
47+
gp.m.locks--
48+
if gp.m.locks < 0 {
49+
throw("lock count")
50+
}
4151
l.key = mutex_unlocked
4252
}
4353

0 commit comments

Comments
 (0)