Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: Use atomic types in exported modules. #3054

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions addrmgr/addrmanager.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Copyright (c) 2015-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -72,13 +72,12 @@ type AddrManager struct {
// serialized and saved to the file system.
addrChanged bool

// started signals whether the address manager has been started. Its value
// is 1 or more if started.
started int32
// started signals whether the address manager has been started.
started atomic.Bool

// shutdown signals whether a shutdown of the address manager has been
// initiated. Its value is 1 or more if a shutdown is done or in progress.
shutdown int32
// initiated.
shutdown atomic.Bool

// The following fields are used for lifecycle management of the
// address manager.
Expand Down Expand Up @@ -623,7 +622,7 @@ func (a *AddrManager) deserializePeers(filePath string) error {
// This function is safe for concurrent access.
func (a *AddrManager) Start() {
// Return early if the address manager has already been started.
if atomic.AddInt32(&a.started, 1) != 1 {
if !a.started.CompareAndSwap(false, true) {
return
}

Expand All @@ -642,7 +641,7 @@ func (a *AddrManager) Start() {
// This function is safe for concurrent access.
func (a *AddrManager) Stop() error {
// Return early if the address manager has already been stopped.
if atomic.AddInt32(&a.shutdown, 1) != 1 {
if !a.shutdown.CompareAndSwap(false, true) {
log.Warnf("Address manager is already in the process of shutting down")
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion addrmgr/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/decred/dcrd/addrmgr/v2

go 1.17
go 1.19

require (
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
Expand Down
27 changes: 12 additions & 15 deletions connmgr/connmanager.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2017-2023 The Decred developers
// Copyright (c) 2017-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -56,13 +56,11 @@ const (
// ConnReq is the connection request to a network address. If permanent, the
// connection will be retried on disconnection.
type ConnReq struct {
// The following variables must only be used atomically.
//
// id is the unique identifier for this connection request.
//
id atomic.Uint64

// state is the current connection state for this connection request.
id uint64
state uint32
state atomic.Uint32
davecgh marked this conversation as resolved.
Show resolved Hide resolved

// The following fields are owned by the connection handler and must not
// be accessed outside of it.
Expand All @@ -87,17 +85,17 @@ type ConnReq struct {

// updateState updates the state of the connection request.
func (c *ConnReq) updateState(state ConnState) {
atomic.StoreUint32(&c.state, uint32(state))
c.state.Store(uint32(state))
}

// ID returns a unique identifier for the connection request.
func (c *ConnReq) ID() uint64 {
return atomic.LoadUint64(&c.id)
return c.id.Load()
}

// State is the connection state of the requested connection.
func (c *ConnReq) State() ConnState {
return ConnState(atomic.LoadUint32(&c.state))
return ConnState(c.state.Load())
}

// String returns a human-readable string for the connection request.
Expand Down Expand Up @@ -209,11 +207,9 @@ type handleForEachConnReq struct {

// ConnManager provides a manager to handle network connections.
type ConnManager struct {
// The following variables must only be used atomically.
//
// connReqCount is the number of connection requests that have been made and
// is primarily used to assign unique connection request IDs.
connReqCount uint64
connReqCount atomic.Uint64

// assignIDMtx synchronizes the assignment of an ID to a connection request
// with overall connection request count above.
Expand Down Expand Up @@ -467,7 +463,8 @@ func (cm *ConnManager) newConnReq(ctx context.Context) {
return
}

c := &ConnReq{id: atomic.AddUint64(&cm.connReqCount, 1)}
c := &ConnReq{}
c.id.Store(cm.connReqCount.Add(1))

// Submit a request of a pending connection attempt to the connection
// manager. By registering the id before the connection is even
Expand Down Expand Up @@ -545,7 +542,7 @@ func (cm *ConnManager) Connect(ctx context.Context, c *ConnReq) {
var doRegisterPending bool
cm.assignIDMtx.Lock()
if c.ID() == 0 {
atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1))
c.id.Store(cm.connReqCount.Add(1))
doRegisterPending = true
}
cm.assignIDMtx.Unlock()
Expand Down Expand Up @@ -716,7 +713,7 @@ func (cm *ConnManager) Run(ctx context.Context) {
// Start enough outbound connections to reach the target number when not
// in manual connect mode.
if cm.cfg.GetNewAddress != nil {
curConnReqCount := atomic.LoadUint64(&cm.connReqCount)
curConnReqCount := cm.connReqCount.Load()
for i := curConnReqCount; i < uint64(cm.cfg.TargetOutbound); i++ {
go cm.newConnReq(ctx)
}
Expand Down
12 changes: 6 additions & 6 deletions connmgr/connmanager_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2019-2022 The Decred developers
// Copyright (c) 2019-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -405,11 +405,11 @@ func TestNetworkFailure(t *testing.T) {
var closeOnce sync.Once
const targetOutbound = 5
const retryTimeout = time.Millisecond * 5
var dials uint32
var dials atomic.Uint32
reachedMaxFailedAttempts := make(chan struct{})
connMgrDone := make(chan struct{})
errDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
totalDials := atomic.AddUint32(&dials, 1)
totalDials := dials.Add(1)
if totalDials >= maxFailedAttempts {
closeOnce.Do(func() { close(reachedMaxFailedAttempts) })
<-connMgrDone
Expand Down Expand Up @@ -447,7 +447,7 @@ func TestNetworkFailure(t *testing.T) {
// Ensure the number of dial attempts does not exceed the max number of
// failed attempts plus the number of potential retries during the
// additional waiting period.
gotDials := atomic.LoadUint32(&dials)
gotDials := dials.Load()
wantMaxDials := uint32(maxFailedAttempts + targetOutbound)
if gotDials > wantMaxDials {
t.Fatalf("unexpected number of dials - got %v, want <= %v", gotDials,
Expand All @@ -468,11 +468,11 @@ func TestMultipleFailedConns(t *testing.T) {
}()

const targetFailed = 5
var dials uint32
var dials atomic.Uint32
var closeOnce sync.Once
hitTargetFailed := make(chan struct{})
errDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
totalDials := atomic.AddUint32(&dials, 1)
totalDials := dials.Add(1)
if totalDials >= targetFailed {
closeOnce.Do(func() { close(hitTargetFailed) })
}
Expand Down
2 changes: 1 addition & 1 deletion connmgr/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/decred/dcrd/connmgr/v3

go 1.17
go 1.19

require (
github.com/decred/dcrd/wire v1.6.0
Expand Down
10 changes: 5 additions & 5 deletions database/ffldb/interface_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2015-2016 The btcsuite developers
// Copyright (c) 2016-2020 The Decred developers
// Copyright (c) 2016-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -2163,17 +2163,17 @@ func testConcurrentClose(tc *testContext) bool {
// Start up a few readers and wait for them to acquire views. Each
// reader waits for a signal to complete to ensure the transactions stay
// open until they are explicitly signalled to be closed.
var activeReaders int32
var activeReaders atomic.Int32
numReaders := 3
started := make(chan struct{})
finishReaders := make(chan struct{})
resultChan := make(chan bool, numReaders+1)
reader := func() {
err := tc.db.View(func(tx database.Tx) error {
atomic.AddInt32(&activeReaders, 1)
activeReaders.Add(1)
started <- struct{}{}
<-finishReaders
atomic.AddInt32(&activeReaders, -1)
activeReaders.Add(-1)
return nil
})
if err != nil {
Expand Down Expand Up @@ -2212,7 +2212,7 @@ func testConcurrentClose(tc *testContext) bool {
// active readers open.
time.AfterFunc(time.Millisecond*250, func() { close(finishReaders) })
<-dbClosed
if nr := atomic.LoadInt32(&activeReaders); nr != 0 {
if nr := activeReaders.Load(); nr != 0 {
tc.t.Errorf("Close did not appear to block with active "+
"readers: %d active", nr)
return false
Expand Down
2 changes: 1 addition & 1 deletion database/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/decred/dcrd/database/v3

go 1.17
go 1.19

require (
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
Expand Down
2 changes: 1 addition & 1 deletion peer/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/decred/dcrd/peer/v3

go 1.17
go 1.19

require (
github.com/davecgh/go-spew v1.1.1
Expand Down
Loading