mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
fix inconsistency when fail at execve
This commit is contained in:
parent
d0b047bb08
commit
dcbc99fa5d
@ -184,20 +184,18 @@ func handleExecve(s *unixsocket.Socket, cmd *Cmd, msg *unixsocket.Msg) error {
|
||||
DropCaps: true,
|
||||
SyncFunc: syncFunc,
|
||||
}
|
||||
// starts the runner, error is handled same as wait4 to make api simple
|
||||
pid, err := r.Start()
|
||||
if err != nil {
|
||||
return sendErrorReply(s, "execve: %v", err)
|
||||
}
|
||||
|
||||
// done is to signal kill goroutine exits
|
||||
done := make(chan struct{})
|
||||
killDone := make(chan struct{})
|
||||
// waitDone is to signal kill goroutine to collect zombies
|
||||
waitDone := make(chan struct{})
|
||||
|
||||
// recv kill
|
||||
go func() {
|
||||
// signal done
|
||||
defer close(done)
|
||||
defer close(killDone)
|
||||
// msg must be kill
|
||||
recvCmd(s)
|
||||
// kill all
|
||||
@ -206,29 +204,27 @@ func handleExecve(s *unixsocket.Socket, cmd *Cmd, msg *unixsocket.Msg) error {
|
||||
<-waitDone
|
||||
// collect zombies
|
||||
for {
|
||||
_, err = syscall.Wait4(-1, nil, syscall.WNOHANG, nil)
|
||||
if err != nil {
|
||||
pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil)
|
||||
if err != nil || pid <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// wait pid
|
||||
// wait pid if no error encoutered for execve
|
||||
var wstatus syscall.WaitStatus
|
||||
loop:
|
||||
for {
|
||||
if err == nil {
|
||||
_, err = syscall.Wait4(pid, &wstatus, 0, nil)
|
||||
}
|
||||
// sync with kill goroutine
|
||||
close(waitDone)
|
||||
if err != nil {
|
||||
sendErrorReply(s, "execve: wait4 %v", err)
|
||||
break loop
|
||||
}
|
||||
} else {
|
||||
switch {
|
||||
case wstatus.Exited():
|
||||
reply := Reply{ExitStatus: wstatus.ExitStatus()}
|
||||
sendReply(s, &reply, nil)
|
||||
break loop
|
||||
|
||||
case wstatus.Signaled():
|
||||
var status types.Status
|
||||
@ -245,11 +241,12 @@ loop:
|
||||
}
|
||||
reply := Reply{Status: status}
|
||||
sendReply(s, &reply, nil)
|
||||
break loop
|
||||
default:
|
||||
sendErrorReply(s, "execve: unknown status %v", wstatus)
|
||||
}
|
||||
}
|
||||
// wait for kill msg and reply done for finish
|
||||
<-done
|
||||
<-killDone
|
||||
return sendReply(s, &Reply{}, nil)
|
||||
}
|
||||
|
||||
|
||||
@ -62,19 +62,18 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.
|
||||
// make sure goroutine not leaked (blocked) even if result is not consumed
|
||||
wait := make(chan types.Result, 1)
|
||||
waitDone := make(chan struct{})
|
||||
killDone := make(chan struct{})
|
||||
// Wait
|
||||
go func() {
|
||||
defer close(wait)
|
||||
reply2, _, _ := m.recvReply()
|
||||
close(waitDone)
|
||||
<-killDone
|
||||
// done signal (should recv after kill)
|
||||
m.recvReply()
|
||||
// emit result after all communication finish
|
||||
wait <- types.Result{
|
||||
ExitStatus: reply2.ExitStatus,
|
||||
Status: reply2.Status,
|
||||
}
|
||||
// done signal (should recv after kill)
|
||||
m.recvReply()
|
||||
}()
|
||||
// Kill (if wait is done, a kill message need to be send to collect zombies)
|
||||
go func() {
|
||||
@ -83,7 +82,6 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.
|
||||
case <-waitDone:
|
||||
}
|
||||
m.sendCmd(&Cmd{Cmd: cmdKill}, nil)
|
||||
close(killDone)
|
||||
}()
|
||||
return wait, nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user