.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / sync@v0.0.0-20201020160332-67f06af15bc9 / semaphore / semaphore.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/sync@v0.0.0-20201020160332-67f06af15bc9/semaphore/semaphore.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/sync@v0.0.0-20201020160332-67f06af15bc9/semaphore/semaphore.go
new file mode 100644 (file)
index 0000000..30f632c
--- /dev/null
@@ -0,0 +1,136 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package semaphore provides a weighted semaphore implementation.
+package semaphore // import "golang.org/x/sync/semaphore"
+
+import (
+       "container/list"
+       "context"
+       "sync"
+)
+
+type waiter struct {
+       n     int64
+       ready chan<- struct{} // Closed when semaphore acquired.
+}
+
+// NewWeighted creates a new weighted semaphore with the given
+// maximum combined weight for concurrent access.
+func NewWeighted(n int64) *Weighted {
+       w := &Weighted{size: n}
+       return w
+}
+
+// Weighted provides a way to bound concurrent access to a resource.
+// The callers can request access with a given weight.
+type Weighted struct {
+       size    int64
+       cur     int64
+       mu      sync.Mutex
+       waiters list.List
+}
+
+// Acquire acquires the semaphore with a weight of n, blocking until resources
+// are available or ctx is done. On success, returns nil. On failure, returns
+// ctx.Err() and leaves the semaphore unchanged.
+//
+// If ctx is already done, Acquire may still succeed without blocking.
+func (s *Weighted) Acquire(ctx context.Context, n int64) error {
+       s.mu.Lock()
+       if s.size-s.cur >= n && s.waiters.Len() == 0 {
+               s.cur += n
+               s.mu.Unlock()
+               return nil
+       }
+
+       if n > s.size {
+               // Don't make other Acquire calls block on one that's doomed to fail.
+               s.mu.Unlock()
+               <-ctx.Done()
+               return ctx.Err()
+       }
+
+       ready := make(chan struct{})
+       w := waiter{n: n, ready: ready}
+       elem := s.waiters.PushBack(w)
+       s.mu.Unlock()
+
+       select {
+       case <-ctx.Done():
+               err := ctx.Err()
+               s.mu.Lock()
+               select {
+               case <-ready:
+                       // Acquired the semaphore after we were canceled.  Rather than trying to
+                       // fix up the queue, just pretend we didn't notice the cancelation.
+                       err = nil
+               default:
+                       isFront := s.waiters.Front() == elem
+                       s.waiters.Remove(elem)
+                       // If we're at the front and there're extra tokens left, notify other waiters.
+                       if isFront && s.size > s.cur {
+                               s.notifyWaiters()
+                       }
+               }
+               s.mu.Unlock()
+               return err
+
+       case <-ready:
+               return nil
+       }
+}
+
+// TryAcquire acquires the semaphore with a weight of n without blocking.
+// On success, returns true. On failure, returns false and leaves the semaphore unchanged.
+func (s *Weighted) TryAcquire(n int64) bool {
+       s.mu.Lock()
+       success := s.size-s.cur >= n && s.waiters.Len() == 0
+       if success {
+               s.cur += n
+       }
+       s.mu.Unlock()
+       return success
+}
+
+// Release releases the semaphore with a weight of n.
+func (s *Weighted) Release(n int64) {
+       s.mu.Lock()
+       s.cur -= n
+       if s.cur < 0 {
+               s.mu.Unlock()
+               panic("semaphore: released more than held")
+       }
+       s.notifyWaiters()
+       s.mu.Unlock()
+}
+
+func (s *Weighted) notifyWaiters() {
+       for {
+               next := s.waiters.Front()
+               if next == nil {
+                       break // No more waiters blocked.
+               }
+
+               w := next.Value.(waiter)
+               if s.size-s.cur < w.n {
+                       // Not enough tokens for the next waiter.  We could keep going (to try to
+                       // find a waiter with a smaller request), but under load that could cause
+                       // starvation for large requests; instead, we leave all remaining waiters
+                       // blocked.
+                       //
+                       // Consider a semaphore used as a read-write lock, with N tokens, N
+                       // readers, and one writer.  Each reader can Acquire(1) to obtain a read
+                       // lock.  The writer can Acquire(N) to obtain a write lock, excluding all
+                       // of the readers.  If we allow the readers to jump ahead in the queue,
+                       // the writer will starve — there is always one token available for every
+                       // reader.
+                       break
+               }
+
+               s.cur += w.n
+               s.waiters.Remove(next)
+               close(w.ready)
+       }
+}