Golang无法从孩子那里杀死父进程

时间:2014-09-18 20:23:51

标签: go signals

最后几天我有点挣扎着分叉一个过程并从分叉的孩子身上杀死父母(孩子)

我不知道为什么但似乎根本不会杀死父母。首先,我强调它是由于优雅的关闭过程而保持流程运行的开放连接,但不是那个问题。

如果我从终端向父节点发送SIGTERM它完美无缺,但是当孩子发送SIGTERM时它不会停止,强制退出是没有选择导致正常关闭的原因。

编辑*流程仍在流程列表中。也许这是父母跟踪其孩子的?

执行fork的一些代码,也许我在这里做错了

func (s *Server) Upgrade() error {
    tl := s.listener.(*listener)

    addr := s.listener.Addr()
    name := fmt.Sprintf("%s:%s->", addr.Network(), addr.String())
    os.Setenv("PROX_NAME", name)

    fl, err := tl.File()
    if err != nil {
        return fmt.Errorf("Failed to extract file desciptor, %v", err)
    }

    fd := fl.Fd()

    argv0, err := exec.LookPath(os.Args[0])
    if err != nil {
        return fmt.Errorf("Failed to execute lookpath, %v", err)
    }

    noCloseOnExec(fd)

    files := make([]*os.File, fd+1)
    files[syscall.Stdin] = os.Stdin
    files[syscall.Stdout] = os.Stdout
    files[syscall.Stderr] = os.Stderr

    files[fd] = os.NewFile(fd, name)

    wd, err := os.Getwd()
    if err != nil {
        return err
    }

    os.Setenv("GPROXY_FD", fmt.Sprintf("%d", fd))
    os.Setenv("GPROXY_PID", fmt.Sprintf("%d", syscall.Getpid()))
    args := []string{"gproxy", "-debug", "start"}
    _, err = os.StartProcess(argv0, args, &os.ProcAttr{
        Dir:   wd,
        Env:   os.Environ(),
        Files: files,
    })

    return err
}

父母的终止

func termParentProcess() error {
    pid := syscall.Getppid()
    return syscall.Kill(pid, syscall.SIGTERM)
}

2 个答案:

答案 0 :(得分:2)

长话短说,你不能分叉,这是一个非常古老而持续的问题here

您可以使用类似https://github.com/icattlecoder/godaemon的内容,但父母必须终止自己而不是孩子。

var isChild = flag.Bool("child", false, "parent pid")

func main() {
    flag.Parse()
    var s string
    if !*isChild { //parent
        fmt.Println("forking")
        files := make([]*os.File, 3)
        files[syscall.Stdin] = os.Stdin
        files[syscall.Stdout] = os.Stdout
        files[syscall.Stderr] = os.Stderr
        fmt.Println(os.StartProcess(os.Args[0], append(os.Args, "-child"), &os.ProcAttr{
            Dir:   "/tmp",
            Env:   os.Environ(),
            Files: files,
        }))
        fmt.Scan(&s) // block
    } else {
        ppid := os.Getppid()
        fmt.Println("ppid", ppid, "kill:", syscall.Kill(ppid, syscall.SIGTERM))
        time.Sleep(5 * time.Second)
        fmt.Println("child dying")
    }
}

答案 1 :(得分:1)

我的父进程不会在TERM信号上终止的问题是因为内部for循环不会中断。我修复了for循环并让main函数返回。如果在Go中,main返回程序退出。很抱歉打扰你们,我自己犯了一个大错误