github.com/demonoid81/containerd@v1.3.4/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  	winio "github.com/Microsoft/go-winio"
    27  	"github.com/Microsoft/go-winio/pkg/etw"
    28  	"github.com/Microsoft/go-winio/pkg/etwlogrus"
    29  	"github.com/Microsoft/go-winio/pkg/guid"
    30  	"github.com/containerd/containerd/log"
    31  	"github.com/containerd/containerd/services/server"
    32  	"github.com/sirupsen/logrus"
    33  	"golang.org/x/sys/windows"
    34  )
    35  
    36  var (
    37  	defaultConfigPath = filepath.Join(os.Getenv("programfiles"), "containerd", "config.toml")
    38  	handledSignals    = []os.Signal{
    39  		windows.SIGTERM,
    40  		windows.SIGINT,
    41  	}
    42  )
    43  
    44  func handleSignals(ctx context.Context, signals chan os.Signal, serverC chan *server.Server) chan struct{} {
    45  	done := make(chan struct{})
    46  	go func() {
    47  		var server *server.Server
    48  		for {
    49  			select {
    50  			case s := <-serverC:
    51  				server = s
    52  			case s := <-signals:
    53  				log.G(ctx).WithField("signal", s).Debug("received signal")
    54  
    55  				if err := notifyStopping(ctx); err != nil {
    56  					log.G(ctx).WithError(err).Error("notify stopping failed")
    57  				}
    58  
    59  				if server == nil {
    60  					close(done)
    61  					return
    62  				}
    63  				server.Stop()
    64  				close(done)
    65  			}
    66  		}
    67  	}()
    68  	setupDumpStacks()
    69  	return done
    70  }
    71  
    72  func setupDumpStacks() {
    73  	// Windows does not support signals like *nix systems. So instead of
    74  	// trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be
    75  	// signaled. ACL'd to builtin administrators and local system
    76  	event := "Global\\stackdump-" + fmt.Sprint(os.Getpid())
    77  	ev, _ := windows.UTF16PtrFromString(event)
    78  	sd, err := winio.SddlToSecurityDescriptor("D:P(A;;GA;;;BA)(A;;GA;;;SY)")
    79  	if err != nil {
    80  		logrus.Errorf("failed to get security descriptor for debug stackdump event %s: %s", event, err.Error())
    81  		return
    82  	}
    83  	var sa windows.SecurityAttributes
    84  	sa.Length = uint32(unsafe.Sizeof(sa))
    85  	sa.InheritHandle = 1
    86  	sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0]))
    87  	h, err := windows.CreateEvent(&sa, 0, 0, ev)
    88  	if h == 0 || err != nil {
    89  		logrus.Errorf("failed to create debug stackdump event %s: %s", event, err.Error())
    90  		return
    91  	}
    92  	go func() {
    93  		logrus.Debugf("Stackdump - waiting signal at %s", event)
    94  		for {
    95  			windows.WaitForSingleObject(h, windows.INFINITE)
    96  			dumpStacks(true)
    97  		}
    98  	}()
    99  }
   100  
   101  func etwCallback(sourceID guid.GUID, state etw.ProviderState, level etw.Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr) {
   102  	if state == etw.ProviderStateCaptureState {
   103  		dumpStacks(false)
   104  	}
   105  }
   106  
   107  func init() {
   108  	// Provider ID: 2acb92c0-eb9b-571a-69cf-8f3410f383ad
   109  	// Provider and hook aren't closed explicitly, as they will exist until
   110  	// process exit. GUID is generated based on name - see
   111  	// Microsoft/go-winio/tools/etw-provider-gen.
   112  	provider, err := etw.NewProvider("ContainerD", etwCallback)
   113  	if err != nil {
   114  		logrus.Error(err)
   115  	} else {
   116  		if hook, err := etwlogrus.NewHookFromProvider(provider); err == nil {
   117  			logrus.AddHook(hook)
   118  		} else {
   119  			logrus.Error(err)
   120  		}
   121  	}
   122  }