From def39799c52846058c6b871812b4261032b48fea Mon Sep 17 00:00:00 2001 From: bryanvu Date: Thu, 15 Dec 2016 01:07:12 -0800 Subject: [PATCH] chainntnfs: handling for potential deadlocks during system shutdown If the lnd daemon is shut down while multiple subsystems are attempting to register for notifications, the blocking of those chain notifier registrations may cause the daemon shutdown to deadlock. The additions in this commit allow the registration functions to return errors rather than potentially deadlock when the chain notifier is shut down. --- chainntnfs/btcdnotify/btcd.go | 38 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/chainntnfs/btcdnotify/btcd.go b/chainntnfs/btcdnotify/btcd.go index b6ef34ad..77c9f88f 100644 --- a/chainntnfs/btcdnotify/btcd.go +++ b/chainntnfs/btcdnotify/btcd.go @@ -2,6 +2,7 @@ package btcdnotify import ( "container/heap" + "errors" "sync" "sync/atomic" "time" @@ -546,7 +547,12 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint) (*chainntnfs.S spendChan: make(chan *chainntnfs.SpendDetail, 1), } - b.notificationRegistry <- ntfn + select { + case <-b.quit: + return nil, errors.New("chainntnfs: system interrupt while " + + "attempting to register for spend notification.") + case b.notificationRegistry <- ntfn: + } // The following conditional checks to ensure that when a spend notification // is registered, the output hasn't already been spent. If the output @@ -603,12 +609,16 @@ func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *wire.ShaHash, negativeConf: make(chan int32, 1), } - b.notificationRegistry <- ntfn - - return &chainntnfs.ConfirmationEvent{ - Confirmed: ntfn.finConf, - NegativeConf: ntfn.negativeConf, - }, nil + select { + case <-b.quit: + return nil, errors.New("chainntnfs: system interrupt while " + + "attempting to register for confirmation notification.") + case b.notificationRegistry <- ntfn: + return &chainntnfs.ConfirmationEvent{ + Confirmed: ntfn.finConf, + NegativeConf: ntfn.negativeConf, + }, nil + } } // blockEpochRegistration represents a client's intent to receive a @@ -625,9 +635,13 @@ func (b *BtcdNotifier) RegisterBlockEpochNtfn() (*chainntnfs.BlockEpochEvent, er epochChan: make(chan *chainntnfs.BlockEpoch, 20), } - b.notificationRegistry <- registration - - return &chainntnfs.BlockEpochEvent{ - Epochs: registration.epochChan, - }, nil + select { + case <-b.quit: + return nil, errors.New("chainntnfs: system interrupt while " + + "attempting to register for block epoch notification.") + case b.notificationRegistry <- registration: + return &chainntnfs.BlockEpochEvent{ + Epochs: registration.epochChan, + }, nil + } }