unix: add SignalNum to convert signal name to a number

Fixes golang/go#28027

Change-Id: Idf8b554e0fd102fd8b2f2f2ea0fa47bf139303da
Reviewed-on: https://go-review.googlesource.com/c/164778
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/syscall_unix.go b/unix/syscall_unix.go
index 33583a2..0f07d29 100644
--- a/unix/syscall_unix.go
+++ b/unix/syscall_unix.go
@@ -28,6 +28,11 @@
 	errENOENT error = syscall.ENOENT
 )
 
+var (
+	signalNameMapOnce sync.Once
+	signalNameMap     map[string]syscall.Signal
+)
+
 // errnoErr returns common boxed Errno values, to prevent
 // allocations at runtime.
 func errnoErr(e syscall.Errno) error {
@@ -66,6 +71,19 @@
 	return ""
 }
 
+// SignalNum returns the syscall.Signal for signal named s,
+// or 0 if a signal with such name is not found.
+// The signal name should start with "SIG".
+func SignalNum(s string) syscall.Signal {
+	signalNameMapOnce.Do(func() {
+		signalNameMap = make(map[string]syscall.Signal)
+		for _, signal := range signalList {
+			signalNameMap[signal.name] = signal.num
+		}
+	})
+	return signalNameMap[s]
+}
+
 // clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
 func clen(n []byte) int {
 	i := bytes.IndexByte(n, 0)
diff --git a/unix/syscall_unix_test.go b/unix/syscall_unix_test.go
index f6abe8c..264305f 100644
--- a/unix/syscall_unix_test.go
+++ b/unix/syscall_unix_test.go
@@ -98,6 +98,27 @@
 	}
 }
 
+func TestSignalNum(t *testing.T) {
+	testSignals := []struct {
+		name string
+		want syscall.Signal
+	}{
+		{"SIGHUP", syscall.SIGHUP},
+		{"SIGPIPE", syscall.SIGPIPE},
+		{"SIGSEGV", syscall.SIGSEGV},
+		{"NONEXISTS", 0},
+	}
+	for _, ts := range testSignals {
+		t.Run(fmt.Sprintf("%s/%d", ts.name, ts.want), func(t *testing.T) {
+			got := unix.SignalNum(ts.name)
+			if got != ts.want {
+				t.Errorf("SignalNum(%s) returned %d, want %d", ts.name, got, ts.want)
+			}
+		})
+
+	}
+}
+
 func TestFcntlInt(t *testing.T) {
 	t.Parallel()
 	file, err := ioutil.TempFile("", "TestFnctlInt")