Golang无法从子进程中终止父进程。

huangapple go评论94阅读模式
英文:

Golang cant kill parent process from child

问题

最近我在处理fork进程并从子进程中杀死父进程的问题上遇到了困难。

我不知道为什么,但似乎根本没有杀死父进程。起初我以为是由于打开的连接导致进程保持运行,因为这是一个优雅关闭的过程,但问题并不在这里。

如果我从终端发送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)
}
英文:

Last days i am kinda struggling with forking a process and kill the parent from the forked one(child)

I don't know why but it seems not to kill the parent at all. first i tough it where the open connections that keeps the process running because of the graceful shutdown process, But its not that issue.

if i send SIGTERM to the parent from the terminal it worked perfect, but when the child send SIGTERM it does not stop, force quitting is no option cause of graceful shutdown.

edit * the processes are still in the process list. Maybe that is for parent to track its children?

Some code that does the fork, maybe i do something wrong here

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
}

the termination of the parent

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

答案1

得分: 2

<strike>长话短说,你不能进行分叉,这是一个非常古老且持续存在的问题,可以在这里找到相关信息。

你可以使用类似https://github.com/icattlecoder/godaemon的东西,但是父进程必须自行终止,而不是子进程。</strike>

var isChild = flag.Bool(&quot;child&quot;, false, &quot;parent pid&quot;)
func main() {
flag.Parse()
var s string
if !*isChild { //parent
fmt.Println(&quot;forking&quot;)
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, &quot;-child&quot;), &amp;os.ProcAttr{
Dir:   &quot;/tmp&quot;,
Env:   os.Environ(),
Files: files,
}))
fmt.Scan(&amp;s) // block
} else {
ppid := os.Getppid()
fmt.Println(&quot;ppid&quot;, ppid, &quot;kill:&quot;, syscall.Kill(ppid, syscall.SIGTERM))
time.Sleep(5 * time.Second)
fmt.Println(&quot;child dying&quot;)
}
}
英文:

<strike>Long story short, you can't fork, there's a very old and ongoing issue for it here.

You could use something like https://github.com/icattlecoder/godaemon but the parent will have to terminate itself not the child.</strike>

var isChild = flag.Bool(&quot;child&quot;, false, &quot;parent pid&quot;)
func main() {
flag.Parse()
var s string
if !*isChild { //parent
fmt.Println(&quot;forking&quot;)
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, &quot;-child&quot;), &amp;os.ProcAttr{
Dir:   &quot;/tmp&quot;,
Env:   os.Environ(),
Files: files,
}))
fmt.Scan(&amp;s) // block
} else {
ppid := os.Getppid()
fmt.Println(&quot;ppid&quot;, ppid, &quot;kill:&quot;, syscall.Kill(ppid, syscall.SIGTERM))
time.Sleep(5 * time.Second)
fmt.Println(&quot;child dying&quot;)
}
}

答案2

得分: 1

我的父进程无法在收到TERM信号时终止的问题是因为一个内部的for循环无法跳出。我修复了这个for循环,并让主函数返回。在Go语言中,如果主函数返回,程序将退出。对于我自己的一个大错误,打扰了你们,我感到很抱歉。

英文:

The problem my parent process wont terminate on a TERM signal is because of a inner for loop that wont break. I fixed the for loop and let the main function return. If in Go the main returns the program exits. sorry for bothering you guys with a big mistake of myself

huangapple
  • 本文由 发表于 2014年9月19日 04:23:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/25921698.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定