【问题标题】:clone process support in pythonpython中的克隆进程支持
【发布时间】:2012-11-14 05:44:50
【问题描述】:

Python 中是否支持系统调用 clone(2)not os.fork)?我想在 Python 下使用 Linux 命名空间,但似乎没有太多关于它的信息。

编辑:

我认为带有 libc 的 ctypes 是答案,但我仍然没有任何成功。 fork 没有任何问题,因为它没有任何参数,那么这段代码就可以工作:

from ctypes import *

libc = CDLL("libc.so.6")
libc.fork()

使用克隆我正在尝试这个:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)

print libc.getpid()
print libc.clone(f_c)
print get_errno()

克隆实际上有这个签名:

int clone(int (*fn)(void *), void *child_stack, int 标志,无效 arg,... / pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

我仍然需要传递 *child_stack 和标志,但不知道该怎么做。有什么帮助吗?

更多编辑:

我现在明白了:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0)

这确实有效,但我想我用堆栈在我的系统中打了一个大洞,有更清洁的方法吗?

编辑:

几乎完成,为 newpid 添加正确的标志:

from ctypes import *

libc = CDLL("libc.so.6")

def f():
    print libc.getpid()
    return 0

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0x20000000)

这不能只为 root 运行,并打印一个不错的 1。

在这篇文章之后,堆栈似乎很好:http://code.google.com/p/chromium/wiki/LinuxPidNamespaceSupport

【问题讨论】:

  • 如果您只使用CLONE_NEWPID 标志(0x000200000),子进程将立即重新成为父进程的init,因此父进程将无法等待子进程.如果您想在父进程中等待子进程,您可能想要使用signal.SIGCHLD|0x000200000。 (你必须指定一些信号,SIGCHLD 是明显的候选者。)

标签: python


【解决方案1】:

好吧,我想我终于得到了答案,就是用 libc 签名 ctypes

这是一个简单的概念证明:

from ctypes import *

libc = CDLL("libc.so.6")

# Create stack.                                                                                                                                                                            
stack = c_char_p(" " * 8096)

def f():
    print libc.getpid()
    return 0

# Conver function to c type returning an integer.                                                                                                                                          
f_c = CFUNCTYPE(c_int)(f)

# We need the top of the stack.                                                                                                                                                            
stack_top = c_void_p(cast(stack, c_void_p).value + 8096)

# Call clone with the NEWPID Flag                                                                                                                                                          
libc.clone(f_c, stack_top, 0x20000000)

这必须由 root 运行。

【讨论】:

    【解决方案2】:

    如果你想要“fork() 但有新的命名空间”语义,你可以直接调用SYS_clone 系统调用。请注意,如果这样做,os.getpid() 方法将在子进程中返回错误的进程 ID,因为 glibc 缓存了进程 ID,并且不知道 SYS_clone 调用使其缓存无效。

    假设x86_64(NR_clone == 56,NR_getpid == 39),可以调用libc.syscall(56, signal.SIGCHLD|0x000200000, 0 0 0)“fork”,然后libc.syscall(39)获取“fork”子进程的当前PID。

    【讨论】:

    • "从 glibc 版本 2.3.4 到并包括版本 2.24,用于 getpid() 缓存 PID 的 glibc 包装函数,...从 glibc 版本 2.25 开始,PID 缓存被删除:调用 getpid () 总是调用实际的系统调用,而不是返回一个缓存的值。” (getpid(2))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 2021-06-26
    • 2016-05-02
    • 2022-01-10
    • 2016-05-31
    • 1970-01-01
    相关资源
    最近更新 更多