ふと思い立ってclone(2)をFFI gemを使って呼び出してみた。 コードはこんなかんじ。
require 'ffi' module LinuxClone extend FFI::Library ffi_lib 'libc.so.6' callback :f_c, [:void], :int attach_function :clone, [:f_c, :pointer, :int], :int attach_function :getpid, [], :int end stack = FFI::MemoryPointer.new(:char, 8096) stack_top = FFI::Pointer.new(stack.address + 8096) f = proc do puts LinuxClone.getpid return 0 end puts LinuxClone.clone(f, stack_top, 0x20000000)
$ ruby -v ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux] $ sudo strace ruby clone.rb 2>&1 > /dev/null | grep clone execve("/usr/local/bin/ruby", ["ruby", "clone.rb"], [/* 18 vars */]) = 0 clone(child_stack=0x7f3e0220afb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f3e0220b9d0, tls=0x7f3e0220b700, child_tidptr=0x7f3e0220b9d0) = 17068 open("clone.rb", O_RDONLY|O_CLOEXEC) = 7 lstat("/home/username/dev/kubo39/utils/clone.rb", {st_mode=S_IFREG|0664, st_size=401, ...}) = 0 clone(child_stack=0x7f3e001c1fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f3e001c29d0, tls=0x7f3e001c2700, child_tidptr=0x7f3e001c29d0) = 17069 clone(child_stack=0x7f3e0400bac0, flags=CLONE_NEWPID) = 17070 ^C
ちゃんとclone(2)を呼び出せているが、SIGINTを送らないと終了しなかった(straceなしならexit status: 0で終了する)。 ちょっと調べてもよくわからなかったので断念。
それと、このプログラムはgetpidがまれに表示できない。原因は単に親が先に死ぬため。
$ for n in {0..9} > do > sudo ruby clone.rb > done clone(2) retval= 2827 getpid: 1 clone(2) retval= 2833 getpid: 1 clone(2) retval= 2838 getpid: 1 clone(2) retval= 2843 clone(2) retval= 2848 getpid: 1 clone(2) retval= 2853 getpid: 1 clone(2) retval= 2858 getpid: 1 clone(2) retval= 2863 getpid: 1 clone(2) retval= 2868 getpid: 1 clone(2) retval= 2873