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