mutexWMask = (1<<20 - 1) << 43
)
+const overflowMsg = "too many concurrent operations on a single file or socket (max 1048575)"
+
// Read operations must do rwlock(true)/rwunlock(true).
//
// Write operations must do rwlock(false)/rwunlock(false).
}
new := old + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
if atomic.CompareAndSwapUint64(&mu.state, old, new) {
return true
// Mark as closed and acquire a reference.
new := (old | mutexClosed) + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
// Remove all read and write waiters.
new &^= mutexRMask | mutexWMask
// Lock is free, acquire it.
new = (old | mutexBit) + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
} else {
// Wait for lock.
new = old + mutexWait
if new&mutexMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
}
if atomic.CompareAndSwapUint64(&mu.state, old, new) {
. "internal/poll"
"math/rand"
"runtime"
+ "strings"
"testing"
"time"
)
mu.RWUnlock(false)
}
+func TestMutexOverflowPanic(t *testing.T) {
+ defer func() {
+ r := recover()
+ if r == nil {
+ t.Fatal("did not panic")
+ }
+ msg, ok := r.(string)
+ if !ok {
+ t.Fatalf("unexpected panic type %T", r)
+ }
+ if !strings.Contains(msg, "too many") || strings.Contains(msg, "inconsistent") {
+ t.Fatalf("wrong panic message %q", msg)
+ }
+ }()
+
+ var mu1 FDMutex
+ for i := 0; i < 1<<21; i++ {
+ mu1.Incref()
+ }
+}
+
func TestMutexStress(t *testing.T) {
P := 8
N := int(1e6)