summaryrefslogtreecommitdiffhomepage
path: root/pkg/sync/seqcount.go
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2019-01-31 17:47:24 -0800
committerShentubot <shentubot@google.com>2019-01-31 17:49:14 -0800
commitfe1369ac98a4f1d8af5e8be6da71165339e52034 (patch)
tree89c1e4553a375b57e9999278613eb37f104e30a6 /pkg/sync/seqcount.go
parent4e695adcd0c739101c3d50431ca18b1b911c9238 (diff)
Move package sync to third_party
PiperOrigin-RevId: 231889261 Change-Id: I482f1df055bcedf4edb9fe3fe9b8e9c80085f1a0
Diffstat (limited to 'pkg/sync/seqcount.go')
-rw-r--r--pkg/sync/seqcount.go158
1 files changed, 0 insertions, 158 deletions
diff --git a/pkg/sync/seqcount.go b/pkg/sync/seqcount.go
deleted file mode 100644
index 732e856a4..000000000
--- a/pkg/sync/seqcount.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// 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 sync
-
-import (
- "fmt"
- "reflect"
- "runtime"
- "sync/atomic"
-)
-
-// SeqCount is a synchronization primitive for optimistic reader/writer
-// synchronization in cases where readers can work with stale data and
-// therefore do not need to block writers.
-//
-// Compared to sync/atomic.Value:
-//
-// - Mutation of SeqCount-protected data does not require memory allocation,
-// whereas atomic.Value generally does. This is a significant advantage when
-// writes are common.
-//
-// - Atomic reads of SeqCount-protected data require copying. This is a
-// disadvantage when atomic reads are common.
-//
-// - SeqCount may be more flexible: correct use of SeqCount.ReadOk allows other
-// operations to be made atomic with reads of SeqCount-protected data.
-//
-// - SeqCount may be less flexible: as of this writing, SeqCount-protected data
-// cannot include pointers.
-//
-// - SeqCount is more cumbersome to use; atomic reads of SeqCount-protected
-// data require instantiating function templates using go_generics (see
-// seqatomic.go).
-type SeqCount struct {
- // epoch is incremented by BeginWrite and EndWrite, such that epoch is odd
- // if a writer critical section is active, and a read from data protected
- // by this SeqCount is atomic iff epoch is the same even value before and
- // after the read.
- epoch uint32
-}
-
-// SeqCountEpoch tracks writer critical sections in a SeqCount.
-type SeqCountEpoch struct {
- val uint32
-}
-
-// We assume that:
-//
-// - All functions in sync/atomic that perform a memory read are at least a
-// read fence: memory reads before calls to such functions cannot be reordered
-// after the call, and memory reads after calls to such functions cannot be
-// reordered before the call, even if those reads do not use sync/atomic.
-//
-// - All functions in sync/atomic that perform a memory write are at least a
-// write fence: memory writes before calls to such functions cannot be
-// reordered after the call, and memory writes after calls to such functions
-// cannot be reordered before the call, even if those writes do not use
-// sync/atomic.
-//
-// As of this writing, the Go memory model completely fails to describe
-// sync/atomic, but these properties are implied by
-// https://groups.google.com/forum/#!topic/golang-nuts/7EnEhM3U7B8.
-
-// BeginRead indicates the beginning of a reader critical section. Reader
-// critical sections DO NOT BLOCK writer critical sections, so operations in a
-// reader critical section MAY RACE with writer critical sections. Races are
-// detected by ReadOk at the end of the reader critical section. Thus, the
-// low-level structure of readers is generally:
-//
-// for {
-// epoch := seq.BeginRead()
-// // do something idempotent with seq-protected data
-// if seq.ReadOk(epoch) {
-// break
-// }
-// }
-//
-// However, since reader critical sections may race with writer critical
-// sections, the Go race detector will (accurately) flag data races in readers
-// using this pattern. Most users of SeqCount will need to use the
-// SeqAtomicLoad function template in seqatomic.go.
-func (s *SeqCount) BeginRead() SeqCountEpoch {
- epoch := atomic.LoadUint32(&s.epoch)
- for epoch&1 != 0 {
- runtime.Gosched()
- epoch = atomic.LoadUint32(&s.epoch)
- }
- return SeqCountEpoch{epoch}
-}
-
-// ReadOk returns true if the reader critical section initiated by a previous
-// call to BeginRead() that returned epoch did not race with any writer critical
-// sections.
-//
-// ReadOk may be called any number of times during a reader critical section.
-// Reader critical sections do not need to be explicitly terminated; the last
-// call to ReadOk is implicitly the end of the reader critical section.
-func (s *SeqCount) ReadOk(epoch SeqCountEpoch) bool {
- return atomic.LoadUint32(&s.epoch) == epoch.val
-}
-
-// BeginWrite indicates the beginning of a writer critical section.
-//
-// SeqCount does not support concurrent writer critical sections; clients with
-// concurrent writers must synchronize them using e.g. sync.Mutex.
-func (s *SeqCount) BeginWrite() {
- if epoch := atomic.AddUint32(&s.epoch, 1); epoch&1 == 0 {
- panic("SeqCount.BeginWrite during writer critical section")
- }
-}
-
-// EndWrite ends the effect of a preceding BeginWrite.
-func (s *SeqCount) EndWrite() {
- if epoch := atomic.AddUint32(&s.epoch, 1); epoch&1 != 0 {
- panic("SeqCount.EndWrite outside writer critical section")
- }
-}
-
-// PointersInType returns a list of pointers reachable from values named
-// valName of the given type.
-//
-// PointersInType is not exhaustive, but it is guaranteed that if typ contains
-// at least one pointer, then PointersInTypeOf returns a non-empty list.
-func PointersInType(typ reflect.Type, valName string) []string {
- switch kind := typ.Kind(); kind {
- case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
- return nil
-
- case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.String, reflect.UnsafePointer:
- return []string{valName}
-
- case reflect.Array:
- return PointersInType(typ.Elem(), valName+"[]")
-
- case reflect.Struct:
- var ptrs []string
- for i, n := 0, typ.NumField(); i < n; i++ {
- field := typ.Field(i)
- ptrs = append(ptrs, PointersInType(field.Type, fmt.Sprintf("%s.%s", valName, field.Name))...)
- }
- return ptrs
-
- default:
- return []string{fmt.Sprintf("%s (of type %s with unknown kind %s)", valName, typ, kind)}
- }
-}