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  }