github.com/lalkh/containerd@v1.4.3/cmd/containerd/command/main_windows.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package command 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "path/filepath" 24 "unsafe" 25 26 "github.com/Microsoft/go-winio/pkg/etw" 27 "github.com/Microsoft/go-winio/pkg/etwlogrus" 28 "github.com/Microsoft/go-winio/pkg/guid" 29 "github.com/containerd/containerd/log" 30 "github.com/containerd/containerd/services/server" 31 "github.com/sirupsen/logrus" 32 "golang.org/x/sys/windows" 33 ) 34 35 var ( 36 defaultConfigPath = filepath.Join(os.Getenv("programfiles"), "containerd", "config.toml") 37 handledSignals = []os.Signal{ 38 windows.SIGTERM, 39 windows.SIGINT, 40 } 41 ) 42 43 func handleSignals(ctx context.Context, signals chan os.Signal, serverC chan *server.Server) chan struct{} { 44 done := make(chan struct{}) 45 go func() { 46 var server *server.Server 47 for { 48 select { 49 case s := <-serverC: 50 server = s 51 case s := <-signals: 52 log.G(ctx).WithField("signal", s).Debug("received signal") 53 54 if err := notifyStopping(ctx); err != nil { 55 log.G(ctx).WithError(err).Error("notify stopping failed") 56 } 57 58 if server == nil { 59 close(done) 60 return 61 } 62 server.Stop() 63 close(done) 64 } 65 } 66 }() 67 setupDumpStacks() 68 return done 69 } 70 71 func setupDumpStacks() { 72 // Windows does not support signals like *nix systems. So instead of 73 // trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be 74 // signaled. ACL'd to builtin administrators and local system 75 event := "Global\\stackdump-" + fmt.Sprint(os.Getpid()) 76 ev, _ := windows.UTF16PtrFromString(event) 77 sd, err := windows.SecurityDescriptorFromString("D:P(A;;GA;;;BA)(A;;GA;;;SY)") 78 if err != nil { 79 logrus.Errorf("failed to get security descriptor for debug stackdump event %s: %s", event, err.Error()) 80 return 81 } 82 var sa windows.SecurityAttributes 83 sa.Length = uint32(unsafe.Sizeof(sa)) 84 sa.InheritHandle = 1 85 sa.SecurityDescriptor = sd 86 h, err := windows.CreateEvent(&sa, 0, 0, ev) 87 if h == 0 || err != nil { 88 logrus.Errorf("failed to create debug stackdump event %s: %s", event, err.Error()) 89 return 90 } 91 go func() { 92 logrus.Debugf("Stackdump - waiting signal at %s", event) 93 for { 94 windows.WaitForSingleObject(h, windows.INFINITE) 95 dumpStacks(true) 96 } 97 }() 98 } 99 100 func etwCallback(sourceID guid.GUID, state etw.ProviderState, level etw.Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr) { 101 if state == etw.ProviderStateCaptureState { 102 dumpStacks(false) 103 } 104 } 105 106 func init() { 107 // Provider ID: 2acb92c0-eb9b-571a-69cf-8f3410f383ad 108 // Provider and hook aren't closed explicitly, as they will exist until 109 // process exit. GUID is generated based on name - see 110 // Microsoft/go-winio/tools/etw-provider-gen. 111 provider, err := etw.NewProvider("ContainerD", etwCallback) 112 if err != nil { 113 logrus.Error(err) 114 } else { 115 if hook, err := etwlogrus.NewHookFromProvider(provider); err == nil { 116 logrus.AddHook(hook) 117 } else { 118 logrus.Error(err) 119 } 120 } 121 }