Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unix 如何在Go中以跨平台的方式按名称列出可用的操作系统信号?_Unix_Go_Signals_Cross Platform - Fatal编程技术网

Unix 如何在Go中以跨平台的方式按名称列出可用的操作系统信号?

Unix 如何在Go中以跨平台的方式按名称列出可用的操作系统信号?,unix,go,signals,cross-platform,Unix,Go,Signals,Cross Platform,假设我正在Go中实现kill程序。我可以从命令行接受数字信号和PID,并将它们发送到syscall.Kill没问题 但是,我不知道如何实现信号调度的“字符串”形式,例如kill-int12345 真正的用例是一个更大程序的一部分,该程序提示用户发送终止信号;不能代替kill 问题: 如何在任何受支持的平台上,在运行时将有效的信号名转换为信号号(或者至少在不编写编译时要运行的每个平台代码的情况下) 我所尝试的: 保持信号名称到数字的静态映射。这在跨平台的方式下不起作用(例如,MacOSX上的ki

假设我正在Go中实现
kill
程序。我可以从命令行接受数字信号和PID,并将它们发送到
syscall.Kill
没问题

但是,我不知道如何实现信号调度的“字符串”形式,例如
kill-int12345

真正的用例是一个更大程序的一部分,该程序提示用户发送终止信号;不能代替
kill

问题:

如何在任何受支持的平台上,在运行时将有效的信号名转换为信号号(或者至少在不编写编译时要运行的每个平台代码的情况下)

我所尝试的:

  • 保持信号名称到数字的静态映射。这在跨平台的方式下不起作用(例如,MacOSX上的
    kill-l
    返回的信号列表与现代Linux和旧Linux不同)。使此解决方案正常工作的唯一方法是为每个操作系统制作映射,这需要我了解每个操作系统的行为,并在它们添加新的信号支持时保持最新
  • 发送到GNU
    kill
    工具并从中捕获信号列表。这是不雅观的,有点自相矛盾,还需要a)能够找到
    kill
    ,b)具有执行子流程的能力/权限,以及c)能够预测/解析
    kill
    -二进制文件的输出
  • 使用各种
    信号
    类型的
    字符串
    方法。这只返回包含信号编号的字符串,例如,
    os.signal(4).String()==“signal 4”
    ,这是不有用的
  • 调用private函数,这正是我想要的
    go://linkname
    hacks会奏效,但我认为这种事情是不受欢迎的
我没有尝试过的想法/事情:

  • 以某种方式使用CGo。我不想冒险进入CGO领域进行一个项目,否则该项目根本就不需要本地集成。如果那是唯一的选择,我会的,但不知道从哪里开始
  • 使用模板和代码生成在编译时基于外部源构建信号列表。出于与CGo相同的原因,这并不可取
  • 反映并解析以
    SIG
    开头的
    syscall
    成员。有人告诉我,这是不可能的,因为名字都被编辑掉了;有没有可能,对于像信号名这样基本的东西,有一个地方它们没有被编译掉

由于没有发布任何答案,我将通过“闯入”Go标准库中的私有信号枚举函数,发布一个不太理想的解决方案

在Unix和Windows上,内部函数可以通过数字获取信号名称。要调用它,您必须使用。基本上,在项目中创建一个名为
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