2017-03-04 19 views
1

假设我正在执行Go中的kill程序。我可以接受来自命令行的数字信号和PID,并将它们发送到syscall.Kill没有问题。如何在Go中以跨平台方式按名称列出可用的操作系统信号?

但是,我不知道如何实现信号分配的“字符串”形式,例如, kill -INT 12345

真实用例是一个较大程序的一部分,它提示用户发送杀死信号;不是kill的替代品。

问:

我如何转换有效信号名称的任何支持的平台上的数字信号,在运行时(或至少不按平台编写代码在编译时运行)?

我已经试过什么:

  • 保持信号名称的静态映射到数字。这不能以跨平台的方式工作(例如,不同的信号列表在Mac OSX上由kill -l返回,而现代Linux与旧版Linux比较)。使这个解决方案一般工作的唯一方法是为每个操作系统制作地图,这需要我了解每个操作系统的行为,并随时添加新的信号支持。
  • 将GNU kill工具封装出来并从中捕获信号列表。这是不雅观的,有点悖论,还需要a)能够找到kill,b)具有执行子进程的能力/权限,以及c)能够预测/解析kill-binary的输出。
  • 使用各种Signal类型的'String方法。这只是返回包含信号编号的字符串,例如os.Signal(4).String() == "signal 4",这是没有用的。
  • 调用私人功能runtime.signame,这正是我想要的。 go://linkname黑客会工作,但我认为这种事情是由于某种原因而皱起了眉头。

理念/事情我还没有尝试过:

  • 使用CGO莫名其妙。我宁愿不冒险进入CGO领域,因为这个项目本来就不是低层次/需要本地整合的项目。如果这是唯一的选择,我会,但不知道从哪里开始。
  • 使用模板和代码生成在编译时根据外部源生成信号列表。由于与CGo相同的原因,这不是可取的。
  • 反映并解析以SIG开头的syscall的成员。我被告知,这是不可能的,因为名字被编辑掉了;是否有可能,对于像信号名称这样重要的东西,有一些地方他们不是编译掉?
+0

难道不可能调用'strsignal'和/或使用'sys_siglist'数组吗? –

+0

潜在的;我给了它一个镜头,但之前没有使用过Cgo,所以它始终无法将输出值存储在我使用的go结构中。如果我到任何地方,我会一直捅它并贴在这里;你知道任何示例代码吗? –

+0

在C:'for(int i = 0; i

回答

0

由于没有发布任何答案,所以我会发布一个不太理想的解决方案,我可以通过在Go标准库中“闯入”一个私有信号枚举函数来使用它。

signame内部函数可以在Unix和Windows上通过数字获取信号名称。要调用它,你必须使用linkname/assembler workaround。基本上,使您的项目称为empty.s或类似的文件,没有任何内容,然后函数声明,如下所示:

//go:linkname signame runtime.signame 
func signame(sig uint32) string 

然后,您可以得到由操作系统已知的所有信号的列表,通过调用signame对越来越多,直到它没有返回值,就像这样:

signum := uint32(0) 
signalmap = make(map[uint32]string) 
for len(signame(signum)) > 0 { 
    words := strings.Fields(signame(signum)) 
    if words[0] == "signal" || ! strings.HasPrefix(words[0], "SIG") { 
     signalmap[signum] = "" 
    } else { 
     // Remove leading SIG and trailing colon. 
     signalmap[signum] = strings.TrimRight(words[0][3:], ":") 
    } 
    signum++ 
} 

运行后,signalmap将有可在当前操作系统上发送的每个信号键。它将有一个空字符串,Go认为操作系统没有信号名称(kill(1)可能会命名Go不会返回名称的一些信号,但我发现它通常是较高编号/非标准一个),或一个字符串名称,例如“INT”可以找到一个名字。

这种行为是无证,如有变更,并在某些平台上可能不成立。但是,如果这是公开的,这将是很好的。

相关问题