summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
authorKevin Krakauer <krakauer@google.com>2018-09-17 16:24:05 -0700
committerShentubot <shentubot@google.com>2018-09-17 16:25:24 -0700
commitbb88c187c5457df14fa78e5e6b6f48cbc90fb489 (patch)
treea92886651d7657480b7f696ebe7a5f774916a1cb /pkg
parentab6fa44588233fa48d1ae0bf7d9b0d9e984a6af0 (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')
-rw-r--r--pkg/sentry/control/proc.go14
-rw-r--r--pkg/sentry/kernel/kernel.go17
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.