Browse code

Move signal handling code to pkg/signal.Trap

Signed-off-by: Solomon Hykes <solomon@docker.com>

Solomon Hykes authored on 2014/08/06 01:32:24
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+package signal
1
+
2
+import (
3
+	"log"
4
+	"os"
5
+	gosignal "os/signal"
6
+	"sync/atomic"
7
+	"syscall"
8
+)
9
+
10
+// Trap sets up a simplified signal "trap", appropriate for common
11
+// behavior expected from a vanilla unix command-line tool in general
12
+// (and the Docker engine in particular).
13
+//
14
+// * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated.
15
+// * If SIGINT or SIGTERM are repeated 3 times before cleanup is complete, then cleanup is
16
+// skipped and the process terminated directly.
17
+// * If "DEBUG" is set in the environment, SIGQUIT causes an exit without cleanup.
18
+//
19
+func Trap(cleanup func()) {
20
+	c := make(chan os.Signal, 1)
21
+	signals := []os.Signal{os.Interrupt, syscall.SIGTERM}
22
+	if os.Getenv("DEBUG") == "" {
23
+		signals = append(signals, syscall.SIGQUIT)
24
+	}
25
+	gosignal.Notify(c, signals...)
26
+	go func() {
27
+		interruptCount := uint32(0)
28
+		for sig := range c {
29
+			go func(sig os.Signal) {
30
+				log.Printf("Received signal '%v', starting shutdown of docker...\n", sig)
31
+				switch sig {
32
+				case os.Interrupt, syscall.SIGTERM:
33
+					// If the user really wants to interrupt, let him do so.
34
+					if atomic.LoadUint32(&interruptCount) < 3 {
35
+						atomic.AddUint32(&interruptCount, 1)
36
+						// Initiate the cleanup only once
37
+						if atomic.LoadUint32(&interruptCount) == 1 {
38
+							// Call cleanup handler
39
+							cleanup()
40
+						} else {
41
+							return
42
+						}
43
+					} else {
44
+						log.Printf("Force shutdown of docker, interrupting cleanup\n")
45
+					}
46
+				case syscall.SIGQUIT:
47
+				}
48
+				os.Exit(128 + int(sig.(syscall.Signal)))
49
+			}(sig)
50
+		}
51
+	}()
52
+}
... ...
@@ -6,15 +6,11 @@ package server
6 6
 
7 7
 import (
8 8
 	"fmt"
9
-	"log"
10
-	"os"
11
-	gosignal "os/signal"
12
-	"sync/atomic"
13
-	"syscall"
14 9
 
15 10
 	"github.com/docker/docker/daemon"
16 11
 	"github.com/docker/docker/daemonconfig"
17 12
 	"github.com/docker/docker/engine"
13
+	"github.com/docker/docker/pkg/signal"
18 14
 	"github.com/docker/docker/utils"
19 15
 )
20 16
 
... ...
@@ -50,38 +46,10 @@ func InitServer(job *engine.Job) engine.Status {
50 50
 		return job.Error(err)
51 51
 	}
52 52
 	job.Logf("Setting up signal traps")
53
-	c := make(chan os.Signal, 1)
54
-	signals := []os.Signal{os.Interrupt, syscall.SIGTERM}
55
-	if os.Getenv("DEBUG") == "" {
56
-		signals = append(signals, syscall.SIGQUIT)
57
-	}
58
-	gosignal.Notify(c, signals...)
59
-	go func() {
60
-		interruptCount := uint32(0)
61
-		for sig := range c {
62
-			go func(sig os.Signal) {
63
-				log.Printf("Received signal '%v', starting shutdown of docker...\n", sig)
64
-				switch sig {
65
-				case os.Interrupt, syscall.SIGTERM:
66
-					// If the user really wants to interrupt, let him do so.
67
-					if atomic.LoadUint32(&interruptCount) < 3 {
68
-						atomic.AddUint32(&interruptCount, 1)
69
-						// Initiate the cleanup only once
70
-						if atomic.LoadUint32(&interruptCount) == 1 {
71
-							utils.RemovePidFile(srv.daemon.Config().Pidfile)
72
-							srv.Close()
73
-						} else {
74
-							return
75
-						}
76
-					} else {
77
-						log.Printf("Force shutdown of docker, interrupting cleanup\n")
78
-					}
79
-				case syscall.SIGQUIT:
80
-				}
81
-				os.Exit(128 + int(sig.(syscall.Signal)))
82
-			}(sig)
83
-		}
84
-	}()
53
+	signal.Trap(func() {
54
+		utils.RemovePidFile(srv.daemon.Config().Pidfile)
55
+		srv.Close()
56
+	})
85 57
 	job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
86 58
 	job.Eng.Hack_SetGlobalVar("httpapi.daemon", srv.daemon)
87 59