os:发送syscall.SIGCONT时已经完成的进程(可能的错误?)

时间:2017-02-28 09:47:43

标签: go signals system-calls

当执行一个过程并使用:Process.Signal向其发送信号时,我注意到在发送第二个信号syscall.SIGCONT后,我得到了:os: process already finished但是如果使用syscall.Kill一切按预期工作。

出于示范目的,我创造了这个天真的例子:

package main

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

func main() {
    exit := make(chan error, 1)
    go run(exit)

    for {
        select {
        case <-exit:
            println("fin, restarting")
            run(exit)
        default:
            time.Sleep(time.Second)
            println("running...")
        }
    }
}

func run(ch chan<- error) {
    cmd := exec.Command("sleep", "3")
    if err := cmd.Start(); err != nil {
        print(err.Error())
        os.Exit(1)
    }
    fmt.Printf("Pid: %d\n", cmd.Process.Pid)
    go func() {
        ch <- cmd.Wait()
    }()

    time.Sleep(2 * time.Second)
    fmt.Printf("%v\n", cmd.Process.Signal(syscall.SIGSTOP))

    time.Sleep(2 * time.Second)

    // Using this will return an os: process already finished  
    fmt.Printf("%v\n", cmd.Process.Signal(syscall.SIGCONT)) 

    // This works as expected
    //fmt.Printf("%v\n", syscall.Kill(cmd.Process.Pid, syscall.SIGCONT))
}

所以基本上如果使用:

cmd.Process.Signal(syscall.SIGCONT)

os: process already finished被退回

但使用时:

syscall.Kill(cmd.Process.Pid, syscall.SIGCONT)

它按预期工作。

这可能是os.exec上的错误还是预期的行为?

UPDATE :似乎只在mac os X上发生

1 个答案:

答案 0 :(得分:1)

issue似乎只发生在Mac OS X上,在“Sierra”和“El Capitan”上进行了测试https://go-review.googlesource.com/#/c/37610/

所以,就目前而言,要保持跨平台更好的用户:

syscall.Kill(cmd.Process.Pid, syscall.SIGCONT))

测试您的系统是否存在此问题的示例代码:

package main

import (
    "fmt"
    "log"
    "os/exec"
    "syscall"
    "unsafe"
)

func main() {
    cmd := exec.Command("sleep", "10")
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    // signal when wait4 will return immediately
    go func() {
        var siginfo [128]byte
        psig := &siginfo[0]
        _, _, e := syscall.Syscall6(syscall.SYS_WAITID, 1, uintptr(cmd.Process.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
        fmt.Println("WAITID RETURNED -- this shouldn't happen:", e)
    }()

    err := cmd.Process.Signal(syscall.SIGSTOP)
    if err != nil {
        log.Fatal(err)
    }
    cmd.Wait()
}