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

mining: Prevent potential shutdown hang. #2196

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 27 additions & 10 deletions mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,8 @@ type regenEvent struct {
// - Block while generating new templates that will make the current template
// stale (e.g. new parent or new votes)
type BgBlkTmplGenerator struct {
wg sync.WaitGroup
wg sync.WaitGroup
quit chan struct{}

// These fields are provided by the caller when the generator is created and
// are either independently safe for concurrent access or do not change after
Expand Down Expand Up @@ -2131,6 +2132,7 @@ type BgBlkTmplGenerator struct {
// method to allowing processing.
func newBgBlkTmplGenerator(tg *BlkTmplGenerator, addrs []dcrutil.Address, allowUnsynced bool) *BgBlkTmplGenerator {
return &BgBlkTmplGenerator{
quit: make(chan struct{}),
chain: tg.chain,
tg: tg,
allowUnsyncedMining: allowUnsynced,
Expand All @@ -2146,6 +2148,16 @@ func newBgBlkTmplGenerator(tg *BlkTmplGenerator, addrs []dcrutil.Address, allowU
}
}

// sendQueueRegenEvent sends the provided regen event on the internal queue
// regen event channel while respecting the quit channel. The allows orderly
// shutdown when the generator is shutdown.
func (g *BgBlkTmplGenerator) sendQueueRegenEvent(event regenEvent) {
select {
case g.queueRegenEvent <- event:
case <-g.quit:
}
}

// setCurrentTemplate sets the current template and error associated with the
// background block template generator and notifies the regen event handler
// about the update.
Expand All @@ -2157,7 +2169,7 @@ func (g *BgBlkTmplGenerator) setCurrentTemplate(template *BlockTemplate, reason
g.templateMtx.Unlock()

tplUpdate := templateUpdate{template: template, err: err}
g.queueRegenEvent <- regenEvent{rtTemplateUpdated, tplUpdate}
g.sendQueueRegenEvent(regenEvent{rtTemplateUpdated, tplUpdate})
}

// currentTemplate returns the current template associated with the background
Expand Down Expand Up @@ -3202,14 +3214,14 @@ func (g *BgBlkTmplGenerator) regenHandler(ctx context.Context) {
// chain reorganization has started. It is caller's responsibility to ensure
// this is only invoked as described.
func (g *BgBlkTmplGenerator) ChainReorgStarted() {
g.queueRegenEvent <- regenEvent{rtReorgStarted, nil}
g.sendQueueRegenEvent(regenEvent{rtReorgStarted, nil})
}

// ChainReorgDone informs the background block template generator that a chain
// reorganization has completed. It is caller's responsibility to ensure this
// is only invoked as described.
func (g *BgBlkTmplGenerator) ChainReorgDone() {
g.queueRegenEvent <- regenEvent{rtReorgDone, nil}
g.sendQueueRegenEvent(regenEvent{rtReorgDone, nil})
}

// BlockAccepted informs the background block template generator that a block
Expand All @@ -3218,7 +3230,7 @@ func (g *BgBlkTmplGenerator) ChainReorgDone() {
//
// This function is safe for concurrent access.
func (g *BgBlkTmplGenerator) BlockAccepted(block *dcrutil.Block) {
g.queueRegenEvent <- regenEvent{rtBlockAccepted, block}
g.sendQueueRegenEvent(regenEvent{rtBlockAccepted, block})
}

// BlockConnected informs the background block template generator that a block
Expand All @@ -3227,7 +3239,7 @@ func (g *BgBlkTmplGenerator) BlockAccepted(block *dcrutil.Block) {
//
// This function is safe for concurrent access.
func (g *BgBlkTmplGenerator) BlockConnected(block *dcrutil.Block) {
g.queueRegenEvent <- regenEvent{rtBlockConnected, block}
g.sendQueueRegenEvent(regenEvent{rtBlockConnected, block})
}

// BlockDisconnected informs the background block template generator that a
Expand All @@ -3236,7 +3248,7 @@ func (g *BgBlkTmplGenerator) BlockConnected(block *dcrutil.Block) {
//
// This function is safe for concurrent access.
func (g *BgBlkTmplGenerator) BlockDisconnected(block *dcrutil.Block) {
g.queueRegenEvent <- regenEvent{rtBlockDisconnected, block}
g.sendQueueRegenEvent(regenEvent{rtBlockDisconnected, block})
}

// VoteReceived informs the background block template generator that a new vote
Expand All @@ -3245,7 +3257,7 @@ func (g *BgBlkTmplGenerator) BlockDisconnected(block *dcrutil.Block) {
//
// This function is safe for concurrent access.
func (g *BgBlkTmplGenerator) VoteReceived(tx *dcrutil.Tx) {
g.queueRegenEvent <- regenEvent{rtVote, tx}
g.sendQueueRegenEvent(regenEvent{rtVote, tx})
}

// ForceRegen asks the background block template generator to generate a new
Expand All @@ -3257,16 +3269,21 @@ func (g *BgBlkTmplGenerator) VoteReceived(tx *dcrutil.Tx) {
//
// This function is safe for concurrent access.
func (g *BgBlkTmplGenerator) ForceRegen() {
g.queueRegenEvent <- regenEvent{rtForceRegen, nil}
g.sendQueueRegenEvent(regenEvent{rtForceRegen, nil})
}

// Run starts the background block template generator and all other goroutines
// necessary for it to function properly and blocks until the provided context
// is cancelled.
func (g *BgBlkTmplGenerator) Run(ctx context.Context) {
g.wg.Add(3)
g.wg.Add(4)
go g.regenQueueHandler(ctx)
go g.regenHandler(ctx)
go g.notifySubscribersHandler(ctx)
go func() {
<-ctx.Done()
close(g.quit)
g.wg.Done()
}()
g.wg.Wait()
}