github.com/anacrolix/torrent@v1.61.0/deferrwl.go (about)

     1  package torrent
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	g "github.com/anacrolix/generics"
     8  	"github.com/anacrolix/missinggo/v2/panicif"
     9  	"github.com/anacrolix/sync"
    10  )
    11  
    12  // Runs deferred actions on Unlock. Note that actions are assumed to be the results of changes that
    13  // would only occur with a write lock at present. The race detector should catch instances of defers
    14  // without the write lock being held.
    15  type lockWithDeferreds struct {
    16  	internal      sync.RWMutex
    17  	unlockActions []func()
    18  	uniqueActions map[any]struct{}
    19  	// Currently unlocking, defers should not occur?
    20  	allowDefers bool
    21  	client      *Client
    22  }
    23  
    24  func (me *lockWithDeferreds) Lock() {
    25  	me.internal.Lock()
    26  	panicif.True(me.allowDefers)
    27  	me.allowDefers = true
    28  }
    29  
    30  func (me *lockWithDeferreds) Unlock() {
    31  	// If this doesn't happen other clean up handlers will block on the lock.
    32  	defer me.internal.Unlock()
    33  	panicif.False(me.allowDefers)
    34  	me.allowDefers = false
    35  	me.client.unlockHandlers.run(me.client.slogger)
    36  	startLen := len(me.unlockActions)
    37  	var i int
    38  	for i = 0; i < len(me.unlockActions); i++ {
    39  		me.unlockActions[i]()
    40  	}
    41  	if i != len(me.unlockActions) {
    42  		panic(fmt.Sprintf("num deferred changed while running: %v -> %v", startLen, len(me.unlockActions)))
    43  	}
    44  	me.unlockActions = me.unlockActions[:0]
    45  	me.uniqueActions = nil
    46  }
    47  
    48  func (me *lockWithDeferreds) RLock() {
    49  	me.internal.RLock()
    50  }
    51  
    52  func (me *lockWithDeferreds) RUnlock() {
    53  	me.internal.RUnlock()
    54  }
    55  
    56  // Not allowed after unlock has started.
    57  func (me *lockWithDeferreds) Defer(action func()) {
    58  	me.deferInner(action)
    59  }
    60  
    61  // Already guarded.
    62  func (me *lockWithDeferreds) deferInner(action func()) {
    63  	panicif.False(me.allowDefers)
    64  	me.unlockActions = append(me.unlockActions, action)
    65  }
    66  
    67  // Protected from looping by once filter.
    68  func (me *lockWithDeferreds) deferOnceInner(key any, action func()) {
    69  	panicif.False(me.allowDefers)
    70  	g.MakeMapIfNil(&me.uniqueActions)
    71  	if g.MapContains(me.uniqueActions, key) {
    72  		return
    73  	}
    74  	me.uniqueActions[key] = struct{}{}
    75  	me.deferInner(action)
    76  }
    77  
    78  // Protected from looping by once filter. Note that if arg is the receiver of action, it should
    79  // match the receiver type (like being a pointer if the method takes a pointer receiver).
    80  func (me *lockWithDeferreds) DeferUniqueUnaryFunc(arg any, action func()) {
    81  	me.deferOnceInner(unaryFuncKey(action, arg), action)
    82  }
    83  
    84  func unaryFuncKey(f func(), key any) funcAndArgKey {
    85  	return funcAndArgKey{
    86  		funcStr: reflect.ValueOf(f).String(),
    87  		key:     key,
    88  	}
    89  }
    90  
    91  type funcAndArgKey struct {
    92  	funcStr string
    93  	key     any
    94  }