diff options
author | Kevin Krakauer <krakauer@google.com> | 2018-09-17 16:24:05 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-09-17 16:25:24 -0700 |
commit | bb88c187c5457df14fa78e5e6b6f48cbc90fb489 (patch) | |
tree | a92886651d7657480b7f696ebe7a5f774916a1cb /pkg/sentry | |
parent | ab6fa44588233fa48d1ae0bf7d9b0d9e984a6af0 (diff) |
runsc: Enable waiting on exited processes.
This makes `runsc wait` behave more like waitpid()/wait4() in that:
- Once a process has run to completion, you can wait on it and get its exit
code.
- Processes not waited on will consume memory (like a zombie process)
PiperOrigin-RevId: 213358916
Change-Id: I5b5eca41ce71eea68e447380df8c38361a4d1558
Diffstat (limited to 'pkg/sentry')
-rw-r--r-- | pkg/sentry/control/proc.go | 14 | ||||
-rw-r--r-- | pkg/sentry/kernel/kernel.go | 17 |
2 files changed, 17 insertions, 14 deletions
diff --git a/pkg/sentry/control/proc.go b/pkg/sentry/control/proc.go index 19bc76f5c..68d3b179b 100644 --- a/pkg/sentry/control/proc.go +++ b/pkg/sentry/control/proc.go @@ -87,7 +87,7 @@ type ExecArgs struct { // Exec runs a new task. func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error { - newTG, err := proc.execAsync(args) + newTG, _, err := proc.execAsync(args) if err != nil { return err } @@ -100,11 +100,13 @@ func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error { // ExecAsync runs a new task, but doesn't wait for it to finish. It is defined // as a function rather than a method to avoid exposing execAsync as an RPC. -func ExecAsync(proc *Proc, args *ExecArgs) (*kernel.ThreadGroup, error) { +func ExecAsync(proc *Proc, args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, error) { return proc.execAsync(args) } -func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, error) { +// execAsync runs a new task, but doesn't wait for it to finish. It returns the +// newly created thread group and its PID. +func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, error) { // Import file descriptors. l := limits.NewLimitSet() fdm := proc.Kernel.NewFDMap() @@ -144,7 +146,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, error) { paths := fs.GetPath(initArgs.Envv) f, err := proc.Kernel.RootMountNamespace().ResolveExecutablePath(ctx, initArgs.WorkingDirectory, initArgs.Argv[0], paths) if err != nil { - return nil, fmt.Errorf("error finding executable %q in PATH %v: %v", initArgs.Argv[0], paths, err) + return nil, 0, fmt.Errorf("error finding executable %q in PATH %v: %v", initArgs.Argv[0], paths, err) } initArgs.Filename = f } @@ -156,7 +158,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, error) { // Import the given file FD. This dups the FD as well. file, err := host.ImportFile(ctx, int(f.Fd()), mounter, enableIoctl) if err != nil { - return nil, err + return nil, 0, err } defer file.DecRef() @@ -164,7 +166,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, error) { f.Close() if err := fdm.NewFDAt(kdefs.FD(appFD), file, kernel.FDFlags{}, l); err != nil { - return nil, err + return nil, 0, err } } diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 316612b37..f71e32ac9 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -596,13 +596,13 @@ func (ctx *createProcessContext) Value(key interface{}) interface{} { // // CreateProcess has no analogue in Linux; it is used to create the initial // application task, as well as processes started by the control server. -func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, error) { +func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, error) { k.extMu.Lock() defer k.extMu.Unlock() log.Infof("EXEC: %v", args.Argv) if k.mounts == nil { - return nil, fmt.Errorf("no kernel MountNamespace") + return nil, 0, fmt.Errorf("no kernel MountNamespace") } tg := NewThreadGroup(k.tasks.Root, NewSignalHandlers(), linux.SIGCHLD, args.Limits, k.monotonicClock) @@ -622,7 +622,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, error) { var err error wd, err = k.mounts.FindInode(ctx, root, nil, args.WorkingDirectory, args.MaxSymlinkTraversals) if err != nil { - return nil, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err) + return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err) } defer wd.DecRef() } @@ -630,10 +630,10 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, error) { if args.Filename == "" { // Was anything provided? if len(args.Argv) == 0 { - return nil, fmt.Errorf("no filename or command provided") + return nil, 0, fmt.Errorf("no filename or command provided") } if !filepath.IsAbs(args.Argv[0]) { - return nil, fmt.Errorf("'%s' is not an absolute path", args.Argv[0]) + return nil, 0, fmt.Errorf("'%s' is not an absolute path", args.Argv[0]) } args.Filename = args.Argv[0] } @@ -641,7 +641,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, error) { // Create a fresh task context. tc, err := k.LoadTaskImage(ctx, k.mounts, root, wd, args.MaxSymlinkTraversals, args.Filename, args.Argv, args.Envv, k.featureSet) if err != nil { - return nil, err + return nil, 0, err } // Take a reference on the FDMap, which will be transferred to @@ -663,17 +663,18 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, error) { } t, err := k.tasks.NewTask(config) if err != nil { - return nil, err + return nil, 0, err } // Success. + tgid := k.tasks.Root.IDOfThreadGroup(tg) if k.started { tid := k.tasks.Root.IDOfTask(t) t.Start(tid) } else if k.globalInit == nil { k.globalInit = tg } - return tg, nil + return tg, tgid, nil } // Start starts execution of all tasks in k. |