// WaitSignal waits for signals to gracefully terminate or restart the process. // When code runs as a daemon process, it is often hoped running without any stop. // So some works should be done on the flying. // Some signals suggestion usage are listed herein. func (gs *GraceServer) WaitSignal() error { ch := make(chan os.Signal, 6) signal.Notify(ch, syscall.SIGTERM, // TERM : Exit immediatly syscall.SIGINT, // INT : Exit immediatly syscall.SIGQUIT, // QUIT : Exit gracefully syscall.SIGHUP, // HUP : Gracefully reload configure and restart // USR1 : Reopen log file // USR2 : Update gracefully // SIGWINCH : Exit worker process gracefully // SIGSTOP, SIGKILL : Need not captured at anytime, process will quit immediatly ) for { sig := <-ch switch sig { case syscall.SIGTERM: fallthrough case syscall.SIGINT: signal.Stop(ch) return nil case syscall.SIGQUIT: signal.Stop(ch) return gs.closeListener() case syscall.SIGHUP: // we only return here if there's an error, otherwise the new process // will send us a TERM when it's ready to trigger the actual shutdown. if err := gs.restart(); err != nil { return err } } } }
func Connect(name, token string, factory Factory, config *ServerConfig) { c, err := connect(name, token, factory, config) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(exitFail) } fmt.Fprintf(os.Stderr, "Connected bot %s. Ctrl-C or send SIGINT to disconnect.\n", name) retryChan := make(chan time.Time) cWait := func() { c.conn.Wait() retryChan <- time.Now() } go cWait() sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGINT, syscall.SIGQUIT) // Wait for either our connection with the server to terminate, or the user // to mercilessly silence their bot. loop: for { select { case <-retryChan: fmt.Fprintln(os.Stderr, "Lost connection to server, trying to reconnect...") c, err = connect(name, token, factory, config) if err == nil { fmt.Fprintf(os.Stderr, "Reconnected bot %s successfully!\n", name) // Wait until we lose the connection again go cWait() } else { if strings.Contains(err.Error(), "connection refused") { // If we can't connect, just wait ten (or --retry_interval) seconds and try again go func() { retryChan <- <-time.After(config.RetryInterval) }() } else { // Fail on all other errors, like the server saying you have an invalid token fmt.Fprintln(os.Stderr, err) os.Exit(exitFail) } } case <-sig: signal.Stop(sig) break loop } } signal.Stop(sig) fmt.Fprintln(os.Stderr, "Interrupted. Quitting...") if c != nil { if err := c.Close(); err != nil { fmt.Fprintln(os.Stderr, "Error closing our connection:", err) os.Exit(exitFail) } } }
func TestSignalsAreDeliveredToMultipleListeners(t *testing.T) { c1 := make(chan os.Signal, 1) c2 := make(chan os.Signal, 1) signal.Notify(c1, syscall.SIGWINCH) signal.Notify(c2, syscall.SIGWINCH) defer signal.Stop(c1) defer signal.Stop(c2) syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) waitSig(t, c1, syscall.SIGWINCH) waitSig(t, c2, syscall.SIGWINCH) }
func main() { cli := CLI{} config := cli.ParseArgs() errs := config.Errors() if len(errs) > 0 { for _, e := range errs { fmt.Println(e) } os.Exit(1) } if config.Debug { log.Printf("Starting with config: %+v\n", config) } // shutdown signal handler; must be buffered, or risk missing the signal // if we're not ready to receive when the signal is sent. sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) transport, err := flapjack.Dial(config.RedisServer, config.RedisDatabase) if err != nil { log.Fatalf("Couldn't establish Redis connection: %s\n", err) } finished := make(chan error) api_client := ApiClient{config: config, redis: transport} api_client.Connect(finished) select { case err := <-finished: if config.Debug { log.Printf("Finished with error // %s\n", err) } signal.Stop(sigs) case <-sigs: log.Println("Interrupted, cancelling request") signal.Stop(sigs) // TODO determine if request not currently active... api_client.Cancel() } // close redis connection transport.Close() }
// setupStdin switches out stdin for a pipe. We do this so that we can // close the writer end of the pipe when we receive an interrupt so plugins // blocked on reading from stdin are unblocked. func setupStdin() { // Create the pipe and swap stdin for the reader end r, w, _ := os.Pipe() originalStdin := os.Stdin os.Stdin = r // Create a goroutine that copies data from the original stdin // into the writer end of the pipe forever. go func() { defer w.Close() io.Copy(w, originalStdin) }() // Register a signal handler for interrupt in order to close the // writer end of our pipe so that readers get EOF downstream. ch := make(chan os.Signal, 1) signal.Notify(ch, os.Interrupt) go func() { defer signal.Stop(ch) defer w.Close() <-ch log.Println("Closing stdin because interrupt received.") }() }
// AskString asks user to input some string func (cli CLI) AskString(query string, defaultStr string) (string, error) { sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) defer signal.Stop(sigCh) result := make(chan string, 1) go func() { fmt.Fprintf(cli.errStream, "%s [default: %s] ", query, defaultStr) reader := bufio.NewReader(os.Stdin) b, _, err := reader.ReadLine() if err != nil { Debugf("Failed to scan stdin: %s", err.Error()) } line := string(b) Debugf("Input: %q", line) // Use Default value if line == "" { result <- defaultStr } result <- line }() select { case <-sigCh: return "", fmt.Errorf("interrupted") case str := <-result: return str, nil } }
func catchInterrupt(quit chan int) { sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, os.Interrupt) <-sigchan signal.Stop(sigchan) quit <- 1 }
// Wait for signals to gracefully terminate or restart the process. func (p *Process) Wait(listeners []Listener) (err error) { ch := make(chan os.Signal, 2) signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR2) for { sig := <-ch switch sig { case syscall.SIGTERM: signal.Stop(ch) var wg sync.WaitGroup wg.Add(len(listeners)) for _, l := range listeners { go func(l Listener) { defer wg.Done() cErr := l.Close() if cErr != nil { err = cErr } }(l) } wg.Wait() return case syscall.SIGUSR2: rErr := Restart(listeners) if rErr != nil { return rErr } } } }
func (runtime *runtime) Run() (err error) { defer func() { if err != nil { runtime.Print(err) } }() sig := make(chan os.Signal, 3) signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP) defer signal.Stop(sig) go func() { Loop: for s := range sig { switch s { case os.Interrupt, syscall.SIGTERM: runtime.Printf("Got signal %d, stopping all services", s) runtime.Stop() break Loop case syscall.SIGHUP: runtime.Printf("Got signal %d, reloading all services", s) if err := runtime.Reload(); err != nil { runtime.Printf("Error reloading services: %v", err) runtime.Stop() } } } }() err = runtime.runFunc(runtime) return }
func main() { if err := embd.InitGPIO(); err != nil { panic(err) } defer embd.CloseGPIO() pin, err := embd.NewAnalogPin(0) if err != nil { panic(err) } defer pin.Close() quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, os.Kill) defer signal.Stop(quit) for { select { case <-time.After(100 * time.Millisecond): val, err := pin.Read() if err != nil { panic(err) } fmt.Printf("reading: %v\n", val) case <-quit: return } } }
func main() { flag.Parse() if err := embd.InitLED(); err != nil { panic(err) } defer embd.CloseLED() led, err := embd.NewLED(3) if err != nil { panic(err) } defer func() { led.Off() led.Close() }() quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, os.Kill) defer signal.Stop(quit) for { select { case <-time.After(250 * time.Millisecond): if err := led.Toggle(); err != nil { panic(err) } fmt.Println("Toggled") case <-quit: return } } }
func main() { flagStorage := cmdFlags{} setupFlags(&flagStorage) flag.Parse() if flagStorage.debug { go debugServer(DebugAddress) } // when the server starts print the version for debugging and issue logs later logrus.Infof("Version: %s, Git commit: %s", version.NotaryVersion, version.GitCommit) ctx, serverConfig, err := parseServerConfig(flagStorage.configFile, health.RegisterPeriodicFunc, flagStorage.doBootstrap) if err != nil { logrus.Fatal(err.Error()) } c := utils.SetupSignalTrap(utils.LogLevelSignalHandle) if c != nil { defer signal.Stop(c) } if flagStorage.doBootstrap { err = bootstrap(ctx) } else { logrus.Info("Starting Server") err = server.Run(ctx, serverConfig) } if err != nil { logrus.Fatal(err.Error()) } return }
func (ui terminalUI) AskForPassword(prompt string, args ...interface{}) (passwd string) { sig := make(chan os.Signal, 10) // Display the prompt. fmt.Println("") fmt.Printf(prompt+PromptColor(">")+" ", args...) // File descriptors for stdin, stdout, and stderr. fd := []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()} // Setup notifications of termination signals to channel sig, create a process to // watch for these signals so we can turn back on echo if need be. signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM) defer signal.Stop(sig) go catchSignal(fd, sig) pid, err := echoOff(fd) defer echoOn(fd) if err != nil { return } passwd = readPassword(pid) // Carriage return after the user input. fmt.Println("") return }
func startServer(config goku.Configuration) func() int { return func() int { backend, _ := goku.NewBackend("debug", "") sv, err := httpd.New(config, backend) if err != nil { return 1 } if err := sv.Start(); err != nil { log.Println(err.Error()) return 1 } sigs := make(chan os.Signal, 2) signal.Notify(sigs, os.Interrupt) <-sigs signal.Stop(sigs) fmt.Println("Stopping http server...") if err := sv.Stop(); err != nil { return 1 } return 0 } }
func handle(networkName string, netConn net.Conn) { var wg sync.WaitGroup fromServer := make(chan gauja.Message) toServer := make(chan gauja.Message) conn := MakeConn(networkName, netConn, fromServer, toServer) conn.ControlLogger.Print("Connected to server") gauja.NewBot(fromServer, toServer) go func() { interrupt := make(chan os.Signal) defer signal.Stop(interrupt) signal.Notify(interrupt, os.Interrupt) <-interrupt conn.ControlLogger.Print("Received interrupt") conn.Terminate() }() wg.Add(3) go func() { defer wg.Done() conn.handleFromServer() }() go func() { defer wg.Done() conn.handleToServer() }() go func() { defer wg.Done() <-conn.Terminated }() wg.Wait() conn.ControlLogger.Print("Disconnected from server") }
func (sp *slave) watchSignal() { signals := make(chan os.Signal) signal.Notify(signals, sp.Config.RestartSignal) go func() { <-signals signal.Stop(signals) sp.debugf("graceful shutdown requested") //master wants to restart, close(sp.state.GracefulShutdown) //release any sockets and notify master if len(sp.listeners) > 0 { //perform graceful shutdown for _, l := range sp.listeners { l.release(sp.Config.TerminateTimeout) } //signal release of held sockets, allows master to start //a new process before this child has actually exited. //early restarts not supported with restarts disabled. if !sp.NoRestart { sp.masterProc.Signal(SIGUSR1) } //listeners should be waiting on connections to close... } //start death-timer go func() { time.Sleep(sp.Config.TerminateTimeout) sp.debugf("timeout. forceful shutdown") os.Exit(1) }() }() }
func main() { flag.Parse() closing := make(chan struct{}) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() bot.RunBot(*token, closing) }() // ensure a clean shutdown shutdown := make(chan os.Signal) signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM) go func() { <-shutdown signal.Stop(shutdown) close(shutdown) close(closing) }() // wait for the signal wg.Wait() }
func (l *linuxSetnsInit) Init(s chan os.Signal) error { // do not inherit the parent's session keyring if _, err := keyctl.JoinSessionKeyring(l.getSessionRingName()); err != nil { return err } if l.config.NoNewPrivileges { if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { return err } } if l.config.Config.Seccomp != nil { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { return err } } if err := finalizeNamespace(l.config); err != nil { return err } if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } signal.Stop(s) close(s) return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) }
func main() { go doStuff() wg.Add(1) // so we can wait on doStuff to finish signalCh := make(chan os.Signal, 1) // quote from: https://golang.org/pkg/os/#Signal // The only signal values guaranteed to be present on all systems are // Interrupt (send the process an interrupt) and // Kill (force the process to exit). // note: a "kill -9 pid" on OS X never reaches this program // note: a "kill -15 pid" is the same as "kill pid" (it's the default) // KILL -15 pid ctrl+c KILL -9 pid KILL -1 pid signal.Notify(signalCh, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP) // SIGHUP should cause us to re-read config files and start over defer func() { signal.Stop(signalCh) fmt.Printf("defer: wait for workers to finish: wg=%#v\n", wg) wg.Wait() fmt.Printf("defer: '%v' signal received! \tcalling signal.Stop!\n", aSignal) }() aSignal = <-signalCh fmt.Printf("\nmain: '%v' signal received\n", aSignal) fmt.Printf("\nmain: tell doStuff to quit by calling stopDoStuff()\n") stopDoStuff() }
// Deploy the application. Spawn one or more of HTTP(s) servers, as // defined in the loaded config, and make them listen on respective // addresses and ports. Every server will have this application set as // the HTTP requests handler. Method will block until all servers are // stopped. See boot.App and this method implementation for details. func (app *App) Deploy(sv Supervisor) { var volume int = len(app.Services) // size log := app.Journal.WithField("name", app.Name) log = log.WithField("version", app.Version) log = log.WithField("ref", app.Reference) // UID log.Infof("deploying app with %v services", volume) cancelled := make(chan os.Signal, 1) // killed signal.Notify(cancelled, os.Interrupt, os.Kill) app.Supervisor = sv // install app-wide supervisor app.unfoldHttpsServers() // spawn HTTPS and listen app.unfoldHttpServers() // spawn HTTP and listen go func() { // this runs in the background _ = <-cancelled // waiting for signal signal.Stop(cancelled) // stop monitoring fmt.Fprintln(app.Journal.Out) // write ^C\n moment := time.Now().Format(app.TimeLayout) uptime := time.Now().Sub(app.Booted) // calc for _, s := range app.Services { s.Down(app) } for _, p := range app.Providers { // cleanups if !p.Invoked.IsZero() { // was invoked? p.Cleanup(app) // run the cleanup } // only cleanup the setup-ed ones } // all the provider have been cleaned up log := app.Journal.WithField("time", moment) log = log.WithField("uptime", uptime.String()) log.Warn("shutting the application down") app.CronEngine.Stop() // stop CRON engine os.Exit(2) // emulate Ctrl-C exit code }() // run go-routine & wait to finish app.finish.Wait() }
// getPassword gets input hidden from the terminal from a user. This is // accomplished by turning off terminal echo, reading input from the user and // finally turning on terminal echo. func getPassword() (password string, err error) { sig := make(chan os.Signal, 10) brk := make(chan bool) // File descriptors for stdin, stdout, and stderr. fd := []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()} // Setup notifications of termination signals to channel sig, create a process to // watch for these signals so we can turn back on echo if need be. signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM) go catchSignal(fd, sig, brk) // Turn off the terminal echo. pid, err := echoOff(fd) if err != nil { return "", err } // Turn on the terminal echo and stop listening for signals. defer signal.Stop(sig) defer close(brk) defer echoOn(fd) syscall.Wait4(pid, nil, 0, nil) line, err := readline() if err == nil { password = strings.TrimSpace(line) } else { err = fmt.Errorf("failed during password entry: %s", err) } return password, err }
// trapSignal wait on listed signals for pre-defined behaviors func (a *app) trapSignal(wg *sync.WaitGroup) { ch := make(chan os.Signal, 10) signal.Notify(ch, syscall.SIGTERM, syscall.SIGHUP) for { sig := <-ch switch sig { case syscall.SIGTERM: // this ensures a subsequent TERM will trigger standard go behaviour of terminating signal.Stop(ch) // roll through all initialized http servers and stop them for _, s := range a.sds { go func(s httpdown.Server) { defer wg.Done() if err := s.Stop(); err != nil { a.errors <- probe.NewError(err) } }(s) } return case syscall.SIGHUP: // we only return here if there's an error, otherwise the new process // will send us a TERM when it's ready to trigger the actual shutdown. if _, err := a.net.StartProcess(); err != nil { a.errors <- err.Trace() } } } }
// withSafeTTYAndInterrupts invokes the provided function after the terminal // state has been stored, and then on any error or termination attempts to // restore the terminal state to its prior behavior. It also eats signals // for the duration of the function. func withSafeTTYAndInterrupts(fn func() error) error { ch := make(chan os.Signal, 1) signal.Notify(ch, childSignals...) defer signal.Stop(ch) inFd := os.Stdin.Fd() if !term.IsTerminal(inFd) { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() } } if term.IsTerminal(inFd) { state, err := term.SaveState(inFd) if err != nil { return err } go func() { if _, ok := <-ch; !ok { return } term.RestoreTerminal(inFd, state) }() defer term.RestoreTerminal(inFd, state) return fn() } return fn() }
func main() { if len(os.Args) < 2 { fmt.Fprintf(os.Stderr, "Usage: %s <mountpoint>\n", os.Args[0]) os.Exit(1) } mountOptions := &fuse.MountOptions{ AllowOther: true, Name: "boardfs", Options: []string{"default_permissions"}, } mountpoint := os.Args[1] root := boardfs.NewRootNode() conn := nodefs.NewFileSystemConnector(root, &nodefs.Options{}) server, err := fuse.NewServer(conn.RawFS(), mountpoint, mountOptions) if err != nil { log.Fatalf("Mount fail: %v\n", err) } // shutdown fuseserver on SIGINT sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, os.Interrupt, os.Kill) go func() { sig := <-sigchan fmt.Print("\nExiting on ", sig, "\n") server.Unmount() }() server.Serve() signal.Stop(sigchan) }
func actionJoin(ctx *cli.Context) { key := os.Getenv(MeshbirdKeyEnv) if key == "" { logger.Fatalf("environment variable %s is not specified", MeshbirdKeyEnv) } nodeConfig := &common.Config{ SecretKey: key, } node, err := common.NewLocalNode(nodeConfig) if err != nil { logger.Fatalf("local node init error: %s", err) } signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt, os.Kill) defer signal.Stop(signalChan) go func() { s := <-signalChan logger.Printf("received signal %s, stopping...", s) node.Stop() time.Sleep(2 * time.Second) os.Exit(0) }() err = node.Start() if err != nil { logger.Fatalf("node start error: %s", err) } node.WaitStop() }
func (srv *Server) supervise(l net.Listener) error { p, err := srv.forkExec(l) if err != nil { return err } if ServerState != nil { ServerState(StateStart) } c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT, ShutdownSignal, RestartSignal) for { switch sig := <-c; sig { case RestartSignal: child, err := srv.forkExec(l) if err != nil { return err } p.Signal(ShutdownSignal) p.Wait() p = child if ServerState != nil { ServerState(StateRestart) } case syscall.SIGINT, ShutdownSignal: signal.Stop(c) l.Close() p.Signal(ShutdownSignal) _, err := p.Wait() if ServerState != nil { ServerState(StateShutdown) } return err } } }
func main() { if len(os.Args) != 2 { log.Fatalf("Usage: %s: <torrent file>\n", os.Args[0]) } quit := make(chan struct{}) t, err := NewTorrent(os.Args[1], quit) if err != nil { log.Fatal(err) } log.Println("main : main : Started") defer log.Println("main : main : Exiting") go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() // Signal handler to catch Ctrl-C and SIGTERM from 'kill' command c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { // Block waiting for a signal <-c // Unregister the signal handler signal.Stop(c) log.Println("Received Interrupt. Shutting down...") close(t.quit) }() // Launch the torrent t.Run() }
func signalHanlder() { <-interrupt signal.Stop(interrupt) close(interrupt) atomic.StoreInt32(&stop, 1) }
// RunPortForward implements all the necessary functionality for port-forward cmd. func (o PortForwardOptions) RunPortForward() error { pod, err := o.PodClient.Pods(o.Namespace).Get(o.PodName) if err != nil { return err } if pod.Status.Phase != api.PodRunning { return fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase) } signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt) defer signal.Stop(signals) go func() { <-signals if o.StopChannel != nil { close(o.StopChannel) } }() req := o.RESTClient.Post(). Resource("pods"). Namespace(o.Namespace). Name(pod.Name). SubResource("portforward") return o.PortForwarder.ForwardPorts("POST", req.URL(), o) }
func cmdShell(app *cli.App) { cli.OsExiter = func(c int) {} reader := bufio.NewReader(os.Stdin) sigs := make(chan os.Signal, 1) go func() { for range sigs { fmt.Printf("\n(type quit or q to exit)\n\nblesh >") } }() defer close(sigs) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) for { fmt.Print("blesh > ") text, _ := reader.ReadString('\n') text = strings.TrimSpace(text) if text == "" { continue } if text == "quit" || text == "q" { break } app.Run(append(os.Args[1:], strings.Split(text, " ")...)) } signal.Stop(sigs) }