github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/refs/refcounter.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package refs defines an interface for reference counted objects. It
    16  // also provides a drop-in implementation called AtomicRefCount.
    17  package refs
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  	"runtime"
    24  	"sync/atomic"
    25  
    26  	"github.com/SagerNet/gvisor/pkg/context"
    27  	"github.com/SagerNet/gvisor/pkg/log"
    28  	"github.com/SagerNet/gvisor/pkg/sync"
    29  )
    30  
    31  // RefCounter is the interface to be implemented by objects that are reference
    32  // counted.
    33  //
    34  // TODO(github.com/SagerNet/issue/1624): Get rid of most of this package and replace it
    35  // with refsvfs2.
    36  type RefCounter interface {
    37  	// IncRef increments the reference counter on the object.
    38  	IncRef()
    39  
    40  	// DecRef decrements the reference counter on the object.
    41  	//
    42  	// Note that AtomicRefCounter.DecRef() does not support destructors.
    43  	// If a type has a destructor, it must implement its own DecRef()
    44  	// method and call AtomicRefCounter.DecRefWithDestructor(destructor).
    45  	DecRef(ctx context.Context)
    46  
    47  	// TryIncRef attempts to increase the reference counter on the object,
    48  	// but may fail if all references have already been dropped. This
    49  	// should be used only in special circumstances, such as WeakRefs.
    50  	TryIncRef() bool
    51  
    52  	// addWeakRef adds the given weak reference. Note that you should have a
    53  	// reference to the object when calling this method.
    54  	addWeakRef(*WeakRef)
    55  
    56  	// dropWeakRef drops the given weak reference. Note that you should have
    57  	// a reference to the object when calling this method.
    58  	dropWeakRef(*WeakRef)
    59  }
    60  
    61  // A WeakRefUser is notified when the last non-weak reference is dropped.
    62  type WeakRefUser interface {
    63  	// WeakRefGone is called when the last non-weak reference is dropped.
    64  	WeakRefGone(ctx context.Context)
    65  }
    66  
    67  // WeakRef is a weak reference.
    68  //
    69  // +stateify savable
    70  type WeakRef struct {
    71  	weakRefEntry `state:"nosave"`
    72  
    73  	// obj is an atomic value that points to the refCounter.
    74  	obj atomic.Value `state:".(savedReference)"`
    75  
    76  	// user is notified when the weak ref is zapped by the object getting
    77  	// destroyed.
    78  	user WeakRefUser
    79  }
    80  
    81  // weakRefPool is a pool of weak references to avoid allocations on the hot path.
    82  var weakRefPool = sync.Pool{
    83  	New: func() interface{} {
    84  		return &WeakRef{}
    85  	},
    86  }
    87  
    88  // NewWeakRef acquires a weak reference for the given object.
    89  //
    90  // An optional user will be notified when the last non-weak reference is
    91  // dropped.
    92  //
    93  // Note that you must hold a reference to the object prior to getting a weak
    94  // reference. (But you may drop the non-weak reference after that.)
    95  func NewWeakRef(rc RefCounter, u WeakRefUser) *WeakRef {
    96  	w := weakRefPool.Get().(*WeakRef)
    97  	w.init(rc, u)
    98  	return w
    99  }
   100  
   101  // get attempts to get a normal reference to the underlying object, and returns
   102  // the object. If this weak reference has already been zapped (the object has
   103  // been destroyed) then false is returned. If the object still exists, then
   104  // true is returned.
   105  func (w *WeakRef) get() (RefCounter, bool) {
   106  	rc := w.obj.Load().(RefCounter)
   107  	if v := reflect.ValueOf(rc); v == reflect.Zero(v.Type()) {
   108  		// This pointer has already been zapped by zap() below. We do
   109  		// this to ensure that the GC can collect the underlying
   110  		// RefCounter objects and they don't hog resources.
   111  		return nil, false
   112  	}
   113  	if !rc.TryIncRef() {
   114  		return nil, true
   115  	}
   116  	return rc, true
   117  }
   118  
   119  // Get attempts to get a normal reference to the underlying object, and returns
   120  // the object. If this fails (the object no longer exists), then nil will be
   121  // returned instead.
   122  func (w *WeakRef) Get() RefCounter {
   123  	rc, _ := w.get()
   124  	return rc
   125  }
   126  
   127  // Drop drops this weak reference. You should always call drop when you are
   128  // finished with the weak reference. You may not use this object after calling
   129  // drop.
   130  func (w *WeakRef) Drop(ctx context.Context) {
   131  	rc, ok := w.get()
   132  	if !ok {
   133  		// We've been zapped already. When the refcounter has called
   134  		// zap, we're guaranteed it's not holding references.
   135  		weakRefPool.Put(w)
   136  		return
   137  	}
   138  	if rc == nil {
   139  		// The object is in the process of being destroyed. We can't
   140  		// remove this from the object's list, nor can we return this
   141  		// object to the pool. It'll just be garbage collected. This is
   142  		// a rare edge case, so it's not a big deal.
   143  		return
   144  	}
   145  
   146  	// At this point, we have a reference on the object. So destruction
   147  	// of the object (and zapping this weak reference) can't race here.
   148  	rc.dropWeakRef(w)
   149  
   150  	// And now aren't on the object's list of weak references. So it won't
   151  	// zap us if this causes the reference count to drop to zero.
   152  	rc.DecRef(ctx)
   153  
   154  	// Return to the pool.
   155  	weakRefPool.Put(w)
   156  }
   157  
   158  // init initializes this weak reference.
   159  func (w *WeakRef) init(rc RefCounter, u WeakRefUser) {
   160  	// Reset the contents of the weak reference.
   161  	// This is important because we are reseting the atomic value type.
   162  	// Otherwise, we could panic here if obj is different than what it was
   163  	// the last time this was used.
   164  	*w = WeakRef{}
   165  	w.user = u
   166  	w.obj.Store(rc)
   167  
   168  	// In the load path, we may already have a nil value. So we need to
   169  	// check whether or not that is the case before calling addWeakRef.
   170  	if v := reflect.ValueOf(rc); v != reflect.Zero(v.Type()) {
   171  		rc.addWeakRef(w)
   172  	}
   173  }
   174  
   175  // zap zaps this weak reference.
   176  func (w *WeakRef) zap() {
   177  	// We need to be careful about types here.
   178  	// So reflect is involved. But it's not that bad.
   179  	rc := w.obj.Load()
   180  	typ := reflect.TypeOf(rc)
   181  	w.obj.Store(reflect.Zero(typ).Interface())
   182  }
   183  
   184  // AtomicRefCount keeps a reference count using atomic operations and calls the
   185  // destructor when the count reaches zero.
   186  //
   187  // Do not use AtomicRefCount for new ref-counted objects! It is deprecated in
   188  // favor of the refsvfs2 package.
   189  //
   190  // N.B. To allow the zero-object to be initialized, the count is offset by
   191  //      1, that is, when refCount is n, there are really n+1 references.
   192  //
   193  // +stateify savable
   194  type AtomicRefCount struct {
   195  	// refCount is composed of two fields:
   196  	//
   197  	//	[32-bit speculative references]:[32-bit real references]
   198  	//
   199  	// Speculative references are used for TryIncRef, to avoid a
   200  	// CompareAndSwap loop. See IncRef, DecRef and TryIncRef for details of
   201  	// how these fields are used.
   202  	refCount int64
   203  
   204  	// name is the name of the type which owns this ref count.
   205  	//
   206  	// name is immutable after EnableLeakCheck is called.
   207  	name string
   208  
   209  	// stack optionally records the caller of EnableLeakCheck.
   210  	//
   211  	// stack is immutable after EnableLeakCheck is called.
   212  	stack []uintptr
   213  
   214  	// mu protects the list below.
   215  	mu sync.Mutex `state:"nosave"`
   216  
   217  	// weakRefs is our collection of weak references.
   218  	weakRefs weakRefList `state:"nosave"`
   219  }
   220  
   221  // LeakMode configures the leak checker.
   222  type LeakMode uint32
   223  
   224  // TODO(github.com/SagerNet/issue/1624): Simplify down to two modes (on/off) once vfs1
   225  // ref counting is gone.
   226  const (
   227  	// UninitializedLeakChecking indicates that the leak checker has not yet been initialized.
   228  	UninitializedLeakChecking LeakMode = iota
   229  
   230  	// NoLeakChecking indicates that no effort should be made to check for
   231  	// leaks.
   232  	NoLeakChecking
   233  
   234  	// LeaksLogWarning indicates that a warning should be logged when leaks
   235  	// are found.
   236  	LeaksLogWarning
   237  
   238  	// LeaksLogTraces indicates that a trace collected during allocation
   239  	// should be logged when leaks are found.
   240  	LeaksLogTraces
   241  )
   242  
   243  // Set implements flag.Value.
   244  func (l *LeakMode) Set(v string) error {
   245  	switch v {
   246  	case "disabled":
   247  		*l = NoLeakChecking
   248  	case "log-names":
   249  		*l = LeaksLogWarning
   250  	case "log-traces":
   251  		*l = LeaksLogTraces
   252  	default:
   253  		return fmt.Errorf("invalid ref leak mode %q", v)
   254  	}
   255  	return nil
   256  }
   257  
   258  // Get implements flag.Value.
   259  func (l *LeakMode) Get() interface{} {
   260  	return *l
   261  }
   262  
   263  // String implements flag.Value.
   264  func (l LeakMode) String() string {
   265  	switch l {
   266  	case UninitializedLeakChecking:
   267  		return "uninitialized"
   268  	case NoLeakChecking:
   269  		return "disabled"
   270  	case LeaksLogWarning:
   271  		return "log-names"
   272  	case LeaksLogTraces:
   273  		return "log-traces"
   274  	}
   275  	panic(fmt.Sprintf("invalid ref leak mode %d", l))
   276  }
   277  
   278  // leakMode stores the current mode for the reference leak checker.
   279  //
   280  // Values must be one of the LeakMode values.
   281  //
   282  // leakMode must be accessed atomically.
   283  var leakMode uint32
   284  
   285  // SetLeakMode configures the reference leak checker.
   286  func SetLeakMode(mode LeakMode) {
   287  	atomic.StoreUint32(&leakMode, uint32(mode))
   288  }
   289  
   290  // GetLeakMode returns the current leak mode.
   291  func GetLeakMode() LeakMode {
   292  	return LeakMode(atomic.LoadUint32(&leakMode))
   293  }
   294  
   295  const maxStackFrames = 40
   296  
   297  type fileLine struct {
   298  	file string
   299  	line int
   300  }
   301  
   302  // A stackKey is a representation of a stack frame for use as a map key.
   303  //
   304  // The fileLine type is used as PC values seem to vary across collections, even
   305  // for the same call stack.
   306  type stackKey [maxStackFrames]fileLine
   307  
   308  var stackCache = struct {
   309  	sync.Mutex
   310  	entries map[stackKey][]uintptr
   311  }{entries: map[stackKey][]uintptr{}}
   312  
   313  func makeStackKey(pcs []uintptr) stackKey {
   314  	frames := runtime.CallersFrames(pcs)
   315  	var key stackKey
   316  	keySlice := key[:0]
   317  	for {
   318  		frame, more := frames.Next()
   319  		keySlice = append(keySlice, fileLine{frame.File, frame.Line})
   320  
   321  		if !more || len(keySlice) == len(key) {
   322  			break
   323  		}
   324  	}
   325  	return key
   326  }
   327  
   328  // RecordStack constructs and returns the PCs on the current stack.
   329  func RecordStack() []uintptr {
   330  	pcs := make([]uintptr, maxStackFrames)
   331  	n := runtime.Callers(1, pcs)
   332  	if n == 0 {
   333  		// No pcs available. Stop now.
   334  		//
   335  		// This can happen if the first argument to runtime.Callers
   336  		// is large.
   337  		return nil
   338  	}
   339  	pcs = pcs[:n]
   340  	key := makeStackKey(pcs)
   341  	stackCache.Lock()
   342  	v, ok := stackCache.entries[key]
   343  	if !ok {
   344  		// Reallocate to prevent pcs from escaping.
   345  		v = append([]uintptr(nil), pcs...)
   346  		stackCache.entries[key] = v
   347  	}
   348  	stackCache.Unlock()
   349  	return v
   350  }
   351  
   352  // FormatStack converts the given stack into a readable format.
   353  func FormatStack(pcs []uintptr) string {
   354  	frames := runtime.CallersFrames(pcs)
   355  	var trace bytes.Buffer
   356  	for {
   357  		frame, more := frames.Next()
   358  		fmt.Fprintf(&trace, "%s:%d: %s\n", frame.File, frame.Line, frame.Function)
   359  
   360  		if !more {
   361  			break
   362  		}
   363  	}
   364  	return trace.String()
   365  }
   366  
   367  func (r *AtomicRefCount) finalize() {
   368  	var note string
   369  	switch LeakMode(atomic.LoadUint32(&leakMode)) {
   370  	case NoLeakChecking:
   371  		return
   372  	case UninitializedLeakChecking:
   373  		note = "(Leak checker uninitialized): "
   374  	}
   375  	if n := r.ReadRefs(); n != 0 {
   376  		msg := fmt.Sprintf("%sAtomicRefCount %p owned by %q garbage collected with ref count of %d (want 0)", note, r, r.name, n)
   377  		if len(r.stack) != 0 {
   378  			msg += ":\nCaller:\n" + FormatStack(r.stack)
   379  		} else {
   380  			msg += " (enable trace logging to debug)"
   381  		}
   382  		log.Warningf(msg)
   383  	}
   384  }
   385  
   386  // EnableLeakCheck checks for reference leaks when the AtomicRefCount gets
   387  // garbage collected.
   388  //
   389  // This function adds a finalizer to the AtomicRefCount, so the AtomicRefCount
   390  // must be at the beginning of its parent.
   391  //
   392  // name is a friendly name that will be listed as the owner of the
   393  // AtomicRefCount in logs. It should be the name of the parent type, including
   394  // package.
   395  func (r *AtomicRefCount) EnableLeakCheck(name string) {
   396  	if name == "" {
   397  		panic("invalid name")
   398  	}
   399  	switch LeakMode(atomic.LoadUint32(&leakMode)) {
   400  	case NoLeakChecking:
   401  		return
   402  	case LeaksLogTraces:
   403  		r.stack = RecordStack()
   404  	}
   405  	r.name = name
   406  	runtime.SetFinalizer(r, (*AtomicRefCount).finalize)
   407  }
   408  
   409  // ReadRefs returns the current number of references. The returned count is
   410  // inherently racy and is unsafe to use without external synchronization.
   411  func (r *AtomicRefCount) ReadRefs() int64 {
   412  	// Account for the internal -1 offset on refcounts.
   413  	return atomic.LoadInt64(&r.refCount) + 1
   414  }
   415  
   416  // IncRef increments this object's reference count. While the count is kept
   417  // greater than zero, the destructor doesn't get called.
   418  //
   419  // The sanity check here is limited to real references, since if they have
   420  // dropped beneath zero then the object should have been destroyed.
   421  //
   422  //go:nosplit
   423  func (r *AtomicRefCount) IncRef() {
   424  	if v := atomic.AddInt64(&r.refCount, 1); v <= 0 {
   425  		panic("Incrementing non-positive ref count")
   426  	}
   427  }
   428  
   429  // TryIncRef attempts to increment the reference count, *unless the count has
   430  // already reached zero*. If false is returned, then the object has already
   431  // been destroyed, and the weak reference is no longer valid. If true if
   432  // returned then a valid reference is now held on the object.
   433  //
   434  // To do this safely without a loop, a speculative reference is first acquired
   435  // on the object. This allows multiple concurrent TryIncRef calls to
   436  // distinguish other TryIncRef calls from genuine references held.
   437  //
   438  //go:nosplit
   439  func (r *AtomicRefCount) TryIncRef() bool {
   440  	const speculativeRef = 1 << 32
   441  	v := atomic.AddInt64(&r.refCount, speculativeRef)
   442  	if int32(v) < 0 {
   443  		// This object has already been freed.
   444  		atomic.AddInt64(&r.refCount, -speculativeRef)
   445  		return false
   446  	}
   447  
   448  	// Turn into a real reference.
   449  	atomic.AddInt64(&r.refCount, -speculativeRef+1)
   450  	return true
   451  }
   452  
   453  // addWeakRef adds the given weak reference.
   454  func (r *AtomicRefCount) addWeakRef(w *WeakRef) {
   455  	r.mu.Lock()
   456  	r.weakRefs.PushBack(w)
   457  	r.mu.Unlock()
   458  }
   459  
   460  // dropWeakRef drops the given weak reference.
   461  func (r *AtomicRefCount) dropWeakRef(w *WeakRef) {
   462  	r.mu.Lock()
   463  	r.weakRefs.Remove(w)
   464  	r.mu.Unlock()
   465  }
   466  
   467  // DecRefWithDestructor decrements the object's reference count. If the
   468  // resulting count is negative and the destructor is not nil, then the
   469  // destructor will be called.
   470  //
   471  // Note that speculative references are counted here. Since they were added
   472  // prior to real references reaching zero, they will successfully convert to
   473  // real references. In other words, we see speculative references only in the
   474  // following case:
   475  //
   476  //	A: TryIncRef [speculative increase => sees non-negative references]
   477  //	B: DecRef [real decrease]
   478  //	A: TryIncRef [transform speculative to real]
   479  //
   480  //go:nosplit
   481  func (r *AtomicRefCount) DecRefWithDestructor(ctx context.Context, destroy func(context.Context)) {
   482  	switch v := atomic.AddInt64(&r.refCount, -1); {
   483  	case v < -1:
   484  		panic("Decrementing non-positive ref count")
   485  
   486  	case v == -1:
   487  		// Zap weak references. Note that at this point, all weak
   488  		// references are already invalid. That is, TryIncRef() will
   489  		// return false due to the reference count check.
   490  		r.mu.Lock()
   491  		for !r.weakRefs.Empty() {
   492  			w := r.weakRefs.Front()
   493  			// Capture the callback because w cannot be touched
   494  			// after it's zapped -- the owner is free it reuse it
   495  			// after that.
   496  			user := w.user
   497  			r.weakRefs.Remove(w)
   498  			w.zap()
   499  
   500  			if user != nil {
   501  				r.mu.Unlock()
   502  				user.WeakRefGone(ctx)
   503  				r.mu.Lock()
   504  			}
   505  		}
   506  		r.mu.Unlock()
   507  
   508  		// Call the destructor.
   509  		if destroy != nil {
   510  			destroy(ctx)
   511  		}
   512  	}
   513  }
   514  
   515  // DecRef decrements this object's reference count.
   516  //
   517  //go:nosplit
   518  func (r *AtomicRefCount) DecRef(ctx context.Context) {
   519  	r.DecRefWithDestructor(ctx, nil)
   520  }
   521  
   522  // OnExit is called on sandbox exit. It runs GC to enqueue refcount finalizers,
   523  // which check for reference leaks. There is no way to guarantee that every
   524  // finalizer will run before exiting, but this at least ensures that they will
   525  // be discovered/enqueued by GC.
   526  func OnExit() {
   527  	if LeakMode(atomic.LoadUint32(&leakMode)) != NoLeakChecking {
   528  		runtime.GC()
   529  	}
   530  }