add extra sync for execve

This commit is contained in:
criyle 2019-08-07 20:48:35 -07:00
parent 8bf0411dbb
commit eb93d92b9e
4 changed files with 72 additions and 31 deletions

View File

@ -185,8 +185,16 @@ func main() {
if err != nil {
panic(fmt.Sprintln("failed to execve", err))
}
println(<-s.Wait)
s.Kill <- 1
tC := time.After(time.Duration(int64(realTimeLimit) * int64(time.Second)))
select {
case <-tC:
s.Kill <- 1
rt = <-s.Wait
case rt = <-s.Wait:
s.Kill <- 1
}
println(rt)
eTime := time.Now()
rt.SetUpTime = int64(rTime.Sub(sTime))
rt.RunningTime = int64(eTime.Sub(rTime))

View File

@ -8,6 +8,7 @@ import (
"syscall"
"github.com/criyle/go-judger/forkexec"
"github.com/criyle/go-judger/types/specs"
"github.com/criyle/go-judger/unixsocket"
)
@ -77,17 +78,15 @@ func handleExecve(s *unixsocket.Socket, cmd *Cmd, msg *unixsocket.Msg) error {
},
}
if err2 := sendReply(s, &Reply{}, &msg2); err2 != nil {
_ = err2
return fmt.Errorf("syncFunc: sendReply(%v)", err2)
}
cmd2, _, err2 := recvCmd(s)
if err2 != nil {
_ = err2
return fmt.Errorf("syncFunc: recvCmd(%v)", err2)
}
switch cmd2.Cmd {
case cmdKill:
return fmt.Errorf("kill")
case cmdOk:
return nil
return fmt.Errorf("syncFunc: recved kill")
}
return nil
}
@ -103,37 +102,68 @@ func handleExecve(s *unixsocket.Socket, cmd *Cmd, msg *unixsocket.Msg) error {
}
pid, err := r.Start()
if err != nil {
_ = err
reply := Reply{Error: fmt.Sprintf("execve: %v", err)}
sendReply(s, &reply, nil)
return nil
}
done := make(chan int)
// recv kill
go func() {
// msg must be kill
if _, _, err3 := recvCmd(s); err3 != nil {
_ = err3
}
recvCmd(s)
// kill all
syscall.Kill(-1, syscall.SIGKILL)
// collect zombies
for {
_, err = syscall.Wait4(-1, nil, 0, nil)
if err != nil {
break
}
}
// signal done
close(done)
}()
var wstatus syscall.WaitStatus
// wait pid
var wstatus syscall.WaitStatus
loop:
for {
_, err = syscall.Wait4(pid, &wstatus, 0, nil)
if err != nil {
_ = err
reply := Reply{Error: fmt.Sprintf("execve: wait4 %v", err)}
sendReply(s, &reply, nil)
break loop
}
switch {
case wstatus.Exited():
reply := Reply{
Status: wstatus.ExitStatus(),
}
if err = sendReply(s, &reply, nil); err != nil {
_ = err
reply := Reply{ExitStatus: wstatus.ExitStatus()}
sendReply(s, &reply, nil)
break loop
case wstatus.Signaled():
var status specs.TraceCode
switch wstatus.Signal() {
// kill signal treats as TLE
case syscall.SIGKILL:
status = specs.TraceCodeTLE
case syscall.SIGXCPU:
status = specs.TraceCodeTLE
case syscall.SIGXFSZ:
status = specs.TraceCodeOLE
case syscall.SIGSYS:
status = specs.TraceCodeBan
default:
status = specs.TraceCodeRE
}
reply := Reply{TraceStatus: status}
sendReply(s, &reply, nil)
break loop
}
}
return nil
// wait for kill msg and reply done for finish
<-done
return sendReply(s, &Reply{}, nil)
}
func recvCmd(s *unixsocket.Socket) (*Cmd, *unixsocket.Msg, error) {

View File

@ -34,6 +34,7 @@ Any socket related error will cause the deamon exit (with all process inside con
import (
"github.com/criyle/go-judger/types/rlimit"
"github.com/criyle/go-judger/types/specs"
)
// Cmd is the control message send into deamon
@ -49,6 +50,7 @@ type Cmd struct {
// Reply is the reply message send back to controller
type Reply struct {
Error string // empty if no error
Status int // waitpid exit status
Error string // empty if no error
ExitStatus int // waitpid exit status
TraceStatus specs.TraceCode // TraceCode
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/criyle/go-judger/types/rlimit"
"github.com/criyle/go-judger/types/specs"
"github.com/criyle/go-judger/unixsocket"
)
@ -22,7 +23,7 @@ type ExecveParam struct {
// Wait channel will produce the waitpid exit status
// Kill channel will kill the process if value received
type ExecveStatus struct {
Wait <-chan int
Wait <-chan specs.TraceResult
Kill chan<- int
}
@ -55,23 +56,23 @@ func (m *Master) Execve(param *ExecveParam) (*ExecveStatus, error) {
if err := m.sendCmd(&Cmd{Cmd: cmdOk}, nil); err != nil {
return nil, fmt.Errorf("execve: ok failed(%v)", err)
}
wait := make(chan int)
wait := make(chan specs.TraceResult)
kill := make(chan int)
// Wait
go func() {
reply2, _, err2 := m.recvReply()
if err2 != nil {
_ = err2
reply2, _, _ := m.recvReply()
wait <- specs.TraceResult{
ExitCode: reply2.ExitStatus,
TraceStatus: reply2.TraceStatus,
}
wait <- reply2.Status
// done signal (should recv after kill)
m.recvReply()
close(wait)
}()
// Kill
go func() {
<-kill
err3 := m.sendCmd(&Cmd{Cmd: cmdKill}, nil)
if err3 != nil {
_ = err3
}
m.sendCmd(&Cmd{Cmd: cmdKill}, nil)
}()
return &ExecveStatus{
Wait: wait,