在Go中设置进程名称(如`ps`所示)

问题描述:

以下(正确)不起作用:

The following (rightfully) doesn't work:

package main

import (
        "os"
        "time"
)

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

有些语言提供设置进程名称作为内置功能(在Ruby中,例如,它只是指定给 $ 0 )或作为第三方库( Python )。

Some languages provide this feature of setting process name as a built-in functionality (in Ruby, for instance, it is only a matter of assigning to $0) or as a third-party library (Python).

我在寻找一个解决方案,至少在Linux上是有效的。

I'm looking for a solution that works, at least, on Linux.

有多种方法可以完成这,并且其中许多只在某些情况下工作。我不建议这样做,因为(有一点),它可能会导致您的流程在不同情况下显示不同的名称。他们需要使用系统调用和/或不安全,所以你故意颠覆Go语言的安全性。然而,这就是说,你的选择似乎是:

修改argv [0]



There are multiple ways to accomplish this, and many of them only work in certain situations. I don't really recommend doing it, as (for one thing) it can result in your process showing up with different names in different situations. They require using syscall and/or unsafe, and so you're deliberately subverting the safety of the Go language. That said, however, your options seem to be:

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数组本身(没有调用内部运行时函数),因此仅限于一个不超过长度的新名称当前进程名称。

In Go, you don't have access to the actual argv array itself (without calling internal runtime functions), so you are limited to a new name no longer than the length of the current process name.

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

This seems to mostly work on both Darwin and Linux.

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个字节。

The new name can be at most 16 bytes.

这在达尔文不起作用,似乎并不在Linux上做了很多工作,虽然它成功了,PR_GET_NAME之后也报告了正确的名称。虽然这可能是我的Linux VM特有的。

This doesn't work on Darwin, and doesn't seem to do much on Linux, though it succeeds and PR_GET_NAME reports the correct name afterward. This may be something peculiar about my Linux VM, though.