How are goroutines scheduled?

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

How are goroutines scheduled?

问题

我想使用ptrace来跟踪一个具有输入和输出的进程,所以我决定使用exec.Com来启动一个进程,而不是使用os.StartProcess。但是有些令我困惑的事情发生了,我不确定是否是由于goroutines的调度引起的。我睡眠了5秒,并且每毫秒发送一个闹钟信号,但测试结果显示进程很快就退出了。
但是,如果我测试一个运行实际CPU时间的进程,它将通过测试。我找到了exec.Com的源代码,发现它有用于管道输入和输出的goroutines,这与os.StartProcess不同。如果我改用os.StartProcess,它将通过测试。所以我想知道是不是goroutines在睡眠时出了问题。
我猜我应该做一些事情来将睡眠锁定到某个线程,但我不确定是什么原因导致了这个问题。

以下是你的代码:

package sandbox

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

const (
	AC uint64 = iota
	PE
	TLE
	MLE
	WA
	RE
	OLE
	CE
	SE
)

type Tracer struct {
	Process *os.Process
}

func Attach(proc *os.Process) (*Tracer, error) {
	err := syscall.PtraceAttach(proc.Pid)
	if err == syscall.EPERM {
		_, err := syscall.PtraceGetEventMsg(proc.Pid)
		if err != nil {
			return nil, err
		}
	} else if err != nil {
		return nil, err
	}

	return &Tracer{
		Process: proc,
	}, nil
}
func (t *Tracer) Syscall(sig syscall.Signal) error {
	err := syscall.PtraceSyscall(t.Process.Pid, int(sig))
	if err != nil {
		return err
	}
	return nil
}

type RunningObject struct {
	Proc        *os.Process
	TimeLimit   int64
	MemoryLimit int64
	Memory      int64
	Time        int64
	Status      uint64
}

func (r *RunningObject) RunTick(dur time.Duration) {
	ticker := time.NewTicker(dur)
	for _ = range ticker.C {
		r.Proc.Signal(os.Signal(syscall.SIGALRM))
	}
}

func Run(src string, args []string, timeLimit int64, memoryLimit int64) *RunningObject {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	var rusage syscall.Rusage
	var runningObject RunningObject
	runningObject.TimeLimit = timeLimit
	runningObject.MemoryLimit = memoryLimit
	cmd := exec.Command(src, args...)
	err := cmd.Start()
	if err != nil {
		panic(err)
	}
	proc := cmd.Process
	tracer, err := Attach(proc)
	if err != nil {
		panic(err)
	}
	runningObject.Proc = proc
	go runningObject.RunTick(time.Millisecond)
	if err != nil {
		fmt.Println(err)
		return &runningObject
	}
	for {
		status := syscall.WaitStatus(0)
		_, err := syscall.Wait4(proc.Pid, &status, syscall.WSTOPPED, &rusage)
		if err != nil {
			panic(err)
		}
		if status.Exited() {
			fmt.Println("exit")
			return &runningObject
		}
		if status.CoreDump() {
			fmt.Println("CoreDump")
			return &runningObject
		}
		if status.Continued() {
			fmt.Println("Continued")
			return &runningObject
		}
		if status.Signaled() {
			return &runningObject
		}
		if status.Stopped() && status.StopSignal() != syscall.SIGTRAP {
			fmt.Println(status.StopSignal())
		}
		err = tracer.Syscall(syscall.Signal(0))
		if err != nil {
			fmt.Println(err)
		}
	}
}

这是我的测试代码:

package sandbox

import (
	"testing"
)

func TestTime(t *testing.T) {
	obj := Run("/bin/sleep", []string{"sleep", "5"}, 1000, 10000)
	//t.Log(obj.Status)
	if obj.Status != TLE {
		t.Fatal("time exceed test failed.")
	}
}
英文:

I want to use ptrace to trace a process with input and output,so I decide to use exec.Com to start a process instead of os.StartProcess. But something confusing me happened,I am not sure if it is caused by gorountines schedule . I sleep 5 seconds,and send alarm signal every millionsecond but test results show it quickly exits.
But If I test with a process running real CPU time,it will pass the test.I find the source code of exec.Com,and there are gorountines to pipe stdin and stdout,which is different from os.StartProcess. If I change to use os.StartProcess , it will pass the test. So I wonder it is something wrong with the gorountines running with sleep.
I guess I should do something to lock the sleep to a certain thread,but I not sure what cause the problem.

This is my code:

package sandbox
import (
"fmt"
"os"
"os/exec"
"runtime"
"syscall"
"time"
)
const (
AC uint64 = iota
PE
TLE
MLE
WA
RE
OLE
CE
SE
)
type Tracer struct {
Process *os.Process
}
func Attach(proc *os.Process) (*Tracer, error) {
err := syscall.PtraceAttach(proc.Pid)
if err == syscall.EPERM {
_, err := syscall.PtraceGetEventMsg(proc.Pid)
if err != nil {
return nil, err
}
} else if err != nil {
return nil, err
}
return &Tracer{
Process: proc,
}, nil
}
func (t *Tracer) Syscall(sig syscall.Signal) error {
err := syscall.PtraceSyscall(t.Process.Pid, int(sig))
if err != nil {
return err
}
return nil
}
type RunningObject struct {
Proc        *os.Process
TimeLimit   int64
MemoryLimit int64
Memory      int64
Time        int64
Status      uint64
}
func (r *RunningObject) RunTick(dur time.Duration) {
ticker := time.NewTicker(dur)
for _ = range ticker.C {
r.Proc.Signal(os.Signal(syscall.SIGALRM))
}
}
func Run(src string, args []string, timeLimit int64, memoryLimit int64) *RunningObject {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var rusage syscall.Rusage
var runningObject RunningObject
runningObject.TimeLimit = timeLimit
runningObject.MemoryLimit = memoryLimit
cmd := exec.Command(src, args...)
err := cmd.Start()
if err != nil {
panic(err)
}
proc := cmd.Process
tracer, err := Attach(proc)
if err != nil {
panic(err)
}
runningObject.Proc = proc
go runningObject.RunTick(time.Millisecond)
if err != nil {
fmt.Println(err)
return &runningObject
}
for {
status := syscall.WaitStatus(0)
_, err := syscall.Wait4(proc.Pid, &status, syscall.WSTOPPED, &rusage)
if err != nil {
panic(err)
}
if status.Exited() {
fmt.Println("exit")
return &runningObject
}
if status.CoreDump() {
fmt.Println("CoreDump")
return &runningObject
}
if status.Continued() {
fmt.Println("Continued")
return &runningObject
}
if status.Signaled() {
return &runningObject
}
if status.Stopped() && status.StopSignal() != syscall.SIGTRAP {
fmt.Println(status.StopSignal())
}
err = tracer.Syscall(syscall.Signal(0))
if err != nil {
fmt.Println(err)
}
}
}

and this is my test:

package sandbox
import (
"testing"
)
func TestTime(t *testing.T) {
obj := Run("/bin/sleep", []string{"sleep", "5"}, 1000, 10000)
//t.Log(obj.Status)
if obj.Status != TLE {
t.Fatal("time exceed test failed.")
}
}

答案1

得分: 1

你不需要将 arg0 传递给 exec.Command

你给 /bin/sleep 传递了 sleep 5 的参数,这样它会立即退出并显示用法文本。

英文:

You don't need to pass arg0 to exec.Command.

You're giving /bin/sleep the arguments of sleep 5, in which case it exits immediately with the usage text..

huangapple
  • 本文由 发表于 2014年7月14日 12:40:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/24729617.html
匿名

发表评论

匿名网友

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

确定