M
M
memba2015-09-30 12:09:24
go
memba, 2015-09-30 12:09:24

What is the problem with sending a signal to a child process?

The third day I can not google. Everything is very simple. There is a parent process which to produce child process. Later, the parent process must kill the child. But not through KIll, but send a signal for a correct termination. The child process catches the signal and exits.
The simplest examples:
Parent (parent.go)

package main

import (
  "fmt"
  "os"
  "os/exec"
  "syscall"
  "time"
)

func main() {
  // Запускаем дочерний процесс
  cmd := exec.Command("./child")
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  err := cmd.Start()

  if err != nil {
    fmt.Println("Child process not starting")
    os.Exit(1)
  }

  pid := cmd.Process.Pid

  fmt.Println("Child PID:", pid)

  // Отправляем сигнал о желании завершить процесс
  err = cmd.Process.Signal(syscall.SIGTERM)

  if err != nil {
    fmt.Println("Signal not sent:", err)
  }

  // Тикаем 10 секунд, в ожидании завершения процесса
  tick := time.NewTicker(1 * time.Second)
  i := 1
  for range tick.C {
    _, err := os.FindProcess(pid)
    if err != nil {
      break
    }
    if i == 10 {
      break
    }
    fmt.Println(i)
    i++
  }
  tick.Stop()

  // Убиваем процесс если он так и не получил сигнал!
  err = cmd.Process.Kill()

  if err != nil {
    fmt.Println("Child process not die")
  }

  fmt.Println("Exiting")
}

Child (child.go)
package main

import (
  "fmt"
  "os"
  "os/signal"
  "syscall"
)

func main() {
  // Слушаем сигнал
  c := make(chan os.Signal, 1)
  signal.Notify(c, syscall.SIGTERM)

  // Зависаем в ожидании сигнала
  <-c

  signal.Stop(c)

  fmt.Println("Child finish!")
}

By running ./parent it runs ./child and immediately sends it a signal to terminate. But nothing happens, the process remains alive.
I checked on Windows and Linux.
I tested listening (signal.Notify) on Ctrl+C - it works.
I don't get errors from cmd.Process.Signal(...)
UPD:
If you call cmd.Process.Kill(), which is the same as cmd.Process.Signal(syscall.SIGKILL), then the child process will die, only when parent ends. It is not possible to catch a signal in a child process. The child process dies after the parent while waiting for data from the pipe (<-c). This is some nonsense.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
T
Tyranron, 2015-09-30
@memba

Sorry for being direct, but the problem is your lack of knowledge of the materiel.
What to read on the topic: Zombie process , as well as Docker and the PID 1 zombie reaping problem .
And now closer to your example.
Bottom line: both SITERM and SIGKILL you successfully kill the child process, after which it turns into a zombie process, that is, it still hangs in memory under its PID, waiting for reaping (wait() system call from the parent process). After the parent process ends, our zombie child is adopted by the init process, which reaps it.
If you run your programs as you posted them, and write ps while ticking, you will see the following picture:

459 ttys000    0:00.03 -bash
498 ttys000    0:00.00 ./parent
499 ttys000    0:00.00 (child)
The fact that child is in parentheses just means that the process was stopped (that is, it made the exit() system call) and is waiting for reaping (when the result of exit() is read by wait()).
If we add before sending the child time.Sleep(10 * time.Second)and immediately after the output of the child's PID we type to look at what is happening in the processes, we will see the following picture:
459 ttys000    0:00.04 -bash
510 ttys000    0:00.00 ./parent
511 ttys000    0:00.00 ./child
Compare with how it appears in processes after it has been killed.
And if we add after sending a signal to child cmd.Process.Wait(), then your ticker cycle will still, perhaps, still be spinning if a new process with such a PID has appeared in the system, but if we look at ps, we will see that our child is no longer there at all:
459 ttys000    0:00.05 -bash
536 ttys000    0:00.01 ./parent

By the way, the magic power of Process.Wait() is written right in its dock .

R
RomanPyr, 2015-09-30
@RomanPyr

A good example of working with child processes . There and about wait is.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question