diff --git a/addrmgr/addrmanager.go b/addrmgr/addrmanager.go index 0f2b63d16..816fe36fd 100644 --- a/addrmgr/addrmanager.go +++ b/addrmgr/addrmanager.go @@ -717,11 +717,7 @@ func (a *AddrManager) Start() { // Start the address ticker to save addresses periodically. a.wg.Add(1) - spawn(a.addressHandler, a.handlePanic) -} - -func (a *AddrManager) handlePanic() { - atomic.AddInt32(&a.shutdown, 1) + spawn(a.addressHandler) } // Stop gracefully shuts down the address manager by stopping the main handler. diff --git a/addrmgr/log.go b/addrmgr/log.go index 0ff68a7a6..f25419bef 100644 --- a/addrmgr/log.go +++ b/addrmgr/log.go @@ -10,4 +10,4 @@ import ( ) var log, _ = logger.Get(logger.SubsystemTags.ADXR) -var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log) +var spawn = panics.GoroutineWrapperFunc(log) diff --git a/cmd/addblock/addblock.go b/cmd/addblock/addblock.go index ad4adb0a8..16d471fe0 100644 --- a/cmd/addblock/addblock.go +++ b/cmd/addblock/addblock.go @@ -23,7 +23,7 @@ const ( var ( cfg *ConfigFlags - log logs.Logger + log *logs.Logger spawn func(func()) ) diff --git a/cmd/kaspaminer/log.go b/cmd/kaspaminer/log.go index f50c4a4fa..e3ed6115f 100644 --- a/cmd/kaspaminer/log.go +++ b/cmd/kaspaminer/log.go @@ -28,7 +28,5 @@ func initLog(logFile, errLogFile string) { } func enableRPCLogging() { - rpclog := backendLog.Logger("RPCC") - rpclog.SetLevel(logs.LevelTrace) - rpcclient.UseLogger(rpclog) + rpcclient.UseLogger(backendLog, logs.LevelTrace) } diff --git a/cmd/kaspaminer/main.go b/cmd/kaspaminer/main.go index e1f08f94e..97f150386 100644 --- a/cmd/kaspaminer/main.go +++ b/cmd/kaspaminer/main.go @@ -12,7 +12,7 @@ import ( ) func main() { - defer panics.HandlePanic(log, nil, nil) + defer panics.HandlePanic(log, nil) interrupt := signal.InterruptListener() cfg, err := parseConfig() diff --git a/connmgr/connmanager.go b/connmgr/connmanager.go index 316e3119c..99080213f 100644 --- a/connmgr/connmanager.go +++ b/connmgr/connmanager.go @@ -234,7 +234,7 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq, err error) { } spawnAfter(d, func() { cm.Connect(c) - }, nil) + }) } else if cm.cfg.GetNewAddress != nil { cm.failedAttempts++ if cm.failedAttempts >= maxFailedAttempts { @@ -243,9 +243,9 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq, err error) { "-- retrying further connections every %s", maxFailedAttempts, cm.cfg.RetryDuration) } - spawnAfter(cm.cfg.RetryDuration, cm.NewConnReq, cm.handlePanic) + spawnAfter(cm.cfg.RetryDuration, cm.NewConnReq) } else { - spawn(cm.NewConnReq, cm.handlePanic) + spawn(cm.NewConnReq) } } } @@ -377,7 +377,7 @@ out: if cm.cfg.OnDisconnection != nil { spawn(func() { cm.cfg.OnDisconnection(connReq) - }, cm.handlePanic) + }) } // All internal state has been cleaned up, if @@ -576,7 +576,7 @@ func (cm *ConnManager) listenHandler(listener net.Listener) { } spawn(func() { cm.cfg.OnAccept(conn) - }, cm.handlePanic) + }) } cm.wg.Done() @@ -592,7 +592,7 @@ func (cm *ConnManager) Start() { log.Trace("Connection manager started") cm.wg.Add(1) - spawn(cm.connHandler, cm.handlePanic) + spawn(cm.connHandler) // Start all the listeners so long as the caller requested them and // provided a callback to be invoked when connections are accepted. @@ -604,12 +604,12 @@ func (cm *ConnManager) Start() { cm.wg.Add(1) spawn(func() { cm.listenHandler(listenerCopy) - }, cm.handlePanic) + }) } } for i := atomic.LoadUint64(&cm.connReqCount); i < uint64(cm.cfg.TargetOutbound); i++ { - spawn(cm.NewConnReq, cm.handlePanic) + spawn(cm.NewConnReq) } } @@ -618,10 +618,6 @@ func (cm *ConnManager) Wait() { cm.wg.Wait() } -func (cm *ConnManager) handlePanic() { - atomic.AddInt32(&cm.stop, 1) -} - // Stop gracefully shuts down the connection manager. func (cm *ConnManager) Stop() { if atomic.AddInt32(&cm.stop, 1) != 1 { diff --git a/connmgr/log.go b/connmgr/log.go index c7a747829..ce983fdd2 100644 --- a/connmgr/log.go +++ b/connmgr/log.go @@ -10,5 +10,5 @@ import ( ) var log, _ = logger.Get(logger.SubsystemTags.CMGR) -var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log) -var spawnAfter = panics.AfterFuncWrapperFuncWithPanicHandler(log) +var spawn = panics.GoroutineWrapperFunc(log) +var spawnAfter = panics.AfterFuncWrapperFunc(log) diff --git a/connmgr/seed.go b/connmgr/seed.go index c13961ca2..b1805bcf2 100644 --- a/connmgr/seed.go +++ b/connmgr/seed.go @@ -94,6 +94,6 @@ func SeedFromDNS(dagParams *dagconfig.Params, reqServices wire.ServiceFlag, incl } seedFn(addresses) - }, nil) + }) } } diff --git a/database/cmd/dbtool/main.go b/database/cmd/dbtool/main.go index 7c10bfab2..9a23a1a4e 100644 --- a/database/cmd/dbtool/main.go +++ b/database/cmd/dbtool/main.go @@ -24,7 +24,7 @@ const ( ) var ( - log logs.Logger + log *logs.Logger spawn func(func()) shutdownChannel = make(chan error) ) diff --git a/kaspad.go b/kaspad.go index 3cc33fcf7..8c4dd186a 100644 --- a/kaspad.go +++ b/kaspad.go @@ -59,7 +59,7 @@ func kaspadMain(serverChan chan<- *server.Server) error { return err } cfg = config.ActiveConfig() - defer panics.HandlePanic(kasdLog, nil, nil) + defer panics.HandlePanic(kasdLog, nil) // Get a channel that will be closed when a shutdown signal has been // triggered either from an OS signal such as SIGINT (Ctrl+C) or from diff --git a/logger/logger.go b/logger/logger.go index 86b91ead3..ac54c966b 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -87,7 +87,7 @@ var SubsystemTags = struct { } // subsystemLoggers maps each subsystem identifier to its associated logger. -var subsystemLoggers = map[string]logs.Logger{ +var subsystemLoggers = map[string]*logs.Logger{ SubsystemTags.ADXR: adxrLog, SubsystemTags.AMGR: amgrLog, SubsystemTags.CMGR: cmgrLog, @@ -180,7 +180,7 @@ func SupportedSubsystems() []string { } // Get returns a logger of a specific sub system -func Get(tag string) (logger logs.Logger, ok bool) { +func Get(tag string) (logger *logs.Logger, ok bool) { logger, ok = subsystemLoggers[tag] return } diff --git a/logs/interface.go b/logs/interface.go deleted file mode 100644 index 994f88c5a..000000000 --- a/logs/interface.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2013-2017 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package logs - -// Logger is an interface which describes a level-based logger. A default -// implementation of Logger is implemented by this package and can be created -// by calling (*Backend).Logger. -type Logger interface { - // Tracef formats message according to format specifier and writes to - // to log with LevelTrace. - Tracef(format string, params ...interface{}) - - // Debugf formats message according to format specifier and writes to - // log with LevelDebug. - Debugf(format string, params ...interface{}) - - // Infof formats message according to format specifier and writes to - // log with LevelInfo. - Infof(format string, params ...interface{}) - - // Warnf formats message according to format specifier and writes to - // to log with LevelWarn. - Warnf(format string, params ...interface{}) - - // Errorf formats message according to format specifier and writes to - // to log with LevelError. - Errorf(format string, params ...interface{}) - - // Criticalf formats message according to format specifier and writes to - // log with LevelCritical. - Criticalf(format string, params ...interface{}) - - // Trace formats message using the default formats for its operands - // and writes to log with LevelTrace. - Trace(v ...interface{}) - - // Debug formats message using the default formats for its operands - // and writes to log with LevelDebug. - Debug(v ...interface{}) - - // Info formats message using the default formats for its operands - // and writes to log with LevelInfo. - Info(v ...interface{}) - - // Warn formats message using the default formats for its operands - // and writes to log with LevelWarn. - Warn(v ...interface{}) - - // Error formats message using the default formats for its operands - // and writes to log with LevelError. - Error(v ...interface{}) - - // Critical formats message using the default formats for its operands - // and writes to log with LevelCritical. - Critical(v ...interface{}) - - // Level returns the current logging level. - Level() Level - - // SetLevel changes the logging level to the passed level. - SetLevel(level Level) -} diff --git a/logs/logs.go b/logs/logs.go index efe17220d..0041bb24e 100644 --- a/logs/logs.go +++ b/logs/logs.go @@ -354,12 +354,12 @@ func (b *Backend) Close() { // Logger returns a new logger for a particular subsystem that writes to the // Backend b. A tag describes the subsystem and is included in all log // messages. The logger uses the info verbosity level by default. -func (b *Backend) Logger(subsystemTag string) Logger { - return &slog{LevelInfo, subsystemTag, b} +func (b *Backend) Logger(subsystemTag string) *Logger { + return &Logger{LevelInfo, subsystemTag, b} } -// slog is a subsystem logger for a Backend. Implements the Logger interface. -type slog struct { +// Logger is a subsystem logger for a Backend. +type Logger struct { lvl Level // atomic tag string b *Backend @@ -367,9 +367,7 @@ type slog struct { // Trace formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelTrace. -// -// This is part of the Logger interface implementation. -func (l *slog) Trace(args ...interface{}) { +func (l *Logger) Trace(args ...interface{}) { lvl := l.Level() if lvl <= LevelTrace { l.b.print(LevelTrace, l.tag, args...) @@ -378,9 +376,7 @@ func (l *slog) Trace(args ...interface{}) { // Tracef formats message according to format specifier, prepends the prefix as // necessary, and writes to log with LevelTrace. -// -// This is part of the Logger interface implementation. -func (l *slog) Tracef(format string, args ...interface{}) { +func (l *Logger) Tracef(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelTrace { l.b.printf(LevelTrace, l.tag, format, args...) @@ -389,9 +385,7 @@ func (l *slog) Tracef(format string, args ...interface{}) { // Debug formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelDebug. -// -// This is part of the Logger interface implementation. -func (l *slog) Debug(args ...interface{}) { +func (l *Logger) Debug(args ...interface{}) { lvl := l.Level() if lvl <= LevelDebug { l.b.print(LevelDebug, l.tag, args...) @@ -400,9 +394,7 @@ func (l *slog) Debug(args ...interface{}) { // Debugf formats message according to format specifier, prepends the prefix as // necessary, and writes to log with LevelDebug. -// -// This is part of the Logger interface implementation. -func (l *slog) Debugf(format string, args ...interface{}) { +func (l *Logger) Debugf(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelDebug { l.b.printf(LevelDebug, l.tag, format, args...) @@ -411,9 +403,7 @@ func (l *slog) Debugf(format string, args ...interface{}) { // Info formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelInfo. -// -// This is part of the Logger interface implementation. -func (l *slog) Info(args ...interface{}) { +func (l *Logger) Info(args ...interface{}) { lvl := l.Level() if lvl <= LevelInfo { l.b.print(LevelInfo, l.tag, args...) @@ -422,9 +412,7 @@ func (l *slog) Info(args ...interface{}) { // Infof formats message according to format specifier, prepends the prefix as // necessary, and writes to log with LevelInfo. -// -// This is part of the Logger interface implementation. -func (l *slog) Infof(format string, args ...interface{}) { +func (l *Logger) Infof(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelInfo { l.b.printf(LevelInfo, l.tag, format, args...) @@ -433,9 +421,7 @@ func (l *slog) Infof(format string, args ...interface{}) { // Warn formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelWarn. -// -// This is part of the Logger interface implementation. -func (l *slog) Warn(args ...interface{}) { +func (l *Logger) Warn(args ...interface{}) { lvl := l.Level() if lvl <= LevelWarn { l.b.print(LevelWarn, l.tag, args...) @@ -444,9 +430,7 @@ func (l *slog) Warn(args ...interface{}) { // Warnf formats message according to format specifier, prepends the prefix as // necessary, and writes to log with LevelWarn. -// -// This is part of the Logger interface implementation. -func (l *slog) Warnf(format string, args ...interface{}) { +func (l *Logger) Warnf(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelWarn { l.b.printf(LevelWarn, l.tag, format, args...) @@ -455,9 +439,7 @@ func (l *slog) Warnf(format string, args ...interface{}) { // Error formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelError. -// -// This is part of the Logger interface implementation. -func (l *slog) Error(args ...interface{}) { +func (l *Logger) Error(args ...interface{}) { lvl := l.Level() if lvl <= LevelError { l.b.print(LevelError, l.tag, args...) @@ -466,9 +448,7 @@ func (l *slog) Error(args ...interface{}) { // Errorf formats message according to format specifier, prepends the prefix as // necessary, and writes to log with LevelError. -// -// This is part of the Logger interface implementation. -func (l *slog) Errorf(format string, args ...interface{}) { +func (l *Logger) Errorf(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelError { l.b.printf(LevelError, l.tag, format, args...) @@ -477,9 +457,7 @@ func (l *slog) Errorf(format string, args ...interface{}) { // Critical formats message using the default formats for its operands, prepends // the prefix as necessary, and writes to log with LevelCritical. -// -// This is part of the Logger interface implementation. -func (l *slog) Critical(args ...interface{}) { +func (l *Logger) Critical(args ...interface{}) { lvl := l.Level() if lvl <= LevelCritical { l.b.print(LevelCritical, l.tag, args...) @@ -488,9 +466,7 @@ func (l *slog) Critical(args ...interface{}) { // Criticalf formats message according to format specifier, prepends the prefix // as necessary, and writes to log with LevelCritical. -// -// This is part of the Logger interface implementation. -func (l *slog) Criticalf(format string, args ...interface{}) { +func (l *Logger) Criticalf(format string, args ...interface{}) { lvl := l.Level() if lvl <= LevelCritical { l.b.printf(LevelCritical, l.tag, format, args...) @@ -498,22 +474,16 @@ func (l *slog) Criticalf(format string, args ...interface{}) { } // Level returns the current logging level -// -// This is part of the Logger interface implementation. -func (l *slog) Level() Level { +func (l *Logger) Level() Level { return Level(atomic.LoadUint32((*uint32)(&l.lvl))) } // SetLevel changes the logging level to the passed level. -// -// This is part of the Logger interface implementation. -func (l *slog) SetLevel(level Level) { +func (l *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&l.lvl), uint32(level)) } -// Disabled is a Logger that will never output anything. -var Disabled Logger - -func init() { - Disabled = &slog{lvl: LevelOff, b: NewBackend()} +// Backend returns the log backend +func (l *Logger) Backend() *Backend { + return l.b } diff --git a/mining/txselection.go b/mining/txselection.go index b2c1c8c53..f75fc525f 100644 --- a/mining/txselection.go +++ b/mining/txselection.go @@ -306,7 +306,7 @@ func (g *BlkTmplGenerator) populateTemplateFromCandidates(candidateTxs []*candid txsForBlockTemplate.totalMass += selectedTx.txMass txsForBlockTemplate.totalFees += selectedTx.txDesc.Fee - log.Tracef("Adding tx %s (feePerKB %.2f)", + log.Tracef("Adding tx %s (feePerKB %d)", tx.ID(), selectedTx.txDesc.FeePerKB) markCandidateTxForDeletion(selectedTx) diff --git a/netsync/blocklogger.go b/netsync/blocklogger.go index 582625840..e642eef0c 100644 --- a/netsync/blocklogger.go +++ b/netsync/blocklogger.go @@ -20,7 +20,7 @@ type blockProgressLogger struct { receivedLogTx int64 lastBlockLogTime time.Time - subsystemLogger logs.Logger + subsystemLogger *logs.Logger progressAction string sync.Mutex } @@ -29,7 +29,7 @@ type blockProgressLogger struct { // The progress message is templated as follows: // {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} // ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) -func newBlockProgressLogger(progressMessage string, logger logs.Logger) *blockProgressLogger { +func newBlockProgressLogger(progressMessage string, logger *logs.Logger) *blockProgressLogger { return &blockProgressLogger{ lastBlockLogTime: time.Now(), progressAction: progressMessage, diff --git a/netsync/log.go b/netsync/log.go index c6e32eab4..6a7d7db73 100644 --- a/netsync/log.go +++ b/netsync/log.go @@ -10,4 +10,4 @@ import ( ) var log, _ = logger.Get(logger.SubsystemTags.SYNC) -var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log) +var spawn = panics.GoroutineWrapperFunc(log) diff --git a/netsync/manager.go b/netsync/manager.go index 3fcc0cc64..f180b4792 100644 --- a/netsync/manager.go +++ b/netsync/manager.go @@ -995,7 +995,7 @@ func (sm *SyncManager) handleBlockDAGNotification(notification *blockdag.Notific if err != nil { panic(fmt.Sprintf("HandleNewBlock failed to handle block %s", block.Hash())) } - }, sm.handlePanic) + }) // Relay if we are current and the block was not just now unorphaned. // Otherwise peers that are current should already know about it @@ -1098,11 +1098,7 @@ func (sm *SyncManager) Start() { log.Trace("Starting sync manager") sm.wg.Add(1) - spawn(sm.messageHandler, sm.handlePanic) -} - -func (sm *SyncManager) handlePanic() { - atomic.AddInt32(&sm.shutdown, 1) + spawn(sm.messageHandler) } // Stop gracefully shuts down the sync manager by stopping all asynchronous diff --git a/peer/peer.go b/peer/peer.go index 6617ee599..6074aa794 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -1199,7 +1199,7 @@ out: handlerActive = false default: - log.Warnf("Unsupported message command %s", + log.Warnf("Unsupported message command %d", msg.command) } diff --git a/rpcclient/log.go b/rpcclient/log.go index f7dcdd4b9..aae678c28 100644 --- a/rpcclient/log.go +++ b/rpcclient/log.go @@ -12,9 +12,11 @@ import ( // log is a logger that is initialized with no output filters. This // means the package will not perform any logging by default until the caller // requests it. -var log logs.Logger +var log *logs.Logger var spawn func(func()) +const logSubsytem = "RPCC" + // The default amount of logging is none. func init() { DisableLog() @@ -23,12 +25,15 @@ func init() { // DisableLog disables all library log output. Logging output is disabled // by default until UseLogger is called. func DisableLog() { - log = logs.Disabled + backend := logs.NewBackend() + log = backend.Logger(logSubsytem) + log.SetLevel(logs.LevelOff) spawn = panics.GoroutineWrapperFunc(log) } // UseLogger uses a specified Logger to output package logging info. -func UseLogger(logger logs.Logger) { - log = logger +func UseLogger(backend *logs.Backend, level logs.Level) { + log = backend.Logger(logSubsytem) + log.SetLevel(level) spawn = panics.GoroutineWrapperFunc(log) } diff --git a/server/p2p/on_get_addr.go b/server/p2p/on_get_addr.go index 002cb5e11..2a3d1b0bd 100644 --- a/server/p2p/on_get_addr.go +++ b/server/p2p/on_get_addr.go @@ -21,16 +21,14 @@ func (sp *Peer) OnGetAddr(_ *peer.Peer, msg *wire.MsgGetAddr) { // Do not accept getaddr requests from outbound peers. This reduces // fingerprinting attacks. if !sp.Inbound() { - peerLog.Debugf("Ignoring getaddr request from outbound peer ", - "%s", sp) + peerLog.Debugf("Ignoring getaddr request from outbound peer %s", sp) return } // Only allow one getaddr request per connection to discourage // address stamping of inv announcements. if sp.sentAddrs { - peerLog.Debugf("Ignoring repeated getaddr request from peer ", - "%s", sp) + peerLog.Debugf("Ignoring repeated getaddr request from peer %s", sp) return } sp.sentAddrs = true diff --git a/signal/signal.go b/signal/signal.go index 75d110467..f37480ca4 100644 --- a/signal/signal.go +++ b/signal/signal.go @@ -13,10 +13,6 @@ import ( // subsystems using the same code paths as when an interrupt signal is received. var ShutdownRequestChannel = make(chan struct{}) -// PanicShutdownChannel is used to initiate shutdown when any thread -// panics using the same code paths as when an interrupt signal is received. -var PanicShutdownChannel = make(chan struct{}) - // interruptSignals defines the default signals to catch in order to do a proper // shutdown. This may be modified during init depending on the platform. var interruptSignals = []os.Signal{os.Interrupt} @@ -39,9 +35,6 @@ func InterruptListener() <-chan struct{} { case <-ShutdownRequestChannel: kasdLog.Info("Shutdown requested. Shutting down...") - - case <-PanicShutdownChannel: - kasdLog.Info("Panic occurred. Shutting down...") } close(c) @@ -57,11 +50,6 @@ func InterruptListener() <-chan struct{} { case <-ShutdownRequestChannel: kasdLog.Info("Shutdown requested. Already " + "shutting down...") - - case <-PanicShutdownChannel: - kasdLog.Info("Panic occurred while shutting down. " + - "Forcing shut down...") - os.Exit(1) } } }() diff --git a/util/locks/log.go b/util/locks/log.go deleted file mode 100644 index 85121bf22..000000000 --- a/util/locks/log.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2013-2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package locks - -import ( - "github.com/kaspanet/kaspad/logger" - "github.com/kaspanet/kaspad/util/panics" -) - -var ( - log, _ = logger.Get(logger.SubsystemTags.UTIL) - spawn = panics.GoroutineWrapperFunc(log) -) diff --git a/util/locks/waitgroup_test.go b/util/locks/waitgroup_test.go index db92feddd..b476b66e5 100644 --- a/util/locks/waitgroup_test.go +++ b/util/locks/waitgroup_test.go @@ -7,7 +7,6 @@ package locks import ( "sync/atomic" "testing" - "time" ) // All of the tests, except TestAddAfterWait and @@ -17,29 +16,6 @@ import ( // behaves the same, except enabling the use of add() // concurrently with wait() -func spawnPatch(t *testing.T) (checkIfRunningSpawnsAreLeft func()) { - realSpawn := spawn - runningSpawns := int32(0) - spawn = func(f func()) { - atomic.AddInt32(&runningSpawns, 1) - realSpawn(func() { - f() - atomic.AddInt32(&runningSpawns, -1) - }) - } - return func() { - defer func() { - spawn = realSpawn - }() - if runningSpawns != 0 { - time.Sleep(10 * time.Millisecond) - if runningSpawns != 0 { - t.Fatalf("%d running spawns left", runningSpawns) - } - } - } -} - func testWaitGroup(t *testing.T, wg1 *waitGroup, wg2 *waitGroup) { n := int64(16) wg1.add(n) @@ -67,8 +43,6 @@ func testWaitGroup(t *testing.T, wg1 *waitGroup, wg2 *waitGroup) { } func TestWaitGroup(t *testing.T) { - checkIfRunningSpawnsAreLeft := spawnPatch(t) - defer checkIfRunningSpawnsAreLeft() wg1 := newWaitGroup() wg2 := newWaitGroup() @@ -94,8 +68,6 @@ func TestWaitGroupMisuse(t *testing.T) { } func TestAddAfterWait(t *testing.T) { - checkIfRunningSpawnsAreLeft := spawnPatch(t) - defer checkIfRunningSpawnsAreLeft() wg := newWaitGroup() wg.add(1) syncChan := make(chan struct{}) @@ -113,8 +85,6 @@ func TestAddAfterWait(t *testing.T) { } func TestWaitGroupRace(t *testing.T) { - checkIfRunningSpawnsAreLeft := spawnPatch(t) - defer checkIfRunningSpawnsAreLeft() // Run this test for about 1ms. for i := 0; i < 1000; i++ { wg := newWaitGroup() @@ -141,8 +111,6 @@ func TestWaitGroupRace(t *testing.T) { } func TestWaitGroupAlign(t *testing.T) { - checkIfRunningSpawnsAreLeft := spawnPatch(t) - defer checkIfRunningSpawnsAreLeft() type X struct { x byte wg *waitGroup @@ -157,8 +125,6 @@ func TestWaitGroupAlign(t *testing.T) { } func TestWaitAfterAddDoneCounterHasReset(t *testing.T) { - checkIfRunningSpawnsAreLeft := spawnPatch(t) - defer checkIfRunningSpawnsAreLeft() wg := newWaitGroup() wg.add(1) wg.done() diff --git a/util/panics/panics.go b/util/panics/panics.go index a3550eb8d..ec1fd7bfc 100644 --- a/util/panics/panics.go +++ b/util/panics/panics.go @@ -1,69 +1,58 @@ package panics import ( + "fmt" "github.com/kaspanet/kaspad/logs" - "github.com/kaspanet/kaspad/signal" + "os" "runtime/debug" "time" ) // HandlePanic recovers panics, log them, runs an optional panicHandler, // and then initiates a clean shutdown. -func HandlePanic(log logs.Logger, goroutineStackTrace []byte, panicHandler func()) { - if err := recover(); err != nil { +func HandlePanic(log *logs.Logger, goroutineStackTrace []byte) { + err := recover() + if err == nil { + return + } + + panicHandlerDone := make(chan struct{}) + go func() { log.Criticalf("Fatal error: %+v", err) if goroutineStackTrace != nil { - log.Criticalf("goroutine stack trace: %s", goroutineStackTrace) + log.Criticalf("Goroutine stack trace: %s", goroutineStackTrace) } log.Criticalf("Stack trace: %s", debug.Stack()) - if panicHandler != nil { - panicHandler() - } - signal.PanicShutdownChannel <- struct{}{} + log.Backend().Close() + panicHandlerDone <- struct{}{} + }() + + const panicHandlerTimeout = 5 * time.Second + select { + case <-time.Tick(panicHandlerTimeout): + fmt.Fprintln(os.Stderr, "Couldn't handle a fatal error. Exiting...") + case <-panicHandlerDone: } + os.Exit(1) } // GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and writes them to the log. -func GoroutineWrapperFunc(log logs.Logger) func(func()) { +func GoroutineWrapperFunc(log *logs.Logger) func(func()) { return func(f func()) { stackTrace := debug.Stack() go func() { - defer HandlePanic(log, stackTrace, nil) - f() - }() - } -} - -// GoroutineWrapperFuncWithPanicHandler returns a goroutine wrapper function that handles panics, -// writes them to the log, and executes a handler function for panics. -func GoroutineWrapperFuncWithPanicHandler(log logs.Logger) func(func(), func()) { - return func(f func(), panicHandler func()) { - stackTrace := debug.Stack() - go func() { - defer HandlePanic(log, stackTrace, panicHandler) + defer HandlePanic(log, stackTrace) f() }() } } // AfterFuncWrapperFunc returns a time.AfterFunc wrapper function that handles panics. -func AfterFuncWrapperFunc(log logs.Logger) func(d time.Duration, f func()) *time.Timer { +func AfterFuncWrapperFunc(log *logs.Logger) func(d time.Duration, f func()) *time.Timer { return func(d time.Duration, f func()) *time.Timer { stackTrace := debug.Stack() return time.AfterFunc(d, func() { - defer HandlePanic(log, stackTrace, nil) - f() - }) - } -} - -// AfterFuncWrapperFuncWithPanicHandler returns a time.AfterFunc wrapper function that handles panics, -// writes them to the log, and executes a handler function for panics. -func AfterFuncWrapperFuncWithPanicHandler(log logs.Logger) func(d time.Duration, f func(), panicHandler func()) *time.Timer { - return func(d time.Duration, f func(), panicHandler func()) *time.Timer { - stackTrace := debug.Stack() - return time.AfterFunc(d, func() { - defer HandlePanic(log, stackTrace, panicHandler) + defer HandlePanic(log, stackTrace) f() }) }