Unix 如何在Go中以跨平台的方式按名称列出可用的操作系统信号?
假设我正在Go中实现Unix 如何在Go中以跨平台的方式按名称列出可用的操作系统信号?,unix,go,signals,cross-platform,Unix,Go,Signals,Cross Platform,假设我正在Go中实现kill程序。我可以从命令行接受数字信号和PID,并将它们发送到syscall.Kill没问题 但是,我不知道如何实现信号调度的“字符串”形式,例如kill-int12345 真正的用例是一个更大程序的一部分,该程序提示用户发送终止信号;不能代替kill 问题: 如何在任何受支持的平台上,在运行时将有效的信号名转换为信号号(或者至少在不编写编译时要运行的每个平台代码的情况下) 我所尝试的: 保持信号名称到数字的静态映射。这在跨平台的方式下不起作用(例如,MacOSX上的ki
kill
程序。我可以从命令行接受数字信号和PID,并将它们发送到syscall.Kill
没问题
但是,我不知道如何实现信号调度的“字符串”形式,例如kill-int12345
真正的用例是一个更大程序的一部分,该程序提示用户发送终止信号;不能代替kill
问题:
如何在任何受支持的平台上,在运行时将有效的信号名转换为信号号(或者至少在不编写编译时要运行的每个平台代码的情况下)
我所尝试的:
- 保持信号名称到数字的静态映射。这在跨平台的方式下不起作用(例如,MacOSX上的
返回的信号列表与现代Linux和旧Linux不同)。使此解决方案正常工作的唯一方法是为每个操作系统制作映射,这需要我了解每个操作系统的行为,并在它们添加新的信号支持时保持最新kill-l
- 发送到GNU
工具并从中捕获信号列表。这是不雅观的,有点自相矛盾,还需要a)能够找到kill
,b)具有执行子流程的能力/权限,以及c)能够预测/解析kill
-二进制文件的输出kill
- 使用各种
类型的信号
方法。这只返回包含信号编号的字符串,例如,字符串
,这是不有用的os.signal(4).String()==“signal 4”
- 调用private函数,这正是我想要的
hacks会奏效,但我认为这种事情是不受欢迎的go://linkname
- 以某种方式使用CGo。我不想冒险进入CGO领域进行一个项目,否则该项目根本就不需要本地集成。如果那是唯一的选择,我会的,但不知道从哪里开始
- 使用模板和代码生成在编译时基于外部源构建信号列表。出于与CGo相同的原因,这并不可取
- 反映并解析以
开头的SIG
成员。有人告诉我,这是不可能的,因为名字都被编辑掉了;有没有可能,对于像信号名这样基本的东西,有一个地方它们没有被编译掉syscall
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认为操作系统没有信号的名称(我发现,一些Go信号的名称可能不会返回名称,但通常是编号较高/非标准的名称),或者一个字符串名称,例如可以找到名称的“INT”
此行为未经记录,可能会发生更改,在某些平台上可能不适用。不过,如果将其公开,那就太好了。Commit在2019年3月将此功能添加为sys/unix.SignalNum()
,因此至少从Go 1.13开始可用。更多细节请参见GitHub问题
从golang.org/x/sys/unix
包的
func SignalNum(s字符串)syscall.Signal
SignalNum为名为s的信号返回syscall.Signal,如果找不到具有此名称的信号,则返回0。信号名称应以“SIG”开头
要回答一个类似的问题,“如何列出所有可用信号的名称(在给定的类Unix平台上)”,我们可以使用反向函数sys/Unix.SignalName()
:
导入“golang.org/x/sys/unix”
//看https://github.com/golang/go/issues/28027#issuecomment-427377759
//了解为什么在0255范围内循环就足够了。
对于i:=syscall.Signal(0);i
是否可能调用strsignal
和/或使用sys\u siglist
array;我尝试了一下,但之前没有使用Cgo,所以它一直无法在我使用的go结构中存储输出值。我会继续戳它,如果我到了任何地方,我会把它贴在这里;你知道这方面的代码吗?在C中:for(inti=0;i