python中的克隆进程支持

python中的克隆进程支持,python,Python,Python中是否支持系统调用(而不是os.fork)?我想在Python下使用Linux名称空间,但似乎没有太多关于它的信息 编辑: 我认为使用libc的ctypes是答案,但我仍然没有取得任何成功。fork可以正常工作,因为它没有任何参数,所以下面的代码可以工作: from ctypes import * libc = CDLL("libc.so.6") libc.fork() 使用clone,我正在尝试以下操作: from ctypes import * def f(): p

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

编辑:

我认为使用libc的ctypes是答案,但我仍然没有取得任何成功。fork可以正常工作,因为它没有任何参数,所以下面的代码可以工作:

from ctypes import *

libc = CDLL("libc.so.6")
libc.fork()
使用clone,我正在尝试以下操作:

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克隆(int(*fn)(void*),void*子堆栈, 整型标志,无效参数。。。 /pid_t*ptid、结构用户_desc*tls、pid_t*ctid*/)

我仍然需要传递*child_堆栈和标志,但不知道如何做。有什么帮助吗

更多编辑:

我现在明白了:

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


在这篇文章之后,堆栈似乎很好:

嗯,最后我想我得到了答案,就是使用libc

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

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用户运行。

如果您希望具有“fork()但具有新名称空间”语义,可以直接调用
SYS\u clone
syscall。请注意,如果这样做,则
os.getpid()
方法将在子进程中返回错误的进程ID,因为glibc缓存进程ID,并且不知道调用
SYS\u clone
使其缓存无效


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

如果您只使用
clone\u NEWPID
标志(
0x000200000
),子进程将立即重新租给父进程的init,因此父进程将无法等待子进程。如果要在父进程中等待子进程,可能需要使用
signal.SIGCHLD | 0x000200000
。(您必须指定一些信号,
SIGCHLD
是明显的候选者。)“从glibc 2.3.4版到2.24版,用于getpid()缓存PID的glibc包装函数,……自glibc 2.25版以来,PID缓存被删除:对getpid()的调用总是调用实际的系统调用,而不是返回缓存值。”()