// ForwardAllSignals forwards signals to the contianer // TODO: this can be unexported again once all container commands are under // api/client/container func (cli *DockerCli) ForwardAllSignals(ctx context.Context, cid string) chan os.Signal { sigc := make(chan os.Signal, 128) signal.CatchAll(sigc) go func() { for s := range sigc { if s == signal.SIGCHLD || s == signal.SIGPIPE { continue } var sig string for sigStr, sigN := range signal.SignalMap { if sigN == s { sig = sigStr break } } if sig == "" { fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s) continue } if err := cli.client.ContainerKill(ctx, cid, sig); err != nil { logrus.Debugf("Error sending signal: %s", err) } } }() return sigc }
func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal { sigc := make(chan os.Signal, 128) signal.CatchAll(sigc) go func() { for s := range sigc { if s == signal.SIGCHLD { continue } var sig string for sigStr, sigN := range signal.SignalMap { if sigN == s { sig = sigStr break } } if sig == "" { fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s) } if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, nil)); err != nil { logrus.Debugf("Error sending signal: %s", err) } } }() return sigc }
func babySit(process *os.Process) int { log := logger.New("fn", "babySit") // Forward all signals to the app sigchan := make(chan os.Signal, 1) sigutil.CatchAll(sigchan) go func() { for sig := range sigchan { log.Info("received signal", "type", sig) if sig == syscall.SIGCHLD { continue } log.Info("forwarding signal to command", "type", sig) process.Signal(sig) } }() // Wait for the app to exit. Also, as pid 1 it's our job to reap all // orphaned zombies. var wstatus syscall.WaitStatus for { pid, err := syscall.Wait4(-1, &wstatus, 0, nil) if err == nil && pid == process.Pid { break } } if wstatus.Signaled() { log.Info("command exited due to signal") return 0 } return wstatus.ExitStatus() }
func babySit(init *ContainerInit, hbs []discoverd.Heartbeater) int { log := logger.New() var shutdownOnce sync.Once hbDone := make(chan struct{}) closeHBs := func() { for _, hb := range hbs { if err := hb.Close(); err != nil { log.Error("error deregistering service", "addr", hb.Addr(), "err", err) } else { log.Info("service deregistered", "addr", hb.Addr()) } } close(hbDone) } // Close the heartbeaters if requested to do so go func() { <-init.deregister log.Info("received deregister request") shutdownOnce.Do(closeHBs) }() // Forward all signals to the app sigchan := make(chan os.Signal, 1) sigutil.CatchAll(sigchan) go func() { for sig := range sigchan { log.Info("received signal", "type", sig) if sig == syscall.SIGCHLD { continue } if sig == syscall.SIGTERM || sig == syscall.SIGINT { shutdownOnce.Do(closeHBs) } log.Info("forwarding signal to job", "type", sig) init.process.Signal(sig) } }() // Wait for the app to exit. Also, as pid 1 it's our job to reap all // orphaned zombies. var wstatus syscall.WaitStatus for { pid, err := syscall.Wait4(-1, &wstatus, 0, nil) if err == nil && pid == init.process.Pid { break } } // Ensure that the heartbeaters are closed even if the app wasn't signaled shutdownOnce.Do(closeHBs) select { case <-hbDone: case <-time.After(5 * time.Second): log.Error("timed out waiting for services to be deregistered") } if wstatus.Signaled() { log.Debug("job exited due to signal") return 0 } return wstatus.ExitStatus() }