英文:
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 (
	"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))
}
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 (
	"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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论