cmd/geth, cmd/utils: improve interrupt handling
The new strategy for interrupts is to handle them explicitly. Ethereum.Stop is now only called once, even if multiple interrupts are sent. Interrupting ten times in a row forces a panic. Fixes #869 Fixes #1359
This commit is contained in:
		@@ -347,7 +347,6 @@ func main() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func run(ctx *cli.Context) {
 | 
					func run(ctx *cli.Context) {
 | 
				
			||||||
	utils.HandleInterrupt()
 | 
					 | 
				
			||||||
	cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
 | 
						cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
 | 
				
			||||||
	ethereum, err := eth.New(cfg)
 | 
						ethereum, err := eth.New(cfg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -527,10 +526,9 @@ func blockRecovery(ctx *cli.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
 | 
					func startEth(ctx *cli.Context, eth *eth.Ethereum) {
 | 
				
			||||||
	// Start Ethereum itself
 | 
						// Start Ethereum itself
 | 
				
			||||||
 | 
					 | 
				
			||||||
	utils.StartEthereum(eth)
 | 
						utils.StartEthereum(eth)
 | 
				
			||||||
	am := eth.AccountManager()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						am := eth.AccountManager()
 | 
				
			||||||
	account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
 | 
						account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
 | 
				
			||||||
	accounts := strings.Split(account, " ")
 | 
						accounts := strings.Split(account, " ")
 | 
				
			||||||
	for i, account := range accounts {
 | 
						for i, account := range accounts {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,29 +46,6 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var interruptCallbacks = []func(os.Signal){}
 | 
					var interruptCallbacks = []func(os.Signal){}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Register interrupt handlers callbacks
 | 
					 | 
				
			||||||
func RegisterInterrupt(cb func(os.Signal)) {
 | 
					 | 
				
			||||||
	interruptCallbacks = append(interruptCallbacks, cb)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// go routine that call interrupt handlers in order of registering
 | 
					 | 
				
			||||||
func HandleInterrupt() {
 | 
					 | 
				
			||||||
	c := make(chan os.Signal, 1)
 | 
					 | 
				
			||||||
	go func() {
 | 
					 | 
				
			||||||
		signal.Notify(c, os.Interrupt)
 | 
					 | 
				
			||||||
		for sig := range c {
 | 
					 | 
				
			||||||
			glog.V(logger.Error).Infof("Shutting down (%v) ... \n", sig)
 | 
					 | 
				
			||||||
			RunInterruptCallbacks(sig)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func RunInterruptCallbacks(sig os.Signal) {
 | 
					 | 
				
			||||||
	for _, cb := range interruptCallbacks {
 | 
					 | 
				
			||||||
		cb(sig)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func openLogFile(Datadir string, filename string) *os.File {
 | 
					func openLogFile(Datadir string, filename string) *os.File {
 | 
				
			||||||
	path := common.AbsolutePath(Datadir, filename)
 | 
						path := common.AbsolutePath(Datadir, filename)
 | 
				
			||||||
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
 | 
						file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
 | 
				
			||||||
@@ -149,19 +126,24 @@ func StartEthereum(ethereum *eth.Ethereum) {
 | 
				
			|||||||
	if err := ethereum.Start(); err != nil {
 | 
						if err := ethereum.Start(); err != nil {
 | 
				
			||||||
		Fatalf("Error starting Ethereum: %v", err)
 | 
							Fatalf("Error starting Ethereum: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	RegisterInterrupt(func(sig os.Signal) {
 | 
						go func() {
 | 
				
			||||||
 | 
							sigc := make(chan os.Signal, 1)
 | 
				
			||||||
 | 
							signal.Notify(sigc, os.Interrupt)
 | 
				
			||||||
 | 
							defer signal.Stop(sigc)
 | 
				
			||||||
 | 
							<-sigc
 | 
				
			||||||
 | 
							glog.V(logger.Info).Infoln("Got interrupt, shutting down...")
 | 
				
			||||||
		ethereum.Stop()
 | 
							ethereum.Stop()
 | 
				
			||||||
		logger.Flush()
 | 
							logger.Flush()
 | 
				
			||||||
	})
 | 
							for i := 10; i > 0; i-- {
 | 
				
			||||||
}
 | 
								<-sigc
 | 
				
			||||||
 | 
								if i > 1 {
 | 
				
			||||||
func StartEthereumForTest(ethereum *eth.Ethereum) {
 | 
									glog.V(logger.Info).Infoln("Already shutting down, please be patient.")
 | 
				
			||||||
	glog.V(logger.Info).Infoln("Starting ", ethereum.Name())
 | 
									glog.V(logger.Info).Infoln("Interrupt", i-1, "more times to induce panic.")
 | 
				
			||||||
	ethereum.StartForTest()
 | 
								}
 | 
				
			||||||
	RegisterInterrupt(func(sig os.Signal) {
 | 
							}
 | 
				
			||||||
		ethereum.Stop()
 | 
							glog.V(logger.Error).Infof("Force quitting: this might not end so well.")
 | 
				
			||||||
		logger.Flush()
 | 
							panic("boom")
 | 
				
			||||||
	})
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FormatTransactionData(data string) []byte {
 | 
					func FormatTransactionData(data string) []byte {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user