mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 07:59:57 +00:00
TUN-528: Move cloudflared into a separate repo
This commit is contained in:
16
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/BUILD.bazel
generated
vendored
Normal file
16
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["refcount.go"],
|
||||
importpath = "zombiezen.com/go/capnproto2/rpc/internal/refcount",
|
||||
visibility = ["//rpc:__subpackages__"],
|
||||
deps = ["//:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["refcount_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//:go_default_library"],
|
||||
)
|
116
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/refcount.go
generated
vendored
Normal file
116
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/refcount.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Package refcount implements a reference-counting client.
|
||||
package refcount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
)
|
||||
|
||||
// A RefCount will close its underlying client once all its references are closed.
|
||||
type RefCount struct {
|
||||
Client capnp.Client
|
||||
|
||||
mu sync.Mutex
|
||||
refs int
|
||||
}
|
||||
|
||||
// New creates a reference counter and the first client reference.
|
||||
func New(c capnp.Client) (rc *RefCount, ref1 capnp.Client) {
|
||||
if rr, ok := c.(*Ref); ok {
|
||||
return rr.rc, rr.rc.Ref()
|
||||
}
|
||||
rc = &RefCount{Client: c, refs: 1}
|
||||
ref1 = rc.newRef()
|
||||
return
|
||||
}
|
||||
|
||||
// Ref makes a new client reference.
|
||||
func (rc *RefCount) Ref() capnp.Client {
|
||||
rc.mu.Lock()
|
||||
if rc.refs <= 0 {
|
||||
rc.mu.Unlock()
|
||||
return capnp.ErrorClient(errZeroRef)
|
||||
}
|
||||
rc.refs++
|
||||
rc.mu.Unlock()
|
||||
return rc.newRef()
|
||||
}
|
||||
|
||||
func (rc *RefCount) newRef() *Ref {
|
||||
r := &Ref{rc: rc}
|
||||
runtime.SetFinalizer(r, (*Ref).Close)
|
||||
return r
|
||||
}
|
||||
|
||||
func (rc *RefCount) call(cl *capnp.Call) capnp.Answer {
|
||||
// We lock here so that we can prevent the client from being closed
|
||||
// while we start the call.
|
||||
rc.mu.Lock()
|
||||
if rc.refs <= 0 {
|
||||
rc.mu.Unlock()
|
||||
return capnp.ErrorAnswer(errClosed)
|
||||
}
|
||||
ans := rc.Client.Call(cl)
|
||||
rc.mu.Unlock()
|
||||
return ans
|
||||
}
|
||||
|
||||
// decref decreases the reference count by one, closing the Client if it reaches zero.
|
||||
func (rc *RefCount) decref() error {
|
||||
shouldClose := false
|
||||
|
||||
rc.mu.Lock()
|
||||
if rc.refs <= 0 {
|
||||
rc.mu.Unlock()
|
||||
return errClosed
|
||||
}
|
||||
rc.refs--
|
||||
if rc.refs == 0 {
|
||||
shouldClose = true
|
||||
}
|
||||
rc.mu.Unlock()
|
||||
|
||||
if shouldClose {
|
||||
return rc.Client.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
errZeroRef = errors.New("rpc: Ref() called on zeroed refcount")
|
||||
errClosed = errors.New("rpc: Close() called on closed client")
|
||||
)
|
||||
|
||||
// A Ref is a single reference to a client wrapped by RefCount.
|
||||
type Ref struct {
|
||||
rc *RefCount
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// Call makes a call on the underlying client.
|
||||
func (r *Ref) Call(cl *capnp.Call) capnp.Answer {
|
||||
return r.rc.call(cl)
|
||||
}
|
||||
|
||||
// Client returns the underlying client.
|
||||
func (r *Ref) Client() capnp.Client {
|
||||
return r.rc.Client
|
||||
}
|
||||
|
||||
// Close decrements the reference count. Close will be called on
|
||||
// finalization (i.e. garbage collection).
|
||||
func (r *Ref) Close() error {
|
||||
var err error
|
||||
closed := false
|
||||
r.once.Do(func() {
|
||||
err = r.rc.decref()
|
||||
closed = true
|
||||
})
|
||||
if !closed {
|
||||
return errClosed
|
||||
}
|
||||
return err
|
||||
}
|
89
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/refcount_test.go
generated
vendored
Normal file
89
vendor/zombiezen.com/go/capnproto2/rpc/internal/refcount/refcount_test.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package refcount
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
)
|
||||
|
||||
func TestSingleRefCloses(t *testing.T) {
|
||||
c := new(fakeClient)
|
||||
|
||||
_, ref := New(c)
|
||||
err := ref.Close()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("ref.Close(): %v", err)
|
||||
}
|
||||
if c.closed != 1 {
|
||||
t.Errorf("client Close() called %d times; want 1 time", c.closed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseRefMultipleDecrefsOnce(t *testing.T) {
|
||||
c := new(fakeClient)
|
||||
|
||||
rc, ref1 := New(c)
|
||||
ref2 := rc.Ref()
|
||||
err1 := ref1.Close()
|
||||
err2 := ref1.Close()
|
||||
_ = ref2
|
||||
|
||||
if err1 != nil {
|
||||
t.Errorf("ref.Close() #1: %v", err1)
|
||||
}
|
||||
if err2 != errClosed {
|
||||
t.Errorf("ref.Close() #2: %v; want %v", err2, errClosed)
|
||||
}
|
||||
if c.closed != 0 {
|
||||
t.Errorf("client Close() called %d times; want 0 times", c.closed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClosingOneOfManyRefsDoesntClose(t *testing.T) {
|
||||
c := new(fakeClient)
|
||||
|
||||
rc, ref1 := New(c)
|
||||
ref2 := rc.Ref()
|
||||
err := ref1.Close()
|
||||
_ = ref2
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("ref1.Close(): %v", err)
|
||||
}
|
||||
if c.closed != 0 {
|
||||
t.Errorf("client Close() called %d times; want 0 times", c.closed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClosingAllRefsCloses(t *testing.T) {
|
||||
c := new(fakeClient)
|
||||
|
||||
rc, ref1 := New(c)
|
||||
ref2 := rc.Ref()
|
||||
err1 := ref1.Close()
|
||||
err2 := ref2.Close()
|
||||
|
||||
if err1 != nil {
|
||||
t.Errorf("ref1.Close(): %v", err1)
|
||||
}
|
||||
if err2 != nil {
|
||||
t.Errorf("ref2.Close(): %v", err2)
|
||||
}
|
||||
if c.closed != 1 {
|
||||
t.Errorf("client Close() called %d times; want 1 times", c.closed)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
closed int
|
||||
}
|
||||
|
||||
func (c *fakeClient) Call(cl *capnp.Call) capnp.Answer {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (c *fakeClient) Close() error {
|
||||
c.closed++
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user