summaryrefslogtreecommitdiffhomepage
path: root/pkg/gate/gate.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/gate/gate.go')
-rw-r--r--pkg/gate/gate.go134
1 files changed, 0 insertions, 134 deletions
diff --git a/pkg/gate/gate.go b/pkg/gate/gate.go
deleted file mode 100644
index bda6aae09..000000000
--- a/pkg/gate/gate.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package gate provides a usage Gate synchronization primitive.
-package gate
-
-import (
- "sync/atomic"
-)
-
-const (
- // gateClosed is the bit set in the gate's user count to indicate that
- // it has been closed. It is the MSB of the 32-bit field; the other 31
- // bits carry the actual count.
- gateClosed = 0x80000000
-)
-
-// Gate is a synchronization primitive that allows concurrent goroutines to
-// "enter" it as long as it hasn't been closed yet. Once it's been closed,
-// goroutines cannot enter it anymore, but are allowed to leave, and the closer
-// will be informed when all goroutines have left.
-//
-// Many goroutines are allowed to enter the gate concurrently, but only one is
-// allowed to close it.
-//
-// This is similar to a r/w critical section, except that goroutines "entering"
-// never block: they either enter immediately or fail to enter. The closer will
-// block waiting for all goroutines currently inside the gate to leave.
-//
-// This function is implemented efficiently. On x86, only one interlocked
-// operation is performed on enter, and one on leave.
-//
-// This is useful, for example, in cases when a goroutine is trying to clean up
-// an object for which multiple goroutines have pointers. In such a case, users
-// would be required to enter and leave the gates, and the cleaner would wait
-// until all users are gone (and no new ones are allowed) before proceeding.
-//
-// Users:
-//
-// if !g.Enter() {
-// // Gate is closed, we can't use the object.
-// return
-// }
-//
-// // Do something with object.
-// [...]
-//
-// g.Leave()
-//
-// Closer:
-//
-// // Prevent new users from using the object, and wait for the existing
-// // ones to complete.
-// g.Close()
-//
-// // Clean up the object.
-// [...]
-//
-type Gate struct {
- userCount uint32
- done chan struct{}
-}
-
-// Enter tries to enter the gate. It will succeed if it hasn't been closed yet,
-// in which case the caller must eventually call Leave().
-//
-// This function is thread-safe.
-func (g *Gate) Enter() bool {
- if g == nil {
- return false
- }
-
- for {
- v := atomic.LoadUint32(&g.userCount)
- if v&gateClosed != 0 {
- return false
- }
-
- if atomic.CompareAndSwapUint32(&g.userCount, v, v+1) {
- return true
- }
- }
-}
-
-// Leave leaves the gate. This must only be called after a successful call to
-// Enter(). If the gate has been closed and this is the last one inside the
-// gate, it will notify the closer that the gate is done.
-//
-// This function is thread-safe.
-func (g *Gate) Leave() {
- for {
- v := atomic.LoadUint32(&g.userCount)
- if v&^gateClosed == 0 {
- panic("leaving a gate with zero usage count")
- }
-
- if atomic.CompareAndSwapUint32(&g.userCount, v, v-1) {
- if v == gateClosed+1 {
- close(g.done)
- }
- return
- }
- }
-}
-
-// Close closes the gate for entering, and waits until all goroutines [that are
-// currently inside the gate] leave before returning.
-//
-// Only one goroutine can call this function.
-func (g *Gate) Close() {
- for {
- v := atomic.LoadUint32(&g.userCount)
- if v&^gateClosed != 0 && g.done == nil {
- g.done = make(chan struct{})
- }
- if atomic.CompareAndSwapUint32(&g.userCount, v, v|gateClosed) {
- if v&^gateClosed != 0 {
- <-g.done
- }
- return
- }
- }
-}