From f4b08c7f5eed2eece239086f260eee9e736ee227 Mon Sep 17 00:00:00 2001 From: John Howard Date: Mon, 6 Jul 2015 18:58:53 -0700 Subject: [PATCH] Windows: Win32 event for sigusr1 linux equivalence Signed-off-by: John Howard --- daemon/daemon.go | 5 +- daemon/{debugtrap.go => debugtrap_unix.go} | 2 +- daemon/debugtrap_unsupported.go | 4 +- daemon/debugtrap_windows.go | 30 ++++++++ pkg/system/events_windows.go | 83 ++++++++++++++++++++++ 5 files changed, 119 insertions(+), 5 deletions(-) rename daemon/{debugtrap.go => debugtrap_unix.go} (90%) create mode 100644 daemon/debugtrap_windows.go create mode 100644 pkg/system/events_windows.go diff --git a/daemon/daemon.go b/daemon/daemon.go index d413ce3324..549a1c188e 100644 --- a/daemon/daemon.go +++ b/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 diff --git a/daemon/debugtrap.go b/daemon/debugtrap_unix.go similarity index 90% rename from daemon/debugtrap.go rename to daemon/debugtrap_unix.go index 949bf3d6fe..c4a11b07fa 100644 --- a/daemon/debugtrap.go +++ b/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() { diff --git a/daemon/debugtrap_unsupported.go b/daemon/debugtrap_unsupported.go index 1600e8b290..fef1bd776b 100644 --- a/daemon/debugtrap_unsupported.go +++ b/daemon/debugtrap_unsupported.go @@ -1,7 +1,7 @@ -// +build !linux,!darwin,!freebsd +// +build !linux,!darwin,!freebsd,!windows package daemon -func setupSigusr1Trap() { +func setupDumpStackTrap() { return } diff --git a/daemon/debugtrap_windows.go b/daemon/debugtrap_windows.go new file mode 100644 index 0000000000..4c47947ba1 --- /dev/null +++ b/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() + } + } + }() +} diff --git a/pkg/system/events_windows.go b/pkg/system/events_windows.go new file mode 100644 index 0000000000..23f7c618bc --- /dev/null +++ b/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 +}