mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Plumbing context.Context to DecRef() and Release().
context is passed to DecRef() and Release() which is needed for SO_LINGER implementation. PiperOrigin-RevId: 324672584
This commit is contained in:
committed by
gVisor bot
parent
ef11bb936b
commit
b2ae7ea1bb
@@ -51,6 +51,7 @@ go_test(
|
||||
srcs = ["futex_test.go"],
|
||||
library = ":futex",
|
||||
deps = [
|
||||
"//pkg/context",
|
||||
"//pkg/sync",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
|
||||
@@ -19,6 +19,7 @@ package futex
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
@@ -66,9 +67,9 @@ type Key struct {
|
||||
Offset uint64
|
||||
}
|
||||
|
||||
func (k *Key) release() {
|
||||
func (k *Key) release(t Target) {
|
||||
if k.MappingIdentity != nil {
|
||||
k.MappingIdentity.DecRef()
|
||||
k.MappingIdentity.DecRef(t)
|
||||
}
|
||||
k.Mappable = nil
|
||||
k.MappingIdentity = nil
|
||||
@@ -94,6 +95,8 @@ func (k *Key) matches(k2 *Key) bool {
|
||||
|
||||
// Target abstracts memory accesses and keys.
|
||||
type Target interface {
|
||||
context.Context
|
||||
|
||||
// SwapUint32 gives access to usermem.IO.SwapUint32.
|
||||
SwapUint32(addr usermem.Addr, new uint32) (uint32, error)
|
||||
|
||||
@@ -296,7 +299,7 @@ func (b *bucket) wakeWaiterLocked(w *Waiter) {
|
||||
// bucket "to".
|
||||
//
|
||||
// Preconditions: b and to must be locked.
|
||||
func (b *bucket) requeueLocked(to *bucket, key, nkey *Key, n int) int {
|
||||
func (b *bucket) requeueLocked(t Target, to *bucket, key, nkey *Key, n int) int {
|
||||
done := 0
|
||||
for w := b.waiters.Front(); done < n && w != nil; {
|
||||
if !w.key.matches(key) {
|
||||
@@ -308,7 +311,7 @@ func (b *bucket) requeueLocked(to *bucket, key, nkey *Key, n int) int {
|
||||
requeued := w
|
||||
w = w.Next() // Next iteration.
|
||||
b.waiters.Remove(requeued)
|
||||
requeued.key.release()
|
||||
requeued.key.release(t)
|
||||
requeued.key = nkey.clone()
|
||||
to.waiters.PushBack(requeued)
|
||||
requeued.bucket.Store(to)
|
||||
@@ -456,7 +459,7 @@ func (m *Manager) Wake(t Target, addr usermem.Addr, private bool, bitmask uint32
|
||||
r := b.wakeLocked(&k, bitmask, n)
|
||||
|
||||
b.mu.Unlock()
|
||||
k.release()
|
||||
k.release(t)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@@ -465,12 +468,12 @@ func (m *Manager) doRequeue(t Target, addr, naddr usermem.Addr, private bool, ch
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer k1.release()
|
||||
defer k1.release(t)
|
||||
k2, err := getKey(t, naddr, private)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer k2.release()
|
||||
defer k2.release(t)
|
||||
|
||||
b1, b2 := m.lockBuckets(&k1, &k2)
|
||||
defer b1.mu.Unlock()
|
||||
@@ -488,7 +491,7 @@ func (m *Manager) doRequeue(t Target, addr, naddr usermem.Addr, private bool, ch
|
||||
done := b1.wakeLocked(&k1, ^uint32(0), nwake)
|
||||
|
||||
// Requeue the number required.
|
||||
b1.requeueLocked(b2, &k1, &k2, nreq)
|
||||
b1.requeueLocked(t, b2, &k1, &k2, nreq)
|
||||
|
||||
return done, nil
|
||||
}
|
||||
@@ -515,12 +518,12 @@ func (m *Manager) WakeOp(t Target, addr1, addr2 usermem.Addr, private bool, nwak
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer k1.release()
|
||||
defer k1.release(t)
|
||||
k2, err := getKey(t, addr2, private)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer k2.release()
|
||||
defer k2.release(t)
|
||||
|
||||
b1, b2 := m.lockBuckets(&k1, &k2)
|
||||
defer b1.mu.Unlock()
|
||||
@@ -571,7 +574,7 @@ func (m *Manager) WaitPrepare(w *Waiter, t Target, addr usermem.Addr, private bo
|
||||
// Perform our atomic check.
|
||||
if err := check(t, addr, val); err != nil {
|
||||
b.mu.Unlock()
|
||||
w.key.release()
|
||||
w.key.release(t)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -585,7 +588,7 @@ func (m *Manager) WaitPrepare(w *Waiter, t Target, addr usermem.Addr, private bo
|
||||
|
||||
// WaitComplete must be called when a Waiter previously added by WaitPrepare is
|
||||
// no longer eligible to be woken.
|
||||
func (m *Manager) WaitComplete(w *Waiter) {
|
||||
func (m *Manager) WaitComplete(w *Waiter, t Target) {
|
||||
// Remove w from the bucket it's in.
|
||||
for {
|
||||
b := w.bucket.Load()
|
||||
@@ -617,7 +620,7 @@ func (m *Manager) WaitComplete(w *Waiter) {
|
||||
}
|
||||
|
||||
// Release references held by the waiter.
|
||||
w.key.release()
|
||||
w.key.release(t)
|
||||
}
|
||||
|
||||
// LockPI attempts to lock the futex following the Priority-inheritance futex
|
||||
@@ -648,13 +651,13 @@ func (m *Manager) LockPI(w *Waiter, t Target, addr usermem.Addr, tid uint32, pri
|
||||
|
||||
success, err := m.lockPILocked(w, t, addr, tid, b, try)
|
||||
if err != nil {
|
||||
w.key.release()
|
||||
w.key.release(t)
|
||||
b.mu.Unlock()
|
||||
return false, err
|
||||
}
|
||||
if success || try {
|
||||
// Release waiter if it's not going to be a wait.
|
||||
w.key.release()
|
||||
w.key.release(t)
|
||||
}
|
||||
b.mu.Unlock()
|
||||
return success, nil
|
||||
@@ -730,7 +733,7 @@ func (m *Manager) UnlockPI(t Target, addr usermem.Addr, tid uint32, private bool
|
||||
|
||||
err = m.unlockPILocked(t, addr, tid, b, &k)
|
||||
|
||||
k.release()
|
||||
k.release(t)
|
||||
b.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
@@ -29,28 +30,33 @@ import (
|
||||
// testData implements the Target interface, and allows us to
|
||||
// treat the address passed for futex operations as an index in
|
||||
// a byte slice for testing simplicity.
|
||||
type testData []byte
|
||||
type testData struct {
|
||||
context.Context
|
||||
data []byte
|
||||
}
|
||||
|
||||
const sizeofInt32 = 4
|
||||
|
||||
func newTestData(size uint) testData {
|
||||
return make([]byte, size)
|
||||
return testData{
|
||||
data: make([]byte, size),
|
||||
}
|
||||
}
|
||||
|
||||
func (t testData) SwapUint32(addr usermem.Addr, new uint32) (uint32, error) {
|
||||
val := atomic.SwapUint32((*uint32)(unsafe.Pointer(&t[addr])), new)
|
||||
val := atomic.SwapUint32((*uint32)(unsafe.Pointer(&t.data[addr])), new)
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (t testData) CompareAndSwapUint32(addr usermem.Addr, old, new uint32) (uint32, error) {
|
||||
if atomic.CompareAndSwapUint32((*uint32)(unsafe.Pointer(&t[addr])), old, new) {
|
||||
if atomic.CompareAndSwapUint32((*uint32)(unsafe.Pointer(&t.data[addr])), old, new) {
|
||||
return old, nil
|
||||
}
|
||||
return atomic.LoadUint32((*uint32)(unsafe.Pointer(&t[addr]))), nil
|
||||
return atomic.LoadUint32((*uint32)(unsafe.Pointer(&t.data[addr]))), nil
|
||||
}
|
||||
|
||||
func (t testData) LoadUint32(addr usermem.Addr) (uint32, error) {
|
||||
return atomic.LoadUint32((*uint32)(unsafe.Pointer(&t[addr]))), nil
|
||||
return atomic.LoadUint32((*uint32)(unsafe.Pointer(&t.data[addr]))), nil
|
||||
}
|
||||
|
||||
func (t testData) GetSharedKey(addr usermem.Addr) (Key, error) {
|
||||
@@ -83,7 +89,7 @@ func TestFutexWake(t *testing.T) {
|
||||
|
||||
// Start waiting for wakeup.
|
||||
w := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w)
|
||||
defer m.WaitComplete(w, d)
|
||||
|
||||
// Perform a wakeup.
|
||||
if n, err := m.Wake(d, 0, private, ^uint32(0), 1); err != nil || n != 1 {
|
||||
@@ -106,7 +112,7 @@ func TestFutexWakeBitmask(t *testing.T) {
|
||||
|
||||
// Start waiting for wakeup.
|
||||
w := newPreparedTestWaiter(t, m, d, 0, private, 0, 0x0000ffff)
|
||||
defer m.WaitComplete(w)
|
||||
defer m.WaitComplete(w, d)
|
||||
|
||||
// Perform a wakeup using the wrong bitmask.
|
||||
if n, err := m.Wake(d, 0, private, 0xffff0000, 1); err != nil || n != 0 {
|
||||
@@ -141,7 +147,7 @@ func TestFutexWakeTwo(t *testing.T) {
|
||||
var ws [3]*Waiter
|
||||
for i := range ws {
|
||||
ws[i] = newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(ws[i])
|
||||
defer m.WaitComplete(ws[i], d)
|
||||
}
|
||||
|
||||
// Perform two wakeups.
|
||||
@@ -174,9 +180,9 @@ func TestFutexWakeUnrelated(t *testing.T) {
|
||||
|
||||
// Start two waiters waiting for wakeup on different addresses.
|
||||
w1 := newPreparedTestWaiter(t, m, d, 0*sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, 1*sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Perform two wakeups on the second address.
|
||||
if n, err := m.Wake(d, 1*sizeofInt32, private, ^uint32(0), 2); err != nil || n != 1 {
|
||||
@@ -216,9 +222,9 @@ func TestWakeOpFirstNonEmpty(t *testing.T) {
|
||||
|
||||
// Add two waiters on address 0.
|
||||
w1 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Perform 10 wakeups on address 0.
|
||||
if n, err := m.WakeOp(d, 0, sizeofInt32, private, 10, 0, 0); err != nil || n != 2 {
|
||||
@@ -244,9 +250,9 @@ func TestWakeOpSecondNonEmpty(t *testing.T) {
|
||||
|
||||
// Add two waiters on address sizeofInt32.
|
||||
w1 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Perform 10 wakeups on address sizeofInt32 (contingent on
|
||||
// d.Op(0), which should succeed).
|
||||
@@ -273,9 +279,9 @@ func TestWakeOpSecondNonEmptyFailingOp(t *testing.T) {
|
||||
|
||||
// Add two waiters on address sizeofInt32.
|
||||
w1 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Perform 10 wakeups on address sizeofInt32 (contingent on
|
||||
// d.Op(1), which should fail).
|
||||
@@ -302,15 +308,15 @@ func TestWakeOpAllNonEmpty(t *testing.T) {
|
||||
|
||||
// Add two waiters on address 0.
|
||||
w1 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Add two waiters on address sizeofInt32.
|
||||
w3 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w3)
|
||||
defer m.WaitComplete(w3, d)
|
||||
w4 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w4)
|
||||
defer m.WaitComplete(w4, d)
|
||||
|
||||
// Perform 10 wakeups on address 0 (unconditionally), and 10
|
||||
// wakeups on address sizeofInt32 (contingent on d.Op(0), which
|
||||
@@ -344,15 +350,15 @@ func TestWakeOpAllNonEmptyFailingOp(t *testing.T) {
|
||||
|
||||
// Add two waiters on address 0.
|
||||
w1 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w1)
|
||||
defer m.WaitComplete(w1, d)
|
||||
w2 := newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w2)
|
||||
defer m.WaitComplete(w2, d)
|
||||
|
||||
// Add two waiters on address sizeofInt32.
|
||||
w3 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w3)
|
||||
defer m.WaitComplete(w3, d)
|
||||
w4 := newPreparedTestWaiter(t, m, d, sizeofInt32, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(w4)
|
||||
defer m.WaitComplete(w4, d)
|
||||
|
||||
// Perform 10 wakeups on address 0 (unconditionally), and 10
|
||||
// wakeups on address sizeofInt32 (contingent on d.Op(1), which
|
||||
@@ -388,7 +394,7 @@ func TestWakeOpSameAddress(t *testing.T) {
|
||||
var ws [4]*Waiter
|
||||
for i := range ws {
|
||||
ws[i] = newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(ws[i])
|
||||
defer m.WaitComplete(ws[i], d)
|
||||
}
|
||||
|
||||
// Perform 1 wakeup on address 0 (unconditionally), and 1 wakeup
|
||||
@@ -422,7 +428,7 @@ func TestWakeOpSameAddressFailingOp(t *testing.T) {
|
||||
var ws [4]*Waiter
|
||||
for i := range ws {
|
||||
ws[i] = newPreparedTestWaiter(t, m, d, 0, private, 0, ^uint32(0))
|
||||
defer m.WaitComplete(ws[i])
|
||||
defer m.WaitComplete(ws[i], d)
|
||||
}
|
||||
|
||||
// Perform 1 wakeup on address 0 (unconditionally), and 1 wakeup
|
||||
@@ -472,7 +478,7 @@ func (t *testMutex) Lock() {
|
||||
for {
|
||||
// Attempt to grab the lock.
|
||||
if atomic.CompareAndSwapUint32(
|
||||
(*uint32)(unsafe.Pointer(&t.d[t.a])),
|
||||
(*uint32)(unsafe.Pointer(&t.d.data[t.a])),
|
||||
testMutexUnlocked,
|
||||
testMutexLocked) {
|
||||
// Lock held.
|
||||
@@ -490,7 +496,7 @@ func (t *testMutex) Lock() {
|
||||
panic("WaitPrepare returned unexpected error: " + err.Error())
|
||||
}
|
||||
<-w.C
|
||||
t.m.WaitComplete(w)
|
||||
t.m.WaitComplete(w, t.d)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +504,7 @@ func (t *testMutex) Lock() {
|
||||
// This will notify any waiters via the futex manager.
|
||||
func (t *testMutex) Unlock() {
|
||||
// Unlock.
|
||||
atomic.StoreUint32((*uint32)(unsafe.Pointer(&t.d[t.a])), testMutexUnlocked)
|
||||
atomic.StoreUint32((*uint32)(unsafe.Pointer(&t.d.data[t.a])), testMutexUnlocked)
|
||||
|
||||
// Notify all waiters.
|
||||
t.m.Wake(t.d, t.a, true, ^uint32(0), math.MaxInt32)
|
||||
|
||||
Reference in New Issue
Block a user