Repository: opencontainers/runc
File: signals.go (Go)

Code before:
	"github.com/opencontainers/runc/libcontainer/system"
	"github.com/opencontainers/runc/libcontainer/utils"

	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

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)
		}
	}
	// ensure that we have a large buffer size so that we do not miss any signals
	// in case we are not processing them fast enough.
	s := make(chan os.Signal, signalBufferSize)
	handler := make(chan *signalHandler)
	go func() {
		// handle all signals for the process.
		signal.Notify(s)
		handler <- &signalHandler{
			signals:      s,
			notifySocket: notifySocket,
		}
	}()
	return handler
}

// exit models a process exit status with the pid and
// exit status.
type exit struct {
	pid    int
	status int
}

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

// 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) {
	// make sure we know the pid of our main process so that we can return

Review comment (performance):
It would be nice to have a comment explaining that `signal.Notify` is actually quite expensive and so we defer creating it to a goroutine for that reason. Something like

```suggestion
	// 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).
	// So, defer this to a background thread while doing the rest of the io/tty
	// setup.
	go func() {
```

Code after:
	"github.com/opencontainers/runc/libcontainer/system"
	"github.com/opencontainers/runc/libcontainer/utils"

	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

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)
		}
	}
	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).
	// So, defer this to a background thread while doing the rest of the io/tty
	// setup.
	go func() {
		// ensure that we have a large buffer size so that we do not miss any
		// signals in case we are not processing them fast enough.
		s := make(chan os.Signal, signalBufferSize)
		// handle all signals for the process.
		signal.Notify(s)
		handler <- &signalHandler{
			signals:      s,
			notifySocket: notifySocket,
		}
	}()
	return handler
}

// exit models a process exit status with the pid and
// exit status.
type exit struct {
	pid    int
	status int
}

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