You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
sync: RWMutex can deadlock when readers queue behind a writer #5692
Concurrent process and pipe creation stopped in my CLI tests. Both use syscall.ForkLock, which is a sync.RWMutex.
A reader holds the lock. A writer waits, then another reader queues. When the first reader unlocks, the writer can remain blocked. A second failure can lose a reader wakeup during lock handover.
On 2 September 2026, the tests in #5630 reproduced this with TinyGo v0.42.0 on Linux/arm64 and Darwin/arm64. TestRWMutexWriterNotStarvedByLateReaders failed after 10 seconds. The lock should let the waiting writer and readers finish.
Regression tests are in #5630. Copy them into src/sync and run tinygo test -run TestRWMutex sync.
Source checked on 18 September 2026. The affected code is unchanged in dev at 93940cb6. #5630 was closed on 17 September with a request for this issue.
@deadprogram The original failure was in CLI tests that created processes and pipes at the same time. The tests stopped making progress. The shared lock was syscall.ForkLock, which uses sync.RWMutex.
Here is a small standalone version of TestRWMutexWriterNotStarvedByLateReaders. It removes the process and pipe code and keeps the lock sequence that caused the failure:
package main
import (
"fmt""sync""time"
)
funcmain() {
varmu sync.RWMutexwriterDone:=make(chanstruct{})
readerDone:=make(chanstruct{})
mu.RLock()
gofunc() {
mu.Lock()
mu.Unlock()
close(writerDone)
}()
time.Sleep(50*time.Millisecond)
gofunc() {
mu.RLock()
mu.RUnlock()
close(readerDone)
}()
time.Sleep(50*time.Millisecond)
mu.RUnlock()
select {
case<-writerDone:
case<-time.After(10*time.Second):
panic("writer did not finish after the first reader unlocked")
}
select {
case<-readerDone:
case<-time.After(10*time.Second):
panic("queued reader did not finish")
}
fmt.Println("ok")
}
Save this as main.go and run tinygo run main.go. The expected result is ok. The sleeps give the writer and second reader time to enter their lock calls, so this reproducer depends on scheduling.
In the affected implementation, the second reader increases the reader count before it waits for the writer. When the first reader unlocks, the count still includes that waiting reader. This prevents the writer wakeup. The writer and second reader then wait for each other.
The regression test reproduced the failure with TinyGo v0.42.0 on Linux/arm64 and Darwin/arm64 on 2 September, as recorded above. I have not rerun this standalone version. The same test is included in #5697.
Activity
deadprogram commentedon Sep 19, 2026
What was the original problem in one of your projects that triggered this @yohimik ? Perhaps a single simple reproducer, if you please?
yohimik commentedon Sep 20, 2026
@deadprogram The original failure was in CLI tests that created processes and pipes at the same time. The tests stopped making progress. The shared lock was
syscall.ForkLock, which usessync.RWMutex.Here is a small standalone version of
TestRWMutexWriterNotStarvedByLateReaders. It removes the process and pipe code and keeps the lock sequence that caused the failure:Save this as
main.goand runtinygo run main.go. The expected result isok. The sleeps give the writer and second reader time to enter their lock calls, so this reproducer depends on scheduling.In the affected implementation, the second reader increases the reader count before it waits for the writer. When the first reader unlocks, the count still includes that waiting reader. This prevents the writer wakeup. The writer and second reader then wait for each other.
The regression test reproduced the failure with TinyGo v0.42.0 on Linux/arm64 and Darwin/arm64 on 2 September, as recorded above. I have not rerun this standalone version. The same test is included in #5697.
deadprogram commentedon Sep 22, 2026
Handled in #5697 labeling to close on next release.
ci: TinyGo