mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Replace kernel.ExitStatus with linux.WaitStatus.
PiperOrigin-RevId: 383705129
This commit is contained in:
@@ -14,6 +14,10 @@
|
||||
|
||||
package linux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Options for waitpid(2), wait4(2), and/or waitid(2), from
|
||||
// include/uapi/linux/wait.h.
|
||||
const (
|
||||
@@ -34,3 +38,124 @@ const (
|
||||
P_PID = 0x1
|
||||
P_PGID = 0x2
|
||||
)
|
||||
|
||||
// WaitStatus represents a thread status, as returned by the wait* family of
|
||||
// syscalls.
|
||||
type WaitStatus uint32
|
||||
|
||||
// WaitStatusExit returns a WaitStatus representing the given exit status.
|
||||
func WaitStatusExit(status int32) WaitStatus {
|
||||
return WaitStatus(uint32(status) << 8)
|
||||
}
|
||||
|
||||
// WaitStatusTerminationSignal returns a WaitStatus representing termination by
|
||||
// the given signal.
|
||||
func WaitStatusTerminationSignal(sig Signal) WaitStatus {
|
||||
return WaitStatus(uint32(sig))
|
||||
}
|
||||
|
||||
// WaitStatusStopped returns a WaitStatus representing stoppage by the given
|
||||
// signal or ptrace trap code.
|
||||
func WaitStatusStopped(code uint32) WaitStatus {
|
||||
return WaitStatus(code<<8 | 0x7f)
|
||||
}
|
||||
|
||||
// WaitStatusContinued returns a WaitStatus representing continuation by
|
||||
// SIGCONT.
|
||||
func WaitStatusContinued() WaitStatus {
|
||||
return WaitStatus(0xffff)
|
||||
}
|
||||
|
||||
// WithCoreDump returns a copy of ws that indicates that a core dump was
|
||||
// generated.
|
||||
//
|
||||
// Preconditions: ws.Signaled().
|
||||
func (ws WaitStatus) WithCoreDump() WaitStatus {
|
||||
return ws | 0x80
|
||||
}
|
||||
|
||||
// Exited returns true if ws represents an exit status, consistent with
|
||||
// WIFEXITED.
|
||||
func (ws WaitStatus) Exited() bool {
|
||||
return ws&0x7f == 0
|
||||
}
|
||||
|
||||
// Signaled returns true if ws represents a termination by signal, consistent
|
||||
// with WIFSIGNALED.
|
||||
func (ws WaitStatus) Signaled() bool {
|
||||
// ws&0x7f != 0 (exited) and ws&0x7f != 0x7f (stopped or continued)
|
||||
return ((ws&0x7f)+1)>>1 != 0
|
||||
}
|
||||
|
||||
// CoreDumped returns true if ws indicates that a core dump was produced,
|
||||
// consistent with WCOREDUMP.
|
||||
//
|
||||
// Preconditions: ws.Signaled().
|
||||
func (ws WaitStatus) CoreDumped() bool {
|
||||
return ws&0x80 != 0
|
||||
}
|
||||
|
||||
// Stopped returns true if ws represents a stoppage, consistent with
|
||||
// WIFSTOPPED.
|
||||
func (ws WaitStatus) Stopped() bool {
|
||||
return ws&0xff == 0x7f
|
||||
}
|
||||
|
||||
// Continued returns true if ws represents a continuation by SIGCONT,
|
||||
// consistent with WIFCONTINUED.
|
||||
func (ws WaitStatus) Continued() bool {
|
||||
return ws == 0xffff
|
||||
}
|
||||
|
||||
// ExitStatus returns the lower 8 bits of the exit status represented by ws,
|
||||
// consistent with WEXITSTATUS.
|
||||
//
|
||||
// Preconditions: ws.Exited().
|
||||
func (ws WaitStatus) ExitStatus() uint32 {
|
||||
return uint32((ws & 0xff00) >> 8)
|
||||
}
|
||||
|
||||
// TerminationSignal returns the termination signal represented by ws,
|
||||
// consistent with WTERMSIG.
|
||||
//
|
||||
// Preconditions: ws.Signaled().
|
||||
func (ws WaitStatus) TerminationSignal() Signal {
|
||||
return Signal(ws & 0x7f)
|
||||
}
|
||||
|
||||
// StopSignal returns the stop signal represented by ws, consistent with
|
||||
// WSTOPSIG.
|
||||
//
|
||||
// Preconditions: ws.Stopped().
|
||||
func (ws WaitStatus) StopSignal() Signal {
|
||||
return Signal((ws & 0xff00) >> 8)
|
||||
}
|
||||
|
||||
// PtraceEvent returns the PTRACE_EVENT_* field in ws.
|
||||
//
|
||||
// Preconditions: ws.Stopped().
|
||||
func (ws WaitStatus) PtraceEvent() uint32 {
|
||||
return uint32(ws >> 16)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (ws WaitStatus) String() string {
|
||||
switch {
|
||||
case ws.Exited():
|
||||
return fmt.Sprintf("exit status %d", ws.ExitStatus())
|
||||
case ws.Signaled():
|
||||
if ws.CoreDumped() {
|
||||
return fmt.Sprintf("killed by signal %d (core dumped)", ws.TerminationSignal())
|
||||
}
|
||||
return fmt.Sprintf("killed by signal %d", ws.TerminationSignal())
|
||||
case ws.Stopped():
|
||||
if ev := ws.PtraceEvent(); ev != 0 {
|
||||
return fmt.Sprintf("stopped by signal %d (PTRACE_EVENT %d)", ws.StopSignal(), ev)
|
||||
}
|
||||
return fmt.Sprintf("stopped by signal %d", ws.StopSignal())
|
||||
case ws.Continued():
|
||||
return "continued"
|
||||
default:
|
||||
return fmt.Sprintf("unknown status %#x", uint32(ws))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error {
|
||||
|
||||
// Wait for completion.
|
||||
newTG.WaitExited()
|
||||
*waitStatus = newTG.ExitStatus().Status()
|
||||
*waitStatus = uint32(newTG.ExitStatus())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package control
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/state"
|
||||
@@ -67,7 +68,7 @@ func (s *State) Save(o *SaveOpts, _ *struct{}) error {
|
||||
log.Warningf("Save failed: exiting...")
|
||||
s.Kernel.SetSaveError(err)
|
||||
}
|
||||
s.Kernel.Kill(kernel.ExitStatus{})
|
||||
s.Kernel.Kill(linux.WaitStatusExit(0))
|
||||
},
|
||||
}
|
||||
return saveOpts.Save(s.Kernel.SupervisorContext(), s.Kernel, s.Watchdog)
|
||||
|
||||
@@ -1299,11 +1299,11 @@ func (k *Kernel) WaitExited() {
|
||||
}
|
||||
|
||||
// Kill requests that all tasks in k immediately exit as if group exiting with
|
||||
// status es. Kill does not wait for tasks to exit.
|
||||
func (k *Kernel) Kill(es ExitStatus) {
|
||||
// status ws. Kill does not wait for tasks to exit.
|
||||
func (k *Kernel) Kill(ws linux.WaitStatus) {
|
||||
k.extMu.Lock()
|
||||
defer k.extMu.Unlock()
|
||||
k.tasks.Kill(es)
|
||||
k.tasks.Kill(ws)
|
||||
}
|
||||
|
||||
// Pause requests that all tasks in k temporarily stop executing, and blocks
|
||||
|
||||
@@ -912,7 +912,7 @@ func (t *Task) ptraceExit() {
|
||||
return
|
||||
}
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
status := t.exitStatus.Status()
|
||||
status := t.exitStatus
|
||||
t.tg.signalHandlers.mu.Unlock()
|
||||
t.Debugf("Entering PTRACE_EVENT_EXIT stop")
|
||||
t.ptraceEventLocked(linux.PTRACE_EVENT_EXIT, uint64(status))
|
||||
|
||||
@@ -232,7 +232,7 @@ type Task struct {
|
||||
// exitStatus is the task's exit status.
|
||||
//
|
||||
// exitStatus is protected by the signal mutex.
|
||||
exitStatus ExitStatus
|
||||
exitStatus linux.WaitStatus
|
||||
|
||||
// syscallRestartBlock represents a custom restart function to run in
|
||||
// restart_syscall(2) to resume an interrupted syscall.
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
@@ -37,58 +36,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// An ExitStatus is a value communicated from an exiting task or thread group
|
||||
// to the party that reaps it.
|
||||
//
|
||||
// +stateify savable
|
||||
type ExitStatus struct {
|
||||
// Code is the numeric value passed to the call to exit or exit_group that
|
||||
// caused the exit. If the exit was not caused by such a call, Code is 0.
|
||||
Code int
|
||||
|
||||
// Signo is the signal that caused the exit. If the exit was not caused by
|
||||
// a signal, Signo is 0.
|
||||
Signo int
|
||||
}
|
||||
|
||||
func (es ExitStatus) String() string {
|
||||
var b strings.Builder
|
||||
if code := es.Code; code != 0 {
|
||||
if b.Len() != 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
_, _ = fmt.Fprintf(&b, "Code=%d", code)
|
||||
}
|
||||
if signal := es.Signo; signal != 0 {
|
||||
if b.Len() != 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
_, _ = fmt.Fprintf(&b, "Signal=%d", signal)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Signaled returns true if the ExitStatus indicates that the exiting task or
|
||||
// thread group was killed by a signal.
|
||||
func (es ExitStatus) Signaled() bool {
|
||||
return es.Signo != 0
|
||||
}
|
||||
|
||||
// Status returns the numeric representation of the ExitStatus returned by e.g.
|
||||
// the wait4() system call.
|
||||
func (es ExitStatus) Status() uint32 {
|
||||
return ((uint32(es.Code) & 0xff) << 8) | (uint32(es.Signo) & 0xff)
|
||||
}
|
||||
|
||||
// ShellExitCode returns the numeric exit code that Bash would return for an
|
||||
// exit status of es.
|
||||
func (es ExitStatus) ShellExitCode() int {
|
||||
if es.Signaled() {
|
||||
return 128 + es.Signo
|
||||
}
|
||||
return es.Code
|
||||
}
|
||||
|
||||
// TaskExitState represents a step in the task exit path.
|
||||
//
|
||||
// "Exiting" and "exited" are often ambiguous; prefer to name specific states.
|
||||
@@ -164,13 +111,13 @@ func (t *Task) killedLocked() bool {
|
||||
return t.pendingSignals.pendingSet&linux.SignalSetOf(linux.SIGKILL) != 0
|
||||
}
|
||||
|
||||
// PrepareExit indicates an exit with status es.
|
||||
// PrepareExit indicates an exit with the given status.
|
||||
//
|
||||
// Preconditions: The caller must be running on the task goroutine.
|
||||
func (t *Task) PrepareExit(es ExitStatus) {
|
||||
func (t *Task) PrepareExit(ws linux.WaitStatus) {
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
defer t.tg.signalHandlers.mu.Unlock()
|
||||
t.exitStatus = es
|
||||
t.exitStatus = ws
|
||||
}
|
||||
|
||||
// PrepareGroupExit indicates a group exit with status es to t's thread group.
|
||||
@@ -181,7 +128,7 @@ func (t *Task) PrepareExit(es ExitStatus) {
|
||||
// ptrace.)
|
||||
//
|
||||
// Preconditions: The caller must be running on the task goroutine.
|
||||
func (t *Task) PrepareGroupExit(es ExitStatus) {
|
||||
func (t *Task) PrepareGroupExit(ws linux.WaitStatus) {
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
defer t.tg.signalHandlers.mu.Unlock()
|
||||
if t.tg.exiting || t.tg.execing != nil {
|
||||
@@ -199,8 +146,8 @@ func (t *Task) PrepareGroupExit(es ExitStatus) {
|
||||
return
|
||||
}
|
||||
t.tg.exiting = true
|
||||
t.tg.exitStatus = es
|
||||
t.exitStatus = es
|
||||
t.tg.exitStatus = ws
|
||||
t.exitStatus = ws
|
||||
for sibling := t.tg.tasks.Front(); sibling != nil; sibling = sibling.Next() {
|
||||
if sibling != t {
|
||||
sibling.killLocked()
|
||||
@@ -208,11 +155,11 @@ func (t *Task) PrepareGroupExit(es ExitStatus) {
|
||||
}
|
||||
}
|
||||
|
||||
// Kill requests that all tasks in ts exit as if group exiting with status es.
|
||||
// Kill requests that all tasks in ts exit as if group exiting with status ws.
|
||||
// Kill does not wait for tasks to exit.
|
||||
//
|
||||
// Kill has no analogue in Linux; it's provided for save/restore only.
|
||||
func (ts *TaskSet) Kill(es ExitStatus) {
|
||||
func (ts *TaskSet) Kill(ws linux.WaitStatus) {
|
||||
ts.mu.Lock()
|
||||
defer ts.mu.Unlock()
|
||||
ts.Root.exiting = true
|
||||
@@ -220,7 +167,7 @@ func (ts *TaskSet) Kill(es ExitStatus) {
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
if !t.tg.exiting {
|
||||
t.tg.exiting = true
|
||||
t.tg.exitStatus = es
|
||||
t.tg.exitStatus = ws
|
||||
}
|
||||
t.killLocked()
|
||||
t.tg.signalHandlers.mu.Unlock()
|
||||
@@ -731,10 +678,10 @@ func (t *Task) exitNotificationSignal(sig linux.Signal, receiver *Task) *linux.S
|
||||
info.SetUID(int32(t.Credentials().RealKUID.In(receiver.UserNamespace()).OrOverflow()))
|
||||
if t.exitStatus.Signaled() {
|
||||
info.Code = linux.CLD_KILLED
|
||||
info.SetStatus(int32(t.exitStatus.Signo))
|
||||
info.SetStatus(int32(t.exitStatus.TerminationSignal()))
|
||||
} else {
|
||||
info.Code = linux.CLD_EXITED
|
||||
info.SetStatus(int32(t.exitStatus.Code))
|
||||
info.SetStatus(int32(t.exitStatus.ExitStatus()))
|
||||
}
|
||||
// TODO(b/72102453): Set utime, stime.
|
||||
return info
|
||||
@@ -742,7 +689,7 @@ func (t *Task) exitNotificationSignal(sig linux.Signal, receiver *Task) *linux.S
|
||||
|
||||
// ExitStatus returns t's exit status, which is only guaranteed to be
|
||||
// meaningful if t.ExitState() != TaskExitNone.
|
||||
func (t *Task) ExitStatus() ExitStatus {
|
||||
func (t *Task) ExitStatus() linux.WaitStatus {
|
||||
t.tg.pidns.owner.mu.RLock()
|
||||
defer t.tg.pidns.owner.mu.RUnlock()
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
@@ -752,7 +699,7 @@ func (t *Task) ExitStatus() ExitStatus {
|
||||
|
||||
// ExitStatus returns the exit status that would be returned by a consuming
|
||||
// wait*() on tg.
|
||||
func (tg *ThreadGroup) ExitStatus() ExitStatus {
|
||||
func (tg *ThreadGroup) ExitStatus() linux.WaitStatus {
|
||||
tg.pidns.owner.mu.RLock()
|
||||
defer tg.pidns.owner.mu.RUnlock()
|
||||
tg.signalHandlers.mu.Lock()
|
||||
@@ -763,7 +710,9 @@ func (tg *ThreadGroup) ExitStatus() ExitStatus {
|
||||
return tg.leader.exitStatus
|
||||
}
|
||||
|
||||
// TerminationSignal returns the thread group's termination signal.
|
||||
// TerminationSignal returns the thread group's termination signal, which is
|
||||
// the signal that will be sent to its leader's parent when all threads have
|
||||
// exited.
|
||||
func (tg *ThreadGroup) TerminationSignal() linux.Signal {
|
||||
tg.pidns.owner.mu.RLock()
|
||||
defer tg.pidns.owner.mu.RUnlock()
|
||||
@@ -889,8 +838,8 @@ type WaitResult struct {
|
||||
// Event is exactly one of the events defined above.
|
||||
Event waiter.EventMask
|
||||
|
||||
// Status is the numeric status associated with the event.
|
||||
Status uint32
|
||||
// Status is the wait status associated with the event.
|
||||
Status linux.WaitStatus
|
||||
}
|
||||
|
||||
// Wait waits for an event from a thread group that is a child of t's thread
|
||||
@@ -1043,7 +992,7 @@ func (t *Task) waitCollectZombieLocked(target *Task, opts *WaitOptions, asPtrace
|
||||
}
|
||||
pid := t.tg.pidns.tids[target]
|
||||
uid := target.Credentials().RealKUID.In(t.UserNamespace()).OrOverflow()
|
||||
status := target.exitStatus.Status()
|
||||
status := target.exitStatus
|
||||
if !opts.ConsumeEvent {
|
||||
return &WaitResult{
|
||||
Task: target,
|
||||
@@ -1057,7 +1006,7 @@ func (t *Task) waitCollectZombieLocked(target *Task, opts *WaitOptions, asPtrace
|
||||
// differ from that reported by a consuming wait; the latter will return
|
||||
// the group exit code if one is available.
|
||||
if target.tg.exiting {
|
||||
status = target.tg.exitStatus.Status()
|
||||
status = target.tg.exitStatus
|
||||
}
|
||||
// t may be (in the thread group of) target's parent, tracer, or both. We
|
||||
// don't need to check for !exitTracerAcked because tracees are detached
|
||||
@@ -1123,12 +1072,11 @@ func (t *Task) waitCollectChildGroupStopLocked(target *Task, opts *WaitOptions)
|
||||
target.tg.groupStopWaitable = false
|
||||
}
|
||||
return &WaitResult{
|
||||
Task: target,
|
||||
TID: pid,
|
||||
UID: uid,
|
||||
Event: EventChildGroupStop,
|
||||
// There is no name for these status constants.
|
||||
Status: (uint32(sig)&0xff)<<8 | 0x7f,
|
||||
Task: target,
|
||||
TID: pid,
|
||||
UID: uid,
|
||||
Event: EventChildGroupStop,
|
||||
Status: linux.WaitStatusStopped(uint32(sig)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,7 +1097,7 @@ func (t *Task) waitCollectGroupContinueLocked(target *Task, opts *WaitOptions) *
|
||||
TID: pid,
|
||||
UID: uid,
|
||||
Event: EventGroupContinue,
|
||||
Status: 0xffff,
|
||||
Status: linux.WaitStatusContinued(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,7 +1125,7 @@ func (t *Task) waitCollectTraceeStopLocked(target *Task, opts *WaitOptions) *Wai
|
||||
TID: pid,
|
||||
UID: uid,
|
||||
Event: EventTraceeStop,
|
||||
Status: uint32(code)<<8 | 0x7f,
|
||||
Status: linux.WaitStatusStopped(uint32(code)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ func (t *Task) traceExitEvent() {
|
||||
if !trace.IsEnabled() {
|
||||
return
|
||||
}
|
||||
trace.Logf(t.traceContext, traceCategory, "exit status: 0x%x", t.exitStatus.Status())
|
||||
trace.Logf(t.traceContext, traceCategory, "exit status: %s", t.exitStatus)
|
||||
}
|
||||
|
||||
// traceExecEvent is called when a task calls exec.
|
||||
|
||||
@@ -377,7 +377,7 @@ func (app *runApp) execute(t *Task) taskRunState {
|
||||
default:
|
||||
// What happened? Can't continue.
|
||||
t.Warningf("Unexpected SwitchToApp error: %v", err)
|
||||
t.PrepareExit(ExitStatus{Code: ExtractErrno(err, -1)})
|
||||
t.PrepareExit(linux.WaitStatusExit(int32(ExtractErrno(err, -1))))
|
||||
return (*runExit)(nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,8 @@ func (t *Task) PendingSignals() linux.SignalSet {
|
||||
|
||||
// deliverSignal delivers the given signal and returns the following run state.
|
||||
func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRunState {
|
||||
sigact := computeAction(linux.Signal(info.Signo), act)
|
||||
sig := linux.Signal(info.Signo)
|
||||
sigact := computeAction(sig, act)
|
||||
|
||||
if t.haveSyscallReturn {
|
||||
if sre, ok := syserror.SyscallRestartErrnoFromReturn(t.Arch().Return()); ok {
|
||||
@@ -198,14 +199,14 @@ func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRu
|
||||
}
|
||||
|
||||
// Attach an fault address if appropriate.
|
||||
switch linux.Signal(info.Signo) {
|
||||
switch sig {
|
||||
case linux.SIGSEGV, linux.SIGFPE, linux.SIGILL, linux.SIGTRAP, linux.SIGBUS:
|
||||
ucs.FaultAddr = info.Addr()
|
||||
}
|
||||
|
||||
eventchannel.Emit(ucs)
|
||||
|
||||
t.PrepareGroupExit(ExitStatus{Signo: int(info.Signo)})
|
||||
t.PrepareGroupExit(linux.WaitStatusTerminationSignal(sig))
|
||||
return (*runExit)(nil)
|
||||
|
||||
case SignalActionStop:
|
||||
@@ -225,12 +226,12 @@ func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRu
|
||||
|
||||
// Send a forced SIGSEGV. If the signal that couldn't be delivered
|
||||
// was a SIGSEGV, force the handler to SIG_DFL.
|
||||
t.forceSignal(linux.SIGSEGV, linux.Signal(info.Signo) == linux.SIGSEGV /* unconditional */)
|
||||
t.forceSignal(linux.SIGSEGV, sig == linux.SIGSEGV /* unconditional */)
|
||||
t.SendSignal(SignalInfoPriv(linux.SIGSEGV))
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown signal action %+v, %d?", info, computeAction(linux.Signal(info.Signo), act)))
|
||||
panic(fmt.Sprintf("Unknown signal action %+v, %d?", info, computeAction(sig, act)))
|
||||
}
|
||||
return (*runInterrupt)(nil)
|
||||
}
|
||||
@@ -506,7 +507,7 @@ func (tg *ThreadGroup) applySignalSideEffectsLocked(sig linux.Signal) {
|
||||
// ignores tg.execing.
|
||||
if !tg.exiting {
|
||||
tg.exiting = true
|
||||
tg.exitStatus = ExitStatus{Signo: int(linux.SIGKILL)}
|
||||
tg.exitStatus = linux.WaitStatusTerminationSignal(linux.SIGKILL)
|
||||
}
|
||||
for t := tg.tasks.Front(); t != nil; t = t.Next() {
|
||||
t.killLocked()
|
||||
|
||||
@@ -161,7 +161,7 @@ func (t *Task) doSyscall() taskRunState {
|
||||
// ok
|
||||
case linux.SECCOMP_RET_KILL_THREAD:
|
||||
t.Debugf("Syscall %d: killed by seccomp", sysno)
|
||||
t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
|
||||
t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
|
||||
return (*runExit)(nil)
|
||||
case linux.SECCOMP_RET_TRACE:
|
||||
t.Debugf("Syscall %d: stopping for PTRACE_EVENT_SECCOMP", sysno)
|
||||
@@ -311,7 +311,7 @@ func (t *Task) doVsyscall(addr hostarch.Addr, sysno uintptr) taskRunState {
|
||||
return &runVsyscallAfterPtraceEventSeccomp{addr, sysno, caller}
|
||||
case linux.SECCOMP_RET_KILL_THREAD:
|
||||
t.Debugf("vsyscall %d: killed by seccomp", sysno)
|
||||
t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
|
||||
t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
|
||||
return (*runExit)(nil)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown seccomp result %d", r))
|
||||
@@ -338,7 +338,7 @@ func (r *runVsyscallAfterPtraceEventSeccomp) execute(t *Task) taskRunState {
|
||||
// Documentation/prctl/seccomp_filter.txt. On Linux, changing orig_ax or ip
|
||||
// causes do_exit(SIGSYS), and changing sp is ignored.
|
||||
if (sysno != ^uintptr(0) && sysno != r.sysno) || hostarch.Addr(t.Arch().IP()) != r.addr {
|
||||
t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
|
||||
t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
|
||||
return (*runExit)(nil)
|
||||
}
|
||||
if sysno == ^uintptr(0) {
|
||||
|
||||
@@ -144,7 +144,7 @@ type ThreadGroup struct {
|
||||
//
|
||||
// While exiting is false, exitStatus is protected by the signal mutex.
|
||||
// When exiting becomes true, exitStatus becomes immutable.
|
||||
exitStatus ExitStatus
|
||||
exitStatus linux.WaitStatus
|
||||
|
||||
// terminationSignal is the signal that this thread group's leader will
|
||||
// send to its parent when it exits.
|
||||
|
||||
@@ -17,7 +17,6 @@ package linux
|
||||
import (
|
||||
"path"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
@@ -188,15 +187,15 @@ func execveat(t *kernel.Task, dirFD int32, pathnameAddr, argvAddr, envvAddr host
|
||||
|
||||
// Exit implements linux syscall exit(2).
|
||||
func Exit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
status := int(args[0].Int())
|
||||
t.PrepareExit(kernel.ExitStatus{Code: status})
|
||||
status := args[0].Int()
|
||||
t.PrepareExit(linux.WaitStatusExit(status & 0xff))
|
||||
return 0, kernel.CtrlDoExit, nil
|
||||
}
|
||||
|
||||
// ExitGroup implements linux syscall exit_group(2).
|
||||
func ExitGroup(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
status := int(args[0].Int())
|
||||
t.PrepareGroupExit(kernel.ExitStatus{Code: status})
|
||||
status := args[0].Int()
|
||||
t.PrepareGroupExit(linux.WaitStatusExit(status & 0xff))
|
||||
return 0, kernel.CtrlDoExit, nil
|
||||
}
|
||||
|
||||
@@ -316,7 +315,7 @@ func wait4(t *kernel.Task, pid int, statusAddr hostarch.Addr, options int, rusag
|
||||
return 0, err
|
||||
}
|
||||
if statusAddr != 0 {
|
||||
if _, err := primitive.CopyUint32Out(t, statusAddr, wr.Status); err != nil {
|
||||
if _, err := primitive.CopyUint32Out(t, statusAddr, uint32(wr.Status)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
@@ -419,23 +418,22 @@ func Waitid(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
|
||||
}
|
||||
si.SetPID(int32(wr.TID))
|
||||
si.SetUID(int32(wr.UID))
|
||||
// TODO(b/73541790): convert kernel.ExitStatus to functions and make
|
||||
// WaitResult.Status a linux.WaitStatus.
|
||||
s := unix.WaitStatus(wr.Status)
|
||||
s := wr.Status
|
||||
switch {
|
||||
case s.Exited():
|
||||
si.Code = linux.CLD_EXITED
|
||||
si.SetStatus(int32(s.ExitStatus()))
|
||||
case s.Signaled():
|
||||
si.Code = linux.CLD_KILLED
|
||||
si.SetStatus(int32(s.Signal()))
|
||||
case s.CoreDump():
|
||||
si.Code = linux.CLD_DUMPED
|
||||
si.SetStatus(int32(s.Signal()))
|
||||
if s.CoreDumped() {
|
||||
si.Code = linux.CLD_DUMPED
|
||||
} else {
|
||||
si.Code = linux.CLD_KILLED
|
||||
}
|
||||
si.SetStatus(int32(s.TerminationSignal()))
|
||||
case s.Stopped():
|
||||
if wr.Event == kernel.EventTraceeStop {
|
||||
si.Code = linux.CLD_TRAPPED
|
||||
si.SetStatus(int32(s.TrapCause()))
|
||||
si.SetStatus(int32(s.PtraceEvent()))
|
||||
} else {
|
||||
si.Code = linux.CLD_STOPPED
|
||||
si.SetStatus(int32(s.StopSignal()))
|
||||
|
||||
@@ -1051,7 +1051,7 @@ func (l *Loader) waitPID(tgid kernel.ThreadID, cid string, waitStatus *uint32) e
|
||||
// to exit.
|
||||
func (l *Loader) wait(tg *kernel.ThreadGroup) uint32 {
|
||||
tg.WaitExited()
|
||||
return tg.ExitStatus().Status()
|
||||
return uint32(tg.ExitStatus())
|
||||
}
|
||||
|
||||
// WaitForStartSignal waits for a start signal from the control server.
|
||||
@@ -1060,7 +1060,7 @@ func (l *Loader) WaitForStartSignal() {
|
||||
}
|
||||
|
||||
// WaitExit waits for the root container to exit, and returns its exit status.
|
||||
func (l *Loader) WaitExit() kernel.ExitStatus {
|
||||
func (l *Loader) WaitExit() linux.WaitStatus {
|
||||
// Wait for container.
|
||||
l.k.WaitExited()
|
||||
|
||||
|
||||
@@ -188,8 +188,8 @@ func doRun(t *testing.T, vfsEnabled bool) {
|
||||
}
|
||||
|
||||
// Wait for the application to exit. It should succeed.
|
||||
if status := l.WaitExit(); status.Code != 0 || status.Signo != 0 {
|
||||
t.Errorf("application exited with status %+v, want 0", status)
|
||||
if status := l.WaitExit(); !status.Exited() || status.ExitStatus() != 0 {
|
||||
t.Errorf("application exited with %s, want exit status 0", status)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -255,7 +255,7 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
|
||||
ws := l.WaitExit()
|
||||
log.Infof("application exiting with %+v", ws)
|
||||
waitStatus := args[1].(*unix.WaitStatus)
|
||||
*waitStatus = unix.WaitStatus(ws.Status())
|
||||
*waitStatus = unix.WaitStatus(ws)
|
||||
l.Destroy()
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user