-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In go1.14+, SIGURG is used by the runtime to handle preemtable system calls. In practice this signal caught *frequently*. For reference: https://go.googlesource.com/proposal/+/master/design/24543-non-cooperative-preemption.md golang/go#37942 Signed-off-by: Brian Goff <cpuguy83@gmail.com> (cherry picked from commit fff164c) Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
- Loading branch information
Showing
10 changed files
with
196 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package container | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
gosignal "os/signal" | ||
|
||
"github.com/docker/cli/cli/command" | ||
"github.com/docker/docker/pkg/signal" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// ForwardAllSignals forwards signals to the container | ||
// | ||
// The channel you pass in must already be setup to receive any signals you want to forward. | ||
func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <-chan os.Signal) { | ||
var s os.Signal | ||
for { | ||
select { | ||
case s = <-sigc: | ||
case <-ctx.Done(): | ||
return | ||
} | ||
|
||
if s == signal.SIGCHLD || s == signal.SIGPIPE { | ||
continue | ||
} | ||
|
||
// In go1.14+, the go runtime issues SIGURG as an interrupt to support pre-emptable system calls on Linux. | ||
// Since we can't forward that along we'll check that here. | ||
if isRuntimeSig(s) { | ||
continue | ||
} | ||
var sig string | ||
for sigStr, sigN := range signal.SignalMap { | ||
if sigN == s { | ||
sig = sigStr | ||
break | ||
} | ||
} | ||
if sig == "" { | ||
fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s) | ||
continue | ||
} | ||
|
||
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil { | ||
logrus.Debugf("Error sending signal: %s", err) | ||
} | ||
} | ||
} | ||
|
||
func notfiyAllSignals() chan os.Signal { | ||
sigc := make(chan os.Signal, 128) | ||
gosignal.Notify(sigc) | ||
return sigc | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package container | ||
|
||
import ( | ||
"os" | ||
|
||
"golang.org/x/sys/unix" | ||
) | ||
|
||
func isRuntimeSig(s os.Signal) bool { | ||
return s == unix.SIGURG | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package container | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"syscall" | ||
"testing" | ||
"time" | ||
|
||
"github.com/docker/cli/internal/test" | ||
"golang.org/x/sys/unix" | ||
"gotest.tools/v3/assert" | ||
) | ||
|
||
func TestIgnoredSignals(t *testing.T) { | ||
ignoredSignals := []syscall.Signal{unix.SIGPIPE, unix.SIGCHLD, unix.SIGURG} | ||
|
||
for _, s := range ignoredSignals { | ||
t.Run(unix.SignalName(s), func(t *testing.T) { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
var called bool | ||
client := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error { | ||
called = true | ||
return nil | ||
}} | ||
|
||
cli := test.NewFakeCli(client) | ||
sigc := make(chan os.Signal) | ||
defer close(sigc) | ||
|
||
done := make(chan struct{}) | ||
go func() { | ||
ForwardAllSignals(ctx, cli, t.Name(), sigc) | ||
close(done) | ||
}() | ||
|
||
timer := time.NewTimer(30 * time.Second) | ||
defer timer.Stop() | ||
|
||
select { | ||
case <-timer.C: | ||
t.Fatal("timeout waiting to send signal") | ||
case sigc <- s: | ||
case <-done: | ||
} | ||
|
||
// cancel the context so ForwardAllSignals will exit after it has processed the signal we sent. | ||
// This is how we know the signal was actually processed and are not introducing a flakey test. | ||
cancel() | ||
<-done | ||
|
||
assert.Assert(t, !called, "kill was called") | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// +build !linux | ||
|
||
package container | ||
|
||
import "os" | ||
|
||
func isRuntimeSig(_ os.Signal) bool { | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package container | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
"github.com/docker/cli/internal/test" | ||
"github.com/docker/docker/pkg/signal" | ||
) | ||
|
||
func TestForwardSignals(t *testing.T) { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
called := make(chan struct{}) | ||
client := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error { | ||
close(called) | ||
return nil | ||
}} | ||
|
||
cli := test.NewFakeCli(client) | ||
sigc := make(chan os.Signal) | ||
defer close(sigc) | ||
|
||
go ForwardAllSignals(ctx, cli, t.Name(), sigc) | ||
|
||
timer := time.NewTimer(30 * time.Second) | ||
defer timer.Stop() | ||
|
||
select { | ||
case <-timer.C: | ||
t.Fatal("timeout waiting to send signal") | ||
case sigc <- signal.SignalMap["TERM"]: | ||
} | ||
if !timer.Stop() { | ||
<-timer.C | ||
} | ||
timer.Reset(30 * time.Second) | ||
|
||
select { | ||
case <-called: | ||
case <-timer.C: | ||
t.Fatal("timeout waiting for signal to be processed") | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters