summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorLantao Liu <lantaol@google.com>2018-09-13 16:36:53 -0700
committerShentubot <shentubot@google.com>2018-09-13 16:38:03 -0700
commitbde2a91433cfbac426577a691bf13817115b53be (patch)
tree1403a6e5ffca3345da142bf68535763b6f34e5a9 /runsc/boot
parentadf8f339703922211886d3e5588160f65bc131b3 (diff)
runsc: Support container signal/wait.
This CL: 1) Fix `runsc wait`, it now also works after the container exits; 2) Generate correct container state in Load; 2) Make sure `Destory` cleanup everything before successfully return. PiperOrigin-RevId: 212900107 Change-Id: Ie129cbb9d74f8151a18364f1fc0b2603eac4109a
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/controller.go25
-rw-r--r--runsc/boot/loader.go75
2 files changed, 48 insertions, 52 deletions
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index aaac852e0..69154ff23 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -161,8 +161,11 @@ func (cm *containerManager) StartRoot(cid *string, _ *struct{}) error {
log.Debugf("containerManager.StartRoot")
// Tell the root container to start and wait for the result.
cm.startChan <- struct{}{}
+ if err := <-cm.startResultChan; err != nil {
+ return fmt.Errorf("failed to start sandbox: %v", err)
+ }
cm.l.setRootContainerID(*cid)
- return <-cm.startResultChan
+ return nil
}
// Processes retrieves information about processes running in the sandbox.
@@ -216,11 +219,11 @@ func (cm *containerManager) Start(args *StartArgs, _ *struct{}) error {
return fmt.Errorf("start arguments must contain at least one file for the container root")
}
- tgid, err := cm.l.startContainer(cm.l.k, args.Spec, args.Conf, args.CID, args.FilePayload.Files)
+ err := cm.l.startContainer(cm.l.k, args.Spec, args.Conf, args.CID, args.FilePayload.Files)
if err != nil {
return err
}
- log.Debugf("Container %q started with root PID of %d", args.CID, tgid)
+ log.Debugf("Container %q started", args.CID)
return nil
}
@@ -241,16 +244,12 @@ func (cm *containerManager) ExecuteAsync(args *ExecArgs, pid *int32) error {
// Get the container Root Dirent from the Task, since we must run this
// process with the same Root.
cm.l.mu.Lock()
- tgid, ok := cm.l.containerRootTGIDs[args.CID]
+ tg, ok := cm.l.containerRootTGs[args.CID]
cm.l.mu.Unlock()
if !ok {
return fmt.Errorf("cannot exec in container %q: no such container", args.CID)
}
- t := cm.l.k.TaskSet().Root.TaskWithID(kernel.ThreadID(tgid))
- if t == nil {
- return fmt.Errorf("cannot exec in container %q: no thread group with ID %d", args.CID, tgid)
- }
- t.WithMuLocked(func(t *kernel.Task) {
+ tg.Leader().WithMuLocked(func(t *kernel.Task) {
args.Root = t.FSContext().RootDirectory()
})
if args.Root != nil {
@@ -378,12 +377,15 @@ func (cm *containerManager) Restore(o *RestoreOpts, _ *struct{}) error {
cm.l.k = k
cm.l.watchdog = watchdog
cm.l.rootProcArgs = kernel.CreateProcessArgs{}
- cm.l.setRootContainerID(o.SandboxID)
cm.l.restore = true
// Tell the root container to start and wait for the result.
cm.startChan <- struct{}{}
- return <-cm.startResultChan
+ if err := <-cm.startResultChan; err != nil {
+ return fmt.Errorf("failed to start sandbox: %v", err)
+ }
+ cm.l.setRootContainerID(o.SandboxID)
+ return nil
}
// Resume unpauses a container.
@@ -423,6 +425,7 @@ type SignalArgs struct {
}
// Signal sends a signal to the init process of the container.
+// TODO: Send signal to exec process.
func (cm *containerManager) Signal(args *SignalArgs, _ *struct{}) error {
log.Debugf("containerManager.Signal")
return cm.l.signal(args.CID, args.Signo)
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 30d22b9c6..2ddb358bd 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -16,7 +16,6 @@
package boot
import (
- "errors"
"fmt"
"math/rand"
"os"
@@ -101,15 +100,15 @@ type Loader struct {
// sandboxID is the ID for the whole sandbox.
sandboxID string
- // mu guards containerRootTGIDs.
+ // mu guards containerRootTGs.
mu sync.Mutex
- // containerRootTGIDs maps container IDs to their root processes. It
+ // containerRootTGs maps container IDs to their root processes. It
// can be used to determine which process to manipulate when clients
// call methods on particular containers.
//
- // containerRootTGIDs is guarded by mu.
- containerRootTGIDs map[string]kernel.ThreadID
+ // containerRootTGs is guarded by mu.
+ containerRootTGs map[string]*kernel.ThreadGroup
}
func init() {
@@ -399,11 +398,11 @@ func (l *Loader) run() error {
// startContainer starts a child container. It returns the thread group ID of
// the newly created process.
-func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config, cid string, files []*os.File) (kernel.ThreadID, error) {
+func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config, cid string, files []*os.File) error {
// Create capabilities.
caps, err := specutils.Capabilities(spec.Process.Capabilities)
if err != nil {
- return 0, fmt.Errorf("error creating capabilities: %v", err)
+ return fmt.Errorf("error creating capabilities: %v", err)
}
// Convert the spec's additional GIDs to KGIDs.
@@ -429,7 +428,7 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
procArgs, err := newProcess(spec, creds, l.k)
if err != nil {
- return 0, fmt.Errorf("failed to create new process: %v", err)
+ return fmt.Errorf("failed to create new process: %v", err)
}
// Can't take ownership away from os.File. dup them to get a new FDs.
@@ -437,7 +436,7 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
for _, f := range files {
fd, err := syscall.Dup(int(f.Fd()))
if err != nil {
- return 0, fmt.Errorf("failed to dup file: %v", err)
+ return fmt.Errorf("failed to dup file: %v", err)
}
f.Close()
ioFDs = append(ioFDs, fd)
@@ -453,24 +452,18 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
procArgs.Limits,
k,
cid); err != nil {
- return 0, fmt.Errorf("failed to create new process: %v", err)
+ return fmt.Errorf("failed to create new process: %v", err)
}
ctx := procArgs.NewContext(l.k)
mns := k.RootMountNamespace()
if err := setExecutablePath(ctx, mns, &procArgs); err != nil {
- return 0, fmt.Errorf("error setting executable path for %+v: %v", procArgs, err)
+ return fmt.Errorf("error setting executable path for %+v: %v", procArgs, err)
}
tg, err := l.k.CreateProcess(procArgs)
if err != nil {
- return 0, fmt.Errorf("failed to create process in sentry: %v", err)
- }
-
- ts := l.k.TaskSet()
- tgid := ts.Root.IDOfThreadGroup(tg)
- if tgid == 0 {
- return 0, errors.New("failed to get thread group ID of new process")
+ return fmt.Errorf("failed to create process in sentry: %v", err)
}
// CreateProcess takes a reference on FDMap if successful.
@@ -478,9 +471,9 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
l.mu.Lock()
defer l.mu.Unlock()
- l.containerRootTGIDs[cid] = tgid
+ l.containerRootTGs[cid] = tg
- return tgid, nil
+ return nil
}
// TODO: Per-container namespaces must be supported for -pid.
@@ -490,53 +483,56 @@ func (l *Loader) waitContainer(cid string, waitStatus *uint32) error {
// Don't defer unlock, as doing so would make it impossible for
// multiple clients to wait on the same container.
l.mu.Lock()
- tgid, ok := l.containerRootTGIDs[cid]
+ tg, ok := l.containerRootTGs[cid]
if !ok {
defer l.mu.Unlock()
- return fmt.Errorf("can't find process for container %q in %v", cid, l.containerRootTGIDs)
+ return fmt.Errorf("can't find process for container %q in %v", cid, l.containerRootTGs)
}
l.mu.Unlock()
// If the thread either has already exited or exits during waiting,
// consider the container exited.
+ // TODO: Multiple calls to waitContainer() should return
+ // the same exit status.
defer func() {
l.mu.Lock()
defer l.mu.Unlock()
// TODO: Containers don't map 1:1 with their root
// processes. Container exits should be managed explicitly
// rather than via PID.
- delete(l.containerRootTGIDs, cid)
+ delete(l.containerRootTGs, cid)
}()
- return l.wait(tgid, cid, waitStatus)
+ l.wait(tg, waitStatus)
+ return nil
}
func (l *Loader) waitPID(tgid kernel.ThreadID, cid string, waitStatus *uint32) error {
// TODO: Containers all currently share a PID namespace.
// When per-container PID namespaces are supported, wait should use cid
// to find the appropriate PID namespace.
- if cid != l.sandboxID {
+ /*if cid != l.sandboxID {
return errors.New("non-sandbox PID namespaces are not yet implemented")
+ }*/
+ // TODO: This won't work if the exec process already exited.
+ tg := l.k.TaskSet().Root.ThreadGroupWithID(kernel.ThreadID(tgid))
+ if tg == nil {
+ return fmt.Errorf("no thread group with ID %d", tgid)
}
- return l.wait(tgid, cid, waitStatus)
+ l.wait(tg, waitStatus)
+ return nil
}
// wait waits for the process with TGID 'tgid' in a container's PID namespace
// to exit.
-func (l *Loader) wait(tgid kernel.ThreadID, cid string, waitStatus *uint32) error {
- tg := l.k.TaskSet().Root.ThreadGroupWithID(kernel.ThreadID(tgid))
- if tg == nil {
- return fmt.Errorf("no thread group with ID %d", tgid)
- }
+func (l *Loader) wait(tg *kernel.ThreadGroup, waitStatus *uint32) {
tg.WaitExited()
*waitStatus = tg.ExitStatus().Status()
- return nil
}
func (l *Loader) setRootContainerID(cid string) {
l.mu.Lock()
defer l.mu.Unlock()
- // The root container has PID 1.
- l.containerRootTGIDs = map[string]kernel.ThreadID{cid: 1}
+ l.containerRootTGs = map[string]*kernel.ThreadGroup{cid: l.k.GlobalInit()}
l.sandboxID = cid
}
@@ -579,18 +575,15 @@ func newEmptyNetworkStack(conf *Config, clock tcpip.Clock) (inet.Stack, error) {
}
}
+// TODO: Support sending signal to all.
func (l *Loader) signal(cid string, signo int32) error {
l.mu.Lock()
- tgid, ok := l.containerRootTGIDs[cid]
+ tg, ok := l.containerRootTGs[cid]
l.mu.Unlock()
if !ok {
return fmt.Errorf("failed to signal container %q: no such container", cid)
}
- // The thread group ID of a process is the leading task's thread ID.
- t := l.k.TaskSet().Root.TaskWithID(tgid)
- if t == nil {
- return fmt.Errorf("cannot signal: no task with ID %d", tgid)
- }
- return t.SendSignal(&arch.SignalInfo{Signo: signo})
+ si := arch.SignalInfo{Signo: signo}
+ return tg.Leader().SendSignal(&si)
}