Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions notify_socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,22 @@ func (s *notifySocket) run(pid1 int) error {
}
}

// forward reads systemd notifications from the container and forwards them
// to notifySocketHost.
func (s *notifySocket) forward(process *libcontainer.Process, detach bool) error {
if detach {
pid, err := process.Pid()
if err != nil {
return err
Comment thread
rata marked this conversation as resolved.
}
_ = s.run(pid)
} else {
_ = s.run(os.Getpid())
go func() { _ = s.run(0) }()
}
return nil
}

// notifyHost tells the host (usually systemd) that the container reported READY.
// Also sends MAINPID and BARRIER.
func notifyHost(client *net.UnixConn, ready []byte, pid1 int) error {
Expand Down
32 changes: 4 additions & 28 deletions signals.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"os/signal"

"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/utils"

"github.com/sirupsen/logrus"
Expand All @@ -16,15 +15,7 @@ const signalBufferSize = 2048

// newSignalHandler returns a signal handler for processing SIGCHLD and SIGWINCH signals
// while still forwarding all other signals to the process.
// If notifySocket is present, use it to read systemd notifications from the container and
// forward them to notifySocketHost.
func newSignalHandler(enableSubreaper bool, notifySocket *notifySocket) chan *signalHandler {
if enableSubreaper {
// set us as the subreaper before registering the signal handler for the container
if err := system.SetSubreaper(1); err != nil {
logrus.Warn(err)
}
}
func newSignalHandler() chan *signalHandler {
handler := make(chan *signalHandler)
// signal.Notify is actually quite expensive, as it has to configure the
// signal mask and add signal handlers for all signals (all ~65 of them).
Expand All @@ -37,8 +28,7 @@ func newSignalHandler(enableSubreaper bool, notifySocket *notifySocket) chan *si
// handle all signals for the process.
signal.Notify(s)
handler <- &signalHandler{
signals: s,
notifySocket: notifySocket,
signals: s,
}
}()
return handler
Expand All @@ -52,33 +42,19 @@ type exit struct {
}

type signalHandler struct {
signals chan os.Signal
notifySocket *notifySocket
signals chan os.Signal
}

// forward handles the main signal event loop forwarding, resizing, or reaping depending
// on the signal received.
func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach bool) (int, error) {
func (h *signalHandler) forward(process *libcontainer.Process, tty *tty) (int, error) {
// make sure we know the pid of our main process so that we can return
// after it dies.
if detach && h.notifySocket == nil {
return 0, nil
}

pid1, err := process.Pid()
if err != nil {
return -1, err
}

if h.notifySocket != nil {
if detach {
_ = h.notifySocket.run(pid1)
return 0, nil
}
_ = h.notifySocket.run(os.Getpid())
go func() { _ = h.notifySocket.run(0) }()
}

// Perform the initial tty resize. Always ignore errors resizing because
// stdout might have disappeared (due to races with when SIGHUP is sent).
_ = tty.resize()
Expand Down
46 changes: 30 additions & 16 deletions utils_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/specconv"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/system/kernelversion"
"github.com/opencontainers/runc/libcontainer/utils"
)
Expand Down Expand Up @@ -219,14 +220,16 @@ type runner struct {
subCgroupPaths map[string]string
}

func (r *runner) run(config *specs.Process) (int, error) {
var err error
func (r *runner) run(config *specs.Process) (_ int, retErr error) {
detach := r.detach || (r.action == CT_ACT_CREATE)
defer func() {
if err != nil {
// For a non-detached container, or we get an error, we
// should destroy the container.
if !detach || retErr != nil {
Comment thread
lifubang marked this conversation as resolved.
Comment thread
rata marked this conversation as resolved.
Comment thread
rata marked this conversation as resolved.
r.destroy()
}
}()
if err = r.checkTerminal(config); err != nil {
if err := r.checkTerminal(config); err != nil {
return -1, err
}
process, err := newProcess(config)
Expand Down Expand Up @@ -255,11 +258,19 @@ func (r *runner) run(config *specs.Process) (int, error) {
}
process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "PreserveFD:"+strconv.Itoa(i)))
}
detach := r.detach || (r.action == CT_ACT_CREATE)
// Setting up IO is a two stage process. We need to modify process to deal
// with detaching containers, and then we get a tty after the container has
// started.
handlerCh := newSignalHandler(r.enableSubreaper, r.notifySocket)
if r.enableSubreaper {
// set us as the subreaper before registering the signal handler for the container
Comment thread
rata marked this conversation as resolved.
if err := system.SetSubreaper(1); err != nil {
Comment thread
rata marked this conversation as resolved.
logrus.Warn(err)
}
}
var handlerCh chan *signalHandler
if !detach {
handlerCh = newSignalHandler()
}
tty, err := setupIO(process, r.container, config.Terminal, detach, r.consoleSocket)
if err != nil {
return -1, err
Expand Down Expand Up @@ -287,29 +298,32 @@ func (r *runner) run(config *specs.Process) (int, error) {
if err != nil {
return -1, err
}
defer func() {
// We should terminate the process once we got an error.
if retErr != nil {
r.terminate(process)
Comment on lines +301 to +304
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated now. The function deferred previously will also do the exact same thing. Is this on purpose?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Therefore, was this also unnecessary in the past? I suggest we keep it, as there may have been scenarios we haven't taken into account.

}
}()
if err = tty.waitConsole(); err != nil {
r.terminate(process)
return -1, err
}
tty.ClosePostStart()
if r.pidFile != "" {
if err = createPidFile(r.pidFile, process); err != nil {
r.terminate(process)
return -1, err
}
}
handler := <-handlerCh
status, err := handler.forward(process, tty, detach)
if err != nil {
r.terminate(process)
if r.notifySocket != nil {
if err = r.notifySocket.forward(process, detach); err != nil {
return -1, err
Comment thread
rata marked this conversation as resolved.
}
}
if detach {
return 0, nil
}
if err == nil {
r.destroy()
}
return status, err
// For non-detached container, we should forward signals to the container.
handler := <-handlerCh
return handler.forward(process, tty)
}

func (r *runner) destroy() {
Expand Down
Loading