// btcdMain is the real main function for btcd. It is necessary to work around // the fact that deferred functions do not run when os.Exit() is called. The // optional serverChan parameter is mainly used by the service code to be // notified with the server once it is setup so it can gracefully stop it when // requested from the service control manager. func btcdMain(serverChan chan<- *server) error { // Load configuration and parse command line. This function also // initializes logging and configures it accordingly. tcfg, _, err := loadConfig() if err != nil { return err } cfg = tcfg defer backendLog.Flush() // 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 // another subsystem such as the RPC server. interruptedChan := interruptListener() defer btcdLog.Info("Shutdown complete") // Show version at startup. btcdLog.Infof("Version %s", version()) // Enable http profiling server if requested. if cfg.Profile != "" { go func() { listenAddr := net.JoinHostPort("", cfg.Profile) btcdLog.Infof("Profile server listening on %s", listenAddr) profileRedirect := http.RedirectHandler("/debug/pprof", http.StatusSeeOther) http.Handle("/", profileRedirect) btcdLog.Errorf("%v", http.ListenAndServe(listenAddr, nil)) }() } // Write cpu profile if requested. if cfg.CPUProfile != "" { f, err := os.Create(cfg.CPUProfile) if err != nil { btcdLog.Errorf("Unable to create cpu profile: %v", err) return err } pprof.StartCPUProfile(f) defer f.Close() defer pprof.StopCPUProfile() } // Perform upgrades to btcd as new versions require it. if err := doUpgrades(); err != nil { btcdLog.Errorf("%v", err) return err } // Return now if an interrupt signal was triggered. if interruptRequested(interruptedChan) { return nil } // Load the block database. db, err := loadBlockDB() if err != nil { btcdLog.Errorf("%v", err) return err } defer func() { // Ensure the database is sync'd and closed on shutdown. btcdLog.Infof("Gracefully shutting down the database...") db.Close() }() // Return now if an interrupt signal was triggered. if interruptRequested(interruptedChan) { return nil } // Drop indexes and exit if requested. // // NOTE: The order is important here because dropping the tx index also // drops the address index since it relies on it. if cfg.DropAddrIndex { if err := indexers.DropAddrIndex(db); err != nil { btcdLog.Errorf("%v", err) return err } return nil } if cfg.DropTxIndex { if err := indexers.DropTxIndex(db); err != nil { btcdLog.Errorf("%v", err) return err } return nil } // Create server and start it. server, err := newServer(cfg.Listeners, db, activeNetParams.Params) if err != nil { // TODO(oga) this logging could do with some beautifying. btcdLog.Errorf("Unable to start server on %v: %v", cfg.Listeners, err) return err } defer func() { btcdLog.Infof("Gracefully shutting down the server...") server.Stop() server.WaitForShutdown() srvrLog.Infof("Server shutdown complete") }() server.Start() if serverChan != nil { serverChan <- server } // Wait until the interrupt signal is received from an OS signal or // shutdown is requested through one of the subsystems such as the RPC // server. <-interruptedChan return nil }
// btcdMain is the real main function for btcd. It is necessary to work around // the fact that deferred functions do not run when os.Exit() is called. The // optional serverChan parameter is mainly used by the service code to be // notified with the server once it is setup so it can gracefully stop it when // requested from the service control manager. func btcdMain(serverChan chan<- *server) error { // Load configuration and parse command line. This function also // initializes logging and configures it accordingly. tcfg, _, err := loadConfig() if err != nil { return err } cfg = tcfg defer backendLog.Flush() // Show version at startup. btcdLog.Infof("Version %s", version()) // Enable http profiling server if requested. if cfg.Profile != "" { go func() { listenAddr := net.JoinHostPort("", cfg.Profile) btcdLog.Infof("Profile server listening on %s", listenAddr) profileRedirect := http.RedirectHandler("/debug/pprof", http.StatusSeeOther) http.Handle("/", profileRedirect) btcdLog.Errorf("%v", http.ListenAndServe(listenAddr, nil)) }() } // Write cpu profile if requested. if cfg.CPUProfile != "" { f, err := os.Create(cfg.CPUProfile) if err != nil { btcdLog.Errorf("Unable to create cpu profile: %v", err) return err } pprof.StartCPUProfile(f) defer f.Close() defer pprof.StopCPUProfile() } // Perform upgrades to btcd as new versions require it. if err := doUpgrades(); err != nil { btcdLog.Errorf("%v", err) return err } // Load the block database. db, err := loadBlockDB() if err != nil { btcdLog.Errorf("%v", err) return err } defer db.Close() // Ensure the database is sync'd and closed on Ctrl+C. addInterruptHandler(func() { btcdLog.Infof("Gracefully shutting down the database...") db.Close() }) // Drop indexes and exit if requested. // // NOTE: The order is important here because dropping the tx index also // drops the address index since it relies on it. if cfg.DropAddrIndex { if err := indexers.DropAddrIndex(db); err != nil { btcdLog.Errorf("%v", err) return err } return nil } if cfg.DropTxIndex { if err := indexers.DropTxIndex(db); err != nil { btcdLog.Errorf("%v", err) return err } return nil } // Create server and start it. server, err := newServer(cfg.Listeners, db, activeNetParams.Params) if err != nil { // TODO(oga) this logging could do with some beautifying. btcdLog.Errorf("Unable to start server on %v: %v", cfg.Listeners, err) return err } addInterruptHandler(func() { btcdLog.Infof("Gracefully shutting down the server...") server.Stop() server.WaitForShutdown() }) server.Start() if serverChan != nil { serverChan <- server } // Monitor for graceful server shutdown and signal the main goroutine // when done. This is done in a separate goroutine rather than waiting // directly so the main goroutine can be signaled for shutdown by either // a graceful shutdown or from the main interrupt handler. This is // necessary since the main goroutine must be kept running long enough // for the interrupt handler goroutine to finish. go func() { server.WaitForShutdown() srvrLog.Infof("Server shutdown complete") shutdownChannel <- struct{}{} }() // Wait for shutdown signal from either a graceful server stop or from // the interrupt handler. <-shutdownChannel btcdLog.Info("Shutdown complete") return nil }