操作系统:在发送syscall.SIGCONT时,进程已经完成(可能是一个错误?)

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

os: process already finished when sending syscall.SIGCONT (possible bug?)

问题

在执行一个进程并使用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)

	// 使用这个会返回一个 os: process already finished 的错误
	fmt.Printf("%v\n", cmd.Process.Signal(syscall.SIGCONT))

	// 这个按预期工作
	//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的一个bug还是预期行为?

更新:似乎只在Mac OS X上发生。

英文:

When executing a process and sending signals to it using: Process.Signal I notice that after sending the second signal syscall.SIGCONT I got a: os: process already finished but if using syscall.Kill everything works as expected.

For demonstrative purposes I have created this naive example:

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
	&quot;syscall&quot;
	&quot;time&quot;
)

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

	for {
		select {
		case &lt;-exit:
			println(&quot;fin, restarting&quot;)
			run(exit)
		default:
			time.Sleep(time.Second)
			println(&quot;running...&quot;)
		}
	}
}

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

	time.Sleep(2 * time.Second)
	fmt.Printf(&quot;%v\n&quot;, cmd.Process.Signal(syscall.SIGSTOP))
	
    time.Sleep(2 * time.Second)
	
    // Using this will return an os: process already finished  
    fmt.Printf(&quot;%v\n&quot;, cmd.Process.Signal(syscall.SIGCONT)) 

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

So basically if using:

cmd.Process.Signal(syscall.SIGCONT)

os: process already finished is returned

But when using:

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

It works as expected.

Could this be a bug on os.exec or it the expected behavior?

UPDATE: seems to be happening only on mac os X

答案1

得分: 2

这个问题似乎只在Mac OS X上发生,经过测试,在"Sierra"和"El Capitan"上发生。为了保持跨平台性,可以使用以下代码:

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)
	}

	// 当wait4立即返回时发出信号
	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()
}

你可以在这里查看更多关于这个问题的信息:链接

英文:

This issue seems to be only happening on Mac OS X, tested on "Sierra" and "El Capitan" https://go-review.googlesource.com/#/c/37610/

So, for now, to keep things cross-platform better user:

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

Example code to test if your system has this issue:

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;os/exec&quot;
	&quot;syscall&quot;
	&quot;unsafe&quot;
)

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

	// signal when wait4 will return immediately
	go func() {
		var siginfo [128]byte
		psig := &amp;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(&quot;WAITID RETURNED -- this shouldn&#39;t happen:&quot;, e)
	}()

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

huangapple
  • 本文由 发表于 2017年2月28日 17:47:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/42505276.html
匿名

发表评论

匿名网友

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

确定