在Go中设置进程名称(在`ps`中可见)

huangapple go评论93阅读模式
英文:

Setting process name (as seen by `ps`) in Go

问题

以下是翻译好的部分:

以下(理所当然地)无法工作:

package main

import (
        "os"
        "time"
)

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

一些语言提供了设置进程名称的功能(例如,在Ruby中,只需要将值赋给$0),或者作为第三方库提供(Python)。

我正在寻找至少在Linux上工作的解决方案。

英文:

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")
}

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).

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

答案1

得分: 14

有多种方法可以实现这一点,其中许多方法只适用于特定情况。我不太建议这样做,因为它可能导致您的进程在不同情况下显示不同的名称。它们需要使用syscall和/或unsafe,因此您正在故意破坏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数组本身(除非调用内部运行时函数),因此您只能将新名称限制为不超过当前进程名称的长度。

这在Darwin和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虚拟机的特殊情况。

英文:

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:

Modify argv[0]

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

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

    return nil
}

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.

This seems to mostly work on both Darwin and Linux.

Call PR_SET_NAME

func SetProcessName(name string) error {
    bytes := append([]byte(name), 0)
    ptr := unsafe.Pointer(&amp;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
}

The new name can be at most 16 bytes.

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.

答案2

得分: 4

要在Linux上更改进程名称,您需要使用prctl系统调用与PR_SET_NAME选项相结合。

目前,我认为您无法在Go代码中实现此功能。但是,您可以构建一个小的C模块来完成此操作,然后将其集成到您的Go构建中。

英文:

To change a process name on Linux, you need to use the <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html">prctl system call</a> combined with the PR_SET_NAME option.

At the moment, I don't think you can do this in Go code. You can, however, build a small C module to do this and then integrate it into your Go build.

答案3

得分: -1

我不认为“进程标题”是一个明确定义的术语。无论如何,Ruby与Go有什么关系?os.Args的文档中没有提到任何“进程标题”,也没有说在分配给切片项时会发生任何魔法。后者实际上是Go的一个普遍特性。对于结构字段、数组/切片项的变量,没有魔法的getter/setter,所以简单的赋值只是简单地赋值,不会有其他操作,也不能有其他操作。

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

如果想要操作除了通过“os”包可移植访问的进程属性之外的其他属性,就必须以特定于平台的方式使用“syscall”包。但是,构建约束(在这里讨论:http://golang.org/pkg/go/build/)可以帮助正确处理跨平台的问题。

英文:

I don't think that "process title" is a well defined term. Anyway, what has Ruby to do with Go? The documentation for os.Args doesn't mention any "process title", nor it says any magic will happen on assigning to a slice item. The later is actually a general property of Go. There's no magic getters/setters for struct fields, variables of array/slice items, so a simple assignment simply assigns and does nothing more and cannot do anything more.

In short, the lack of magic is the expected, correct behavior.

For fiddling with process properties other than the portably accessible ones via the 'os' package, one has to use package 'syscall' in a platform specific way. But then the build constraints (discussed here) can help to correctly handle stuff across platforms.

huangapple
  • 本文由 发表于 2013年2月18日 05:02:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/14926020.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定