From d17faf6bcbc15ea0a3c3ea13f100c5aaf5f0384c Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 11 Dec 2022 00:53:12 -0500 Subject: [PATCH] fix #1975 Provide a nondestructive stack trace dump option even when the http pprof listener is disabled --- irc/server.go | 26 +++++++++++++++++++++----- irc/utils/signals.go | 4 ++++ irc/utils/signals_plan9.go | 3 +++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/irc/server.go b/irc/server.go index 5800f5a4..1a7e1abd 100644 --- a/irc/server.go +++ b/irc/server.go @@ -12,6 +12,7 @@ import ( _ "net/http/pprof" "os" "os/signal" + "runtime/pprof" "strconv" "strings" "sync" @@ -83,6 +84,7 @@ type Server struct { rehashSignal chan os.Signal pprofServer *http.Server exitSignals chan os.Signal + tracebackSignal chan os.Signal snomasks SnoManager store *buntdb.DB historyDB mysql.MySQL @@ -98,11 +100,12 @@ type Server struct { func NewServer(config *Config, logger *logger.Manager) (*Server, error) { // initialize data structures server := &Server{ - ctime: time.Now().UTC(), - listeners: make(map[string]IRCListener), - logger: logger, - rehashSignal: make(chan os.Signal, 1), - exitSignals: make(chan os.Signal, len(utils.ServerExitSignals)), + ctime: time.Now().UTC(), + listeners: make(map[string]IRCListener), + logger: logger, + rehashSignal: make(chan os.Signal, 1), + exitSignals: make(chan os.Signal, len(utils.ServerExitSignals)), + tracebackSignal: make(chan os.Signal, len(utils.ServerTracebackSignals)), } server.defcon.Store(5) @@ -120,6 +123,9 @@ func NewServer(config *Config, logger *logger.Manager) (*Server, error) { // Attempt to clean up when receiving these signals. signal.Notify(server.exitSignals, utils.ServerExitSignals...) signal.Notify(server.rehashSignal, syscall.SIGHUP) + if len(utils.ServerTracebackSignals) != 0 { + signal.Notify(server.tracebackSignal, utils.ServerTracebackSignals...) + } time.AfterFunc(alwaysOnMaintenanceInterval, server.periodicAlwaysOnMaintenance) @@ -158,6 +164,8 @@ func (server *Server) Run() { case <-server.rehashSignal: server.logger.Info("server", "Rehashing due to SIGHUP") go server.rehash() + case <-server.tracebackSignal: + go server.dumpStacks() } } } @@ -1128,3 +1136,11 @@ var ( Edmund Huber, edmund-huber `, "\n") ) + +func (server *Server) dumpStacks() { + if gprof := pprof.Lookup("goroutine"); gprof != nil { + gprof.WriteTo(os.Stderr, 2) + } else { + server.logger.Error("internal", "unable to dump goroutine stacks") + } +} diff --git a/irc/utils/signals.go b/irc/utils/signals.go index e381ab6d..20f45301 100644 --- a/irc/utils/signals.go +++ b/irc/utils/signals.go @@ -18,4 +18,8 @@ var ( syscall.SIGTERM, syscall.SIGQUIT, } + + ServerTracebackSignals = []os.Signal{ + syscall.SIGUSR1, + } ) diff --git a/irc/utils/signals_plan9.go b/irc/utils/signals_plan9.go index 318a0552..9e1968e9 100644 --- a/irc/utils/signals_plan9.go +++ b/irc/utils/signals_plan9.go @@ -18,4 +18,7 @@ var ( syscall.SIGINT, syscall.SIGTERM, } + + // no SIGUSR1 on plan9 + ServerTracebackSignals []os.Signal )