2014-07-14 5 views
1

입출력이있는 프로세스를 추적하기 위해 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.") 
    } 
} 
+0

가 사용 텍스트로 즉시 종료하는 경우에는 sleep 5/bin/sleep 인수를 .. 제공하고 있습니다. 어떤 OS를 실행하고 있습니까? –

+0

내 OS는 우분투 – ggaaooppeenngg

답변

1

.

당신은 일부 시스템 때문에, 수면 SIGALARM를 사용하여 구현되고, 그것은 수면과 SIGALARM 사이의 간섭이있을 수 있습니다

+0

오! 내가 얼마나 바보 야! – ggaaooppeenngg