在Go中设置进程名称(由`ps`看到)

时间:2013-02-17 21:02:25

标签: linux process go

以下(理所当然地)不起作用:

package main

import (
        "os"
        "time"
)

func main() {
        os.Args[0] = "custom name"
        println("sleeping")
        time.Sleep(1000 * time.Second)
        println("done")
}

某些语言提供setting process name的此功能作为内置功能(例如,在Ruby中,它只是assigning to $0)或作为第三方图书馆(Python)。

我正在寻找一种至少适用于Linux的解决方案。

3 个答案:

答案 0 :(得分:11)

有多种方法可以实现这一点,其中许多方法仅适用于某些情况。我不建议这样做,因为(一方面)它可能导致你的进程在不同情况下显示不同的名称。它们需要使用系统调用和/或不安全,因此您故意破坏Go语言的安全性。那就是说,你的选择似乎是:

修改argv [0]

func SetProcessName(name string) error {
    argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
    argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len]

    n := copy(argv0, name)
    if n < len(argv0) {
            argv0[n] = 0
    }

    return nil
}

在Go中,您无权访问实际的argv数组本身(不调用内部运行时函数),因此您只能使用不超过当前进程名称长度的新名称。

这似乎主要适用于达尔文和Linux。

致电PR_SET_NAME

func SetProcessName(name string) error {
    bytes := append([]byte(name), 0)
    ptr := unsafe.Pointer(&bytes[0])
    if _, _, errno := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_NAME, uintptr(ptr), 0, 0, 0, 0); errno != 0 {
            return syscall.Errno(errno)
    }
    return nil
}

新名称最多可以是16个字节。

这对Darwin不起作用,并且在Linux上似乎没有太大作用,虽然它成功并且PR_GET_NAME之后报告了正确的名称。不过,这可能是我的Linux VM特有的。

答案 1 :(得分:4)

要在Linux上更改流程名称,您需要将prctl system callPR_SET_NAME选项结合使用。

目前,我认为你不能在Go代码中做到这一点。但是,您可以构建一个小C模块来执行此操作,然后将其集成到Go构建中。

答案 2 :(得分:0)

我不认为“流程标题”是一个定义明确的术语。无论如何,Ruby与Go有什么关系? documentation for os.Args没有提及任何“流程标题”,也没有说在分配切片项目时会发生任何魔法。后者实际上是Go的一般属性。结构字段,数组/切片项的变量没有神奇的getter / setter,所以一个简单的赋值只是分配而不再做任何事情而且不能做更多的事情。

简而言之,缺乏魔力是预期的正确行为。

为了通过'os'软件包摆弄可移植的进程属性,必须以特定于平台的方式使用软件包'syscall'。但是,构建约束(讨论here)可以帮助正确处理跨平台的内容。