Goで作ったプログラムでシグナルを受け取る


## シグナルを受ける
Goで作ったプログラム実行中にシグナルを受け取れるか試してみる。
これができれば、リモートからの通信や、他のイベントを1つのselectで一気に待機できるかも。
signal.Notify()というメソッドが用意されているので、これで試してみる。

godocを見ると、1つめの引数のチャネルに、登録したいシグナルを指定していくみたい。

```go
// Notify causes package signal to relay incoming signals to c.
// If no signals are provided, all incoming signals will be relayed to c.
// Otherwise, just the provided signals will.
//
// Package signal will not block sending to c: the caller must ensure
// that c has sufficient buffer space to keep up with the expected
// signal rate.  For a channel used for notification of just one signal value,
// a buffer of size 1 is sufficient.
//
// It is allowed to call Notify multiple times with the same channel:
// each call expands the set of signals sent to that channel.
// The only way to remove signals from the set is to call Stop.
//
// It is allowed to call Notify multiple times with different channels
// and the same signals: each channel receives copies of incoming
// signals independently.
func Notify(c chan<- os.Signal, sig ...os.Signal) {
```

しかし、シグナルはどうやって指定するのか、、、、１とか2とかで選ぶのかな？
SIGTERMでGoの中をgrepすると、それっぽいファイルを発見。

>./syscall/zerrors_darwin_amd64.go

当方マカーなのでdarwinがついているけど、windowsもあるみたい。
中をのぞいてみると、それっぽい。


```go
// Signals
const (
	SIGABRT   = Signal(0x6)
	SIGALRM   = Signal(0xe)
	SIGBUS    = Signal(0xa)
	SIGCHLD   = Signal(0x14)
	SIGCONT   = Signal(0x13)
	SIGEMT    = Signal(0x7)
	SIGFPE    = Signal(0x8)
	SIGHUP    = Signal(0x1)
	SIGILL    = Signal(0x4)
	SIGINFO   = Signal(0x1d)
	SIGINT    = Signal(0x2)
	SIGIO     = Signal(0x17)
	SIGIOT    = Signal(0x6)
	SIGKILL   = Signal(0x9)
	SIGPIPE   = Signal(0xd)
	SIGPROF   = Signal(0x1b)
	SIGQUIT   = Signal(0x3)
	SIGSEGV   = Signal(0xb)
	SIGSTOP   = Signal(0x11)
	SIGSYS    = Signal(0xc)
	SIGTERM   = Signal(0xf)
	SIGTRAP   = Signal(0x5)
	SIGTSTP   = Signal(0x12)
	SIGTTIN   = Signal(0x15)
	SIGTTOU   = Signal(0x16)
	SIGURG    = Signal(0x10)
	SIGUSR1   = Signal(0x1e)
	SIGUSR2   = Signal(0x1f)
	SIGVTALRM = Signal(0x1a)
	SIGWINCH  = Signal(0x1c)
	SIGXCPU   = Signal(0x18)
	SIGXFSZ   = Signal(0x19)
)
```

とりあえずこれでやってみる。

```go
package main

import (
	"fmt"
	"os"
	"syscall"

	"os/signal"
)

func main() {
	signalCh := make(chan os.Signal)
	// SIGHUPとSIGTERMとSIGKILLに対応する
	signal.Notify(signalCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL)

	for {

		select {
		case ch := <-signalCh:
			catchSig(ch)
		}
	}
}

func catchSig(sig os.Signal) {
	switch sig {
	case syscall.SIGHUP:
		fmt.Println("SIGHUP Happend! ", sig)
	case syscall.SIGTERM:
		fmt.Println("SIGTERM Happend! ", sig)
	case syscall.SIGKILL:
		fmt.Println("SIGKILL Happend! ", sig)
	default:
		fmt.Println("Other singal Happend! ", sig)
	}
}
```

これで動かすと。。。

> $./samples &
[2] 34210
$ 
$ kill 34210
SIGTERM Happend!  terminated
$ kill -1 34210
SIGHUP Happend!  hangup
$ kill -9 34212
[2]+  Killed: 9               ./samples

さすがにSIGKILLは受け取れなかったけど、狙い通り。
一応未登録のシグナルも、発行してみる。

>$ ./samples &
[2] 34226
$ kill -30 34226

やはり何も起こらない。SIGINTも発行する。

>$ kill -2 34226
[2]+  Exit 2                  ./samples

プログラムは何も受け取らないが、標準動作で終了する。
予期しないシグナルを防ぐには、何もしないように防ぐための登録が必要かも。

## Windowsだとどうなる？
Windows版にも、ztypes_windows.goがあって、そこに定義があった。

```go
const (
	// More invented values for signals
	SIGHUP  = Signal(0x1)
	SIGINT  = Signal(0x2)
	SIGQUIT = Signal(0x3)
	SIGILL  = Signal(0x4)
	SIGTRAP = Signal(0x5)
	SIGABRT = Signal(0x6)
	SIGBUS  = Signal(0x7)
	SIGFPE  = Signal(0x8)
	SIGKILL = Signal(0x9)
	SIGSEGV = Signal(0xb)
	SIGPIPE = Signal(0xd)
	SIGALRM = Signal(0xe)
	SIGTERM = Signal(0xf)
)
```
ここにあるシグナルは、受け取れるってことなのかな？
今度試してみよう。