Import atomic package
The code is the same as github.com/uber/tchannel-go/atomic
This commit is contained in:
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
.DS_Store
|
||||
/vendor
|
||||
/cover
|
||||
cover.out
|
||||
|
||||
|
||||
# Binaries
|
||||
*.test
|
||||
|
||||
# Profiling output
|
||||
*.prof
|
||||
18
.travis.yml
Normal file
18
.travis.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
|
||||
install:
|
||||
- make install_ci
|
||||
|
||||
script:
|
||||
- make test_ci
|
||||
- travis_retry goveralls -coverprofile=cover.out -service=travis-ci
|
||||
32
Makefile
Normal file
32
Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
PACKAGES := $(shell glide novendor)
|
||||
|
||||
export GO15VENDOREXPERIMENT=1
|
||||
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build -i $(PACKAGES)
|
||||
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
glide --version || go get github.com/Masterminds/glide
|
||||
glide install
|
||||
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -cover -race $(PACKAGES)
|
||||
|
||||
|
||||
.PHONY: install_ci
|
||||
install_ci: install
|
||||
go get github.com/wadey/gocovmerge
|
||||
go get github.com/mattn/goveralls
|
||||
go get golang.org/x/tools/cmd/cover
|
||||
|
||||
|
||||
.PHONY: test_ci
|
||||
test_ci: install_ci build
|
||||
./scripts/cover.sh $(shell go list $(PACKAGES))
|
||||
|
||||
197
atomic.go
Normal file
197
atomic.go
Normal file
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package atomic provides simple wrappers around numerics to enforce atomic
|
||||
// access.
|
||||
package atomic
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// Int32 is an atomic wrapper around an int32.
|
||||
type Int32 struct{ int32 }
|
||||
|
||||
// NewInt32 creates an Int32.
|
||||
func NewInt32(i int32) *Int32 {
|
||||
return &Int32{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int32) Load() int32 {
|
||||
return atomic.LoadInt32(&i.int32)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Add(n int32) int32 {
|
||||
return atomic.AddInt32(&i.int32, n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Inc() int32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Dec() int32 {
|
||||
return i.Add(-1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int32) CAS(old, new int32) bool {
|
||||
return atomic.CompareAndSwapInt32(&i.int32, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int32) Store(n int32) {
|
||||
atomic.StoreInt32(&i.int32, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||
func (i *Int32) Swap(n int32) int32 {
|
||||
return atomic.SwapInt32(&i.int32, n)
|
||||
}
|
||||
|
||||
// Int64 is an atomic wrapper around an int64.
|
||||
type Int64 struct{ int64 }
|
||||
|
||||
// NewInt64 creates an Int64.
|
||||
func NewInt64(i int64) *Int64 {
|
||||
return &Int64{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int64) Load() int64 {
|
||||
return atomic.LoadInt64(&i.int64)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Add(n int64) int64 {
|
||||
return atomic.AddInt64(&i.int64, n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Inc() int64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Dec() int64 {
|
||||
return i.Add(-1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int64) CAS(old, new int64) bool {
|
||||
return atomic.CompareAndSwapInt64(&i.int64, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int64) Store(n int64) {
|
||||
atomic.StoreInt64(&i.int64, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||
func (i *Int64) Swap(n int64) int64 {
|
||||
return atomic.SwapInt64(&i.int64, n)
|
||||
}
|
||||
|
||||
// Uint32 is an atomic wrapper around an uint32.
|
||||
type Uint32 struct{ uint32 }
|
||||
|
||||
// NewUint32 creates a Uint32.
|
||||
func NewUint32(i uint32) *Uint32 {
|
||||
return &Uint32{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint32) Load() uint32 {
|
||||
return atomic.LoadUint32(&i.uint32)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Add(n uint32) uint32 {
|
||||
return atomic.AddUint32(&i.uint32, n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Inc() uint32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||
func (i *Uint32) Dec() uint32 {
|
||||
return i.Add(^uint32(0))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint32) CAS(old, new uint32) bool {
|
||||
return atomic.CompareAndSwapUint32(&i.uint32, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint32) Store(n uint32) {
|
||||
atomic.StoreUint32(&i.uint32, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||
func (i *Uint32) Swap(n uint32) uint32 {
|
||||
return atomic.SwapUint32(&i.uint32, n)
|
||||
}
|
||||
|
||||
// Uint64 is an atomic wrapper around a uint64.
|
||||
type Uint64 struct{ uint64 }
|
||||
|
||||
// NewUint64 creates a Uint64.
|
||||
func NewUint64(i uint64) *Uint64 {
|
||||
return &Uint64{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint64) Load() uint64 {
|
||||
return atomic.LoadUint64(&i.uint64)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Add(n uint64) uint64 {
|
||||
return atomic.AddUint64(&i.uint64, n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Inc() uint64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Dec() uint64 {
|
||||
return i.Add(^uint64(0))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint64) CAS(old, new uint64) bool {
|
||||
return atomic.CompareAndSwapUint64(&i.uint64, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint64) Store(n uint64) {
|
||||
atomic.StoreUint64(&i.uint64, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||
func (i *Uint64) Swap(n uint64) uint64 {
|
||||
return atomic.SwapUint64(&i.uint64, n)
|
||||
}
|
||||
99
atomic_test.go
Normal file
99
atomic_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInt32(t *testing.T) {
|
||||
atom := NewInt32(42)
|
||||
|
||||
require.Equal(t, int32(42), atom.Load(), "Load didn't work.")
|
||||
require.Equal(t, int32(44), atom.Add(2), "Add didn't work.")
|
||||
require.Equal(t, int32(45), atom.Inc(), "Inc didn't work.")
|
||||
require.Equal(t, int32(44), atom.Dec(), "Dec didn't work.")
|
||||
|
||||
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
|
||||
require.Equal(t, int32(0), atom.Load(), "CAS didn't set the correct value.")
|
||||
|
||||
require.Equal(t, int32(0), atom.Swap(1), "Swap didn't return the old value.")
|
||||
require.Equal(t, int32(1), atom.Load(), "Swap didn't set the correct value.")
|
||||
|
||||
atom.Store(42)
|
||||
require.Equal(t, int32(42), atom.Load(), "Store didn't set the correct value.")
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
atom := NewInt64(42)
|
||||
|
||||
require.Equal(t, int64(42), atom.Load(), "Load didn't work.")
|
||||
require.Equal(t, int64(44), atom.Add(2), "Add didn't work.")
|
||||
require.Equal(t, int64(45), atom.Inc(), "Inc didn't work.")
|
||||
require.Equal(t, int64(44), atom.Dec(), "Dec didn't work.")
|
||||
|
||||
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
|
||||
require.Equal(t, int64(0), atom.Load(), "CAS didn't set the correct value.")
|
||||
|
||||
require.Equal(t, int64(0), atom.Swap(1), "Swap didn't return the old value.")
|
||||
require.Equal(t, int64(1), atom.Load(), "Swap didn't set the correct value.")
|
||||
|
||||
atom.Store(42)
|
||||
require.Equal(t, int64(42), atom.Load(), "Store didn't set the correct value.")
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
atom := NewUint32(42)
|
||||
|
||||
require.Equal(t, uint32(42), atom.Load(), "Load didn't work.")
|
||||
require.Equal(t, uint32(44), atom.Add(2), "Add didn't work.")
|
||||
require.Equal(t, uint32(45), atom.Inc(), "Inc didn't work.")
|
||||
require.Equal(t, uint32(44), atom.Dec(), "Dec didn't work.")
|
||||
|
||||
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
|
||||
require.Equal(t, uint32(0), atom.Load(), "CAS didn't set the correct value.")
|
||||
|
||||
require.Equal(t, uint32(0), atom.Swap(1), "Swap didn't return the old value.")
|
||||
require.Equal(t, uint32(1), atom.Load(), "Swap didn't set the correct value.")
|
||||
|
||||
atom.Store(42)
|
||||
require.Equal(t, uint32(42), atom.Load(), "Store didn't set the correct value.")
|
||||
}
|
||||
|
||||
func TestUint64(t *testing.T) {
|
||||
atom := NewUint64(42)
|
||||
|
||||
require.Equal(t, uint64(42), atom.Load(), "Load didn't work.")
|
||||
require.Equal(t, uint64(44), atom.Add(2), "Add didn't work.")
|
||||
require.Equal(t, uint64(45), atom.Inc(), "Inc didn't work.")
|
||||
require.Equal(t, uint64(44), atom.Dec(), "Dec didn't work.")
|
||||
|
||||
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
|
||||
require.Equal(t, uint64(0), atom.Load(), "CAS didn't set the correct value.")
|
||||
|
||||
require.Equal(t, uint64(0), atom.Swap(1), "Swap didn't return the old value.")
|
||||
require.Equal(t, uint64(1), atom.Load(), "Swap didn't set the correct value.")
|
||||
|
||||
atom.Store(42)
|
||||
require.Equal(t, uint64(42), atom.Load(), "Store didn't set the correct value.")
|
||||
}
|
||||
4
glide.lock
generated
Normal file
4
glide.lock
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
hash: 8413cf7f8e981fc97e0ce202471bf1cab8b935615ae831b98ebc499655acd513
|
||||
updated: 2016-05-25T10:54:24.639721239-07:00
|
||||
imports: []
|
||||
devImports: []
|
||||
7
glide.yaml
Normal file
7
glide.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
package: github.com/uber-go/atomic
|
||||
imports:
|
||||
# Test dependencies
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
- assert
|
||||
- require
|
||||
40
scripts/cover.sh
Executable file
40
scripts/cover.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
COVER=cover
|
||||
ROOT_PKG=github.com/uber-go/atomic
|
||||
|
||||
if [[ -d "$COVER" ]]; then
|
||||
rm -rf "$COVER"
|
||||
fi
|
||||
mkdir -p "$COVER"
|
||||
|
||||
i=0
|
||||
for pkg in "$@"; do
|
||||
i=$((i + 1))
|
||||
|
||||
extracoverpkg=""
|
||||
if [[ -f "$GOPATH/src/$pkg/.extra-coverpkg" ]]; then
|
||||
extracoverpkg=$( \
|
||||
sed -e "s|^|$pkg/|g" < "$GOPATH/src/$pkg/.extra-coverpkg" \
|
||||
| tr '\n' ',')
|
||||
fi
|
||||
|
||||
coverpkg=$(go list -json "$pkg" | jq -r '
|
||||
.Deps
|
||||
| map(select(startswith("'"$ROOT_PKG"'")))
|
||||
| map(select(contains("/vendor/") | not))
|
||||
| . + ["'"$pkg"'"]
|
||||
| join(",")
|
||||
')
|
||||
if [[ -n "$extracoverpkg" ]]; then
|
||||
coverpkg="$extracoverpkg$coverpkg"
|
||||
fi
|
||||
|
||||
go test \
|
||||
-coverprofile "$COVER/cover.${i}.out" -coverpkg "$coverpkg" \
|
||||
-v "$pkg"
|
||||
done
|
||||
|
||||
gocovmerge "$COVER"/*.out > cover.out
|
||||
101
stress_test.go
Normal file
101
stress_test.go
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const _parallelism = 4
|
||||
const _iterations = 1000
|
||||
|
||||
func TestStressInt32(t *testing.T) {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
|
||||
atom := &Int32{0}
|
||||
for i := 0; i < _parallelism; i++ {
|
||||
go func() {
|
||||
for j := 0; j < _iterations; j++ {
|
||||
atom.Load()
|
||||
atom.Add(1)
|
||||
atom.Inc()
|
||||
atom.Dec()
|
||||
atom.CAS(1, 0)
|
||||
atom.Swap(5)
|
||||
atom.Store(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStressInt64(t *testing.T) {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
|
||||
atom := &Int64{0}
|
||||
for i := 0; i < _parallelism; i++ {
|
||||
go func() {
|
||||
for j := 0; j < _iterations; j++ {
|
||||
atom.Load()
|
||||
atom.Add(1)
|
||||
atom.Inc()
|
||||
atom.Dec()
|
||||
atom.CAS(1, 0)
|
||||
atom.Swap(5)
|
||||
atom.Store(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStressUint32(t *testing.T) {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
|
||||
atom := &Uint32{0}
|
||||
for i := 0; i < _parallelism; i++ {
|
||||
go func() {
|
||||
for j := 0; j < _iterations; j++ {
|
||||
atom.Load()
|
||||
atom.Add(1)
|
||||
atom.Inc()
|
||||
atom.Dec()
|
||||
atom.CAS(1, 0)
|
||||
atom.Swap(5)
|
||||
atom.Store(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStressUint64(t *testing.T) {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
|
||||
atom := &Uint64{0}
|
||||
for i := 0; i < _parallelism; i++ {
|
||||
go func() {
|
||||
for j := 0; j < _iterations; j++ {
|
||||
atom.Load()
|
||||
atom.Add(1)
|
||||
atom.Inc()
|
||||
atom.Dec()
|
||||
atom.CAS(1, 0)
|
||||
atom.Swap(5)
|
||||
atom.Store(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user