Преглед на файлове

Merge pull request #14422 from Microsoft/10662-dumpstacks

Windows: Win32 event for sigusr1 linux equivalence
Arnaud Porterie преди 10 години
родител
ревизия
2ea4d90da4
променени са 5 файла, в които са добавени 119 реда и са изтрити 5 реда
  1. 3 2
      daemon/daemon.go
  2. 1 1
      daemon/debugtrap_unix.go
  3. 2 2
      daemon/debugtrap_unsupported.go
  4. 30 0
      daemon/debugtrap_windows.go
  5. 83 0
      pkg/system/events_windows.go

+ 3 - 2
daemon/daemon.go

@@ -568,8 +568,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
 		return nil, err
 	}
 
-	// set up SIGUSR1 handler to dump Go routine stacks
-	setupSigusr1Trap()
+	// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event
+	// on Windows to dump Go routine stacks
+	setupDumpStackTrap()
 
 	// get the canonical path to the Docker root directory
 	var realRoot string

+ 1 - 1
daemon/debugtrap.go → daemon/debugtrap_unix.go

@@ -10,7 +10,7 @@ import (
 	psignal "github.com/docker/docker/pkg/signal"
 )
 
-func setupSigusr1Trap() {
+func setupDumpStackTrap() {
 	c := make(chan os.Signal, 1)
 	signal.Notify(c, syscall.SIGUSR1)
 	go func() {

+ 2 - 2
daemon/debugtrap_unsupported.go

@@ -1,7 +1,7 @@
-// +build !linux,!darwin,!freebsd
+// +build !linux,!darwin,!freebsd,!windows
 
 package daemon
 
-func setupSigusr1Trap() {
+func setupDumpStackTrap() {
 	return
 }

+ 30 - 0
daemon/debugtrap_windows.go

@@ -0,0 +1,30 @@
+package daemon
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+	psignal "github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/pkg/system"
+)
+
+func setupDumpStackTrap() {
+	// Windows does not support signals like *nix systems. So instead of
+	// trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be
+	// signalled.
+	go func() {
+		sa := syscall.SecurityAttributes{
+			Length: 0,
+		}
+		ev := "Global\\docker-daemon-" + fmt.Sprint(os.Getpid())
+		if h, _ := system.CreateEvent(&sa, false, false, ev); h != 0 {
+			logrus.Debugf("Stackdump - waiting signal at %s", ev)
+			for {
+				syscall.WaitForSingleObject(h, syscall.INFINITE)
+				psignal.DumpStacks()
+			}
+		}
+	}()
+}

+ 83 - 0
pkg/system/events_windows.go

@@ -0,0 +1,83 @@
+package system
+
+// This file implements syscalls for Win32 events which are not implemented
+// in golang.
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+const (
+	EVENT_ALL_ACCESS    = 0x1F0003
+	EVENT_MODIFY_STATUS = 0x0002
+)
+
+var (
+	procCreateEvent = modkernel32.NewProc("CreateEventW")
+	procOpenEvent   = modkernel32.NewProc("OpenEventW")
+	procSetEvent    = modkernel32.NewProc("SetEvent")
+	procResetEvent  = modkernel32.NewProc("ResetEvent")
+	procPulseEvent  = modkernel32.NewProc("PulseEvent")
+)
+
+func CreateEvent(eventAttributes *syscall.SecurityAttributes, manualReset bool, initialState bool, name string) (handle syscall.Handle, err error) {
+	namep, _ := syscall.UTF16PtrFromString(name)
+	var _p1 uint32 = 0
+	if manualReset {
+		_p1 = 1
+	}
+	var _p2 uint32 = 0
+	if initialState {
+		_p2 = 1
+	}
+	r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep)))
+	use(unsafe.Pointer(namep))
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		err = e1
+	}
+	return
+}
+
+func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle syscall.Handle, err error) {
+	namep, _ := syscall.UTF16PtrFromString(name)
+	var _p1 uint32 = 0
+	if inheritHandle {
+		_p1 = 1
+	}
+	r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep)))
+	use(unsafe.Pointer(namep))
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		err = e1
+	}
+	return
+}
+
+func SetEvent(handle syscall.Handle) (err error) {
+	return setResetPulse(handle, procSetEvent)
+}
+
+func ResetEvent(handle syscall.Handle) (err error) {
+	return setResetPulse(handle, procResetEvent)
+}
+
+func PulseEvent(handle syscall.Handle) (err error) {
+	return setResetPulse(handle, procPulseEvent)
+}
+
+func setResetPulse(handle syscall.Handle, proc *syscall.LazyProc) (err error) {
+	r0, _, _ := proc.Call(uintptr(handle))
+	if r0 != 0 {
+		err = syscall.Errno(r0)
+	}
+	return
+}
+
+var temp unsafe.Pointer
+
+// use ensures a variable is kept alive without the GC freeing while still needed
+func use(p unsafe.Pointer) {
+	temp = p
+}