입출력이있는 프로세스를 추적하기 위해 ptrace를 사용하려고하므로 exec.Com을 사용하여 os.StartProcess 대신 프로세스를 시작하기로 결정했습니다. 그러나 저를 혼동시키는 무언가는 일어났습니다, 그것이 gorountines 일정에 기인하는지 확실하지 않습니다. 나는 5 초 동안 잠을 자며 매 수백 초마다 알람 신호를 보내지 만, 테스트 결과는 신속하게 종료되었음을 보여줍니다. 하지만 실제 CPU 시간을 실행하는 프로세스로 테스트하면 test.I에 exec.Com의 소스 코드가 있고 os.StartProcess와 다른 stdin과 stdout을 파이프하는 gorountines가 있습니다. os.StartProcess를 사용하도록 변경하면 테스트를 통과합니다. 그래서 나는 gorountines가 잠을 자고있는 것이 잘못된 것이라고 생각합니다. 나는 특정 스레드로 잠을 잠 그려면 뭔가해야한다고 생각하지만, 무엇이 문제를 일으키는 지 잘 모르겠습니다.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)
}
}
}
이 내 테스트입니다 : 당신은 exec.Command
에 arg0를 통과 할 필요가 없습니다
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.")
}
}
가 사용 텍스트로 즉시 종료하는 경우에는
sleep 5
의/bin/sleep
인수를 .. 제공하고 있습니다. 어떤 OS를 실행하고 있습니까? –내 OS는 우분투 – ggaaooppeenngg