2012-11-14 12 views
8

Czy istnieje wsparcie dla syscall clone(2) (nieos.fork) w języku Python? Chcę grać z przestrzeniami nazw Linux w Pythonie, ale wydaje się, że nie ma na ten temat zbyt wiele informacji.Obsługa procesu klonowania w pythonie

Edits:

myślę ctypes z libc jest odpowiedź, ale ja wciąż nie mają żadnych sukcesów. widelec działa bez problemów, ponieważ nie ma żadnego argumentu, potem tę pracę kodu:

from ctypes import * 

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

Z klonu próbuję to:

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

Clone rzeczywiście ma ten podpis:

int clone (int (* fn) (void *), void * child_stack, int flags, void arg, ... / pid_t * ptid, struct user_desc * tls, pid_t * ctid * /);

Nadal muszę przekazać * child_stack i flagi, ale nie mam pojęcia, jak to zrobić. Jakaś pomoc?

Więcej Edits:

mam to teraz:

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) 

To faktycznie działa, ale mogę sobie wyobrazić, że czyniąc dziurę w moim systemie ze stosu, jest bardziej przejrzysty sposób to zrobić?

Edits:

Prawie gotowe, dodając odpowiednią flagę 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) 

To nie jest runnable tylko dla korzenia i wydrukować piękny 1.

I po to opublikować stos wydaje się być w porządku: http://code.google.com/p/chromium/wiki/LinuxPidNamespaceSupport

+2

Jeśli użyjesz tylko flagi 'CLONE_NEWPID' (' 0x000200000'), proces potomny zostanie natychmiast ponownie nadany do procesu nadrzędnego procesu, więc proces nadrzędny nie będzie w stanie czekać na potomka. Prawdopodobnie chcesz użyć 'signal.SIGCHLD | 0x000200000', jeśli chcesz poczekać na proces potomny w procesie nadrzędnym. (Musisz podać sygnał, a "SIGCHLD" jest oczywistym kandydatem.) – mkj

Odpowiedz

6

Cóż, w końcu myślę, że dostałem odpowiedź, jest po prostu usign ctypes z libc,

Jest to prosty dowód pojęcia:

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) 

To musi być prowadzony przez korzeń.

0

Jeśli chcesz mieć semantykę "fork(), ale z nową przestrzenią nazw", możesz zamiast tego bezpośrednio wywołać syscall SYS_clone. Zauważ, że w takim przypadku metoda os.getpid() zwróci nieprawidłowy identyfikator procesu w elemencie podrzędnym, ponieważ glibc buforuje identyfikator procesu i nie wie o wywołaniu SYS_clone, aby unieważnić jego pamięć podręczną.

Zakładając x86_64 (NR_clone == 56, NR_getpid == 39), można wywołać libc.syscall(56, signal.SIGCHLD|0x000200000, 0 0 0) do „widelec”, a następnie libc.syscall(39) aby uzyskać aktualny PID z „rozwidloną” procesu potomnego.