Browse code

Windows: Win32 event for sigusr1 linux equivalence

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2015/07/07 10:58:53
Showing 6 changed files
... ...
@@ -568,8 +568,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
568 568
 		return nil, err
569 569
 	}
570 570
 
571
-	// set up SIGUSR1 handler to dump Go routine stacks
572
-	setupSigusr1Trap()
571
+	// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event
572
+	// on Windows to dump Go routine stacks
573
+	setupDumpStackTrap()
573 574
 
574 575
 	// get the canonical path to the Docker root directory
575 576
 	var realRoot string
576 577
deleted file mode 100644
... ...
@@ -1,21 +0,0 @@
1
-// +build !windows
2
-
3
-package daemon
4
-
5
-import (
6
-	"os"
7
-	"os/signal"
8
-	"syscall"
9
-
10
-	psignal "github.com/docker/docker/pkg/signal"
11
-)
12
-
13
-func setupSigusr1Trap() {
14
-	c := make(chan os.Signal, 1)
15
-	signal.Notify(c, syscall.SIGUSR1)
16
-	go func() {
17
-		for range c {
18
-			psignal.DumpStacks()
19
-		}
20
-	}()
21
-}
22 1
new file mode 100644
... ...
@@ -0,0 +1,21 @@
0
+// +build !windows
1
+
2
+package daemon
3
+
4
+import (
5
+	"os"
6
+	"os/signal"
7
+	"syscall"
8
+
9
+	psignal "github.com/docker/docker/pkg/signal"
10
+)
11
+
12
+func setupDumpStackTrap() {
13
+	c := make(chan os.Signal, 1)
14
+	signal.Notify(c, syscall.SIGUSR1)
15
+	go func() {
16
+		for range c {
17
+			psignal.DumpStacks()
18
+		}
19
+	}()
20
+}
... ...
@@ -1,7 +1,7 @@
1
-// +build !linux,!darwin,!freebsd
1
+// +build !linux,!darwin,!freebsd,!windows
2 2
 
3 3
 package daemon
4 4
 
5
-func setupSigusr1Trap() {
5
+func setupDumpStackTrap() {
6 6
 	return
7 7
 }
8 8
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package daemon
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"syscall"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+	psignal "github.com/docker/docker/pkg/signal"
9
+	"github.com/docker/docker/pkg/system"
10
+)
11
+
12
+func setupDumpStackTrap() {
13
+	// Windows does not support signals like *nix systems. So instead of
14
+	// trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be
15
+	// signalled.
16
+	go func() {
17
+		sa := syscall.SecurityAttributes{
18
+			Length: 0,
19
+		}
20
+		ev := "Global\\docker-daemon-" + fmt.Sprint(os.Getpid())
21
+		if h, _ := system.CreateEvent(&sa, false, false, ev); h != 0 {
22
+			logrus.Debugf("Stackdump - waiting signal at %s", ev)
23
+			for {
24
+				syscall.WaitForSingleObject(h, syscall.INFINITE)
25
+				psignal.DumpStacks()
26
+			}
27
+		}
28
+	}()
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+package system
1
+
2
+// This file implements syscalls for Win32 events which are not implemented
3
+// in golang.
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+const (
11
+	EVENT_ALL_ACCESS    = 0x1F0003
12
+	EVENT_MODIFY_STATUS = 0x0002
13
+)
14
+
15
+var (
16
+	procCreateEvent = modkernel32.NewProc("CreateEventW")
17
+	procOpenEvent   = modkernel32.NewProc("OpenEventW")
18
+	procSetEvent    = modkernel32.NewProc("SetEvent")
19
+	procResetEvent  = modkernel32.NewProc("ResetEvent")
20
+	procPulseEvent  = modkernel32.NewProc("PulseEvent")
21
+)
22
+
23
+func CreateEvent(eventAttributes *syscall.SecurityAttributes, manualReset bool, initialState bool, name string) (handle syscall.Handle, err error) {
24
+	namep, _ := syscall.UTF16PtrFromString(name)
25
+	var _p1 uint32 = 0
26
+	if manualReset {
27
+		_p1 = 1
28
+	}
29
+	var _p2 uint32 = 0
30
+	if initialState {
31
+		_p2 = 1
32
+	}
33
+	r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep)))
34
+	use(unsafe.Pointer(namep))
35
+	handle = syscall.Handle(r0)
36
+	if handle == syscall.InvalidHandle {
37
+		err = e1
38
+	}
39
+	return
40
+}
41
+
42
+func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle syscall.Handle, err error) {
43
+	namep, _ := syscall.UTF16PtrFromString(name)
44
+	var _p1 uint32 = 0
45
+	if inheritHandle {
46
+		_p1 = 1
47
+	}
48
+	r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep)))
49
+	use(unsafe.Pointer(namep))
50
+	handle = syscall.Handle(r0)
51
+	if handle == syscall.InvalidHandle {
52
+		err = e1
53
+	}
54
+	return
55
+}
56
+
57
+func SetEvent(handle syscall.Handle) (err error) {
58
+	return setResetPulse(handle, procSetEvent)
59
+}
60
+
61
+func ResetEvent(handle syscall.Handle) (err error) {
62
+	return setResetPulse(handle, procResetEvent)
63
+}
64
+
65
+func PulseEvent(handle syscall.Handle) (err error) {
66
+	return setResetPulse(handle, procPulseEvent)
67
+}
68
+
69
+func setResetPulse(handle syscall.Handle, proc *syscall.LazyProc) (err error) {
70
+	r0, _, _ := proc.Call(uintptr(handle))
71
+	if r0 != 0 {
72
+		err = syscall.Errno(r0)
73
+	}
74
+	return
75
+}
76
+
77
+var temp unsafe.Pointer
78
+
79
+// use ensures a variable is kept alive without the GC freeing while still needed
80
+func use(p unsafe.Pointer) {
81
+	temp = p
82
+}