github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/sync/trymutex.go (about)

     1  package sync
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // TryMutex provides a mutex that allows you to attempt to grab a mutex, and
     9  // then fail if the mutex is either not grabbed immediately or is not grabbed
    10  // by the specified duration.
    11  type TryMutex struct {
    12  	once sync.Once
    13  	lock chan struct{}
    14  }
    15  
    16  // init will create the channel that manages the lock.
    17  func (tm *TryMutex) init() {
    18  	tm.lock = make(chan struct{}, 1)
    19  	tm.lock <- struct{}{}
    20  }
    21  
    22  // Lock grabs a lock on the TryMutex, blocking until the lock is obtained.
    23  func (tm *TryMutex) Lock() {
    24  	tm.once.Do(tm.init)
    25  
    26  	<-tm.lock
    27  }
    28  
    29  // TryLock grabs a lock on the TryMutex, returning an error if the mutex is
    30  // already locked.
    31  func (tm *TryMutex) TryLock() bool {
    32  	tm.once.Do(tm.init)
    33  	select {
    34  	case <-tm.lock:
    35  		return true
    36  	default:
    37  		return false
    38  	}
    39  }
    40  
    41  // TryLockTimed grabs a lock on the TryMutex, returning an error if the mutex
    42  // is not grabbed after the provided duration.
    43  func (tm *TryMutex) TryLockTimed(t time.Duration) bool {
    44  	tm.once.Do(tm.init)
    45  
    46  	timer := time.NewTimer(t)
    47  	select {
    48  	case <-tm.lock:
    49  		timer.Stop()
    50  		return true
    51  	case <-timer.C:
    52  		return false
    53  	}
    54  }
    55  
    56  // Unlock releases a lock on the TryMutex.
    57  func (tm *TryMutex) Unlock() {
    58  	tm.once.Do(tm.init)
    59  
    60  	select {
    61  	case tm.lock <- struct{}{}:
    62  		// Success - do nothing.
    63  	default:
    64  		panic("unlock called when TryMutex is not locked")
    65  	}
    66  }