async def _setup_stub( thread: Thread, bootstrap_sock: FileDescriptor, ) -> t.Tuple[t.List[str], Thread]: "Setup a stub thread" [(access_syscall_sock, passed_syscall_sock), (access_data_sock, passed_data_sock) ] = await thread.open_async_channels(2) # memfd for setting up the futex futex_memfd = await thread.task.memfd_create(await thread.ram.ptr( Path("child_robust_futex_list"))) # send the fds to the new process connection_fd, make_connection = await thread.connection.prep_fd_transfer() async def sendmsg_op(sem: RAM) -> WrittenPointer[SendMsghdr]: iovec = await sem.ptr(IovecList([await sem.malloc(bytes, 1)])) cmsgs = await sem.ptr( CmsgList([ CmsgSCMRights([ passed_syscall_sock, passed_data_sock, futex_memfd, connection_fd ]) ])) return await sem.ptr(SendMsghdr(None, iovec, cmsgs)) _, [] = await bootstrap_sock.sendmsg( await thread.ram.perform_batch(sendmsg_op), SendmsgFlags.NONE) # close our reference to fds that only the new process needs await passed_syscall_sock.invalidate() await passed_data_sock.invalidate() # close the socketpair await bootstrap_sock.invalidate() #### read describe to get all the information we need from the new process describe_buf = AsyncReadBuffer(access_data_sock) describe_struct = await describe_buf.read_cffi('struct rsyscall_unix_stub') argv_raw = await describe_buf.read_length_prefixed_array( describe_struct.argc) argv = [os.fsdecode(arg) for arg in argv_raw] environ = await describe_buf.read_envp(describe_struct.envp_count) #### build the new task pid = describe_struct.pid fd_table = handle.FDTable(pid) address_space = far.AddressSpace(pid) # we assume pid namespace is shared pidns = thread.task.pidns process = near.Process(pid) # we assume net namespace is shared - that's dubious... # we should make it possible to control the namespace sharing more, hmm. # TODO maybe the describe should contain the net namespace number? and we can store our own as well? # then we can automatically do it right base_task = Task(process, fd_table, address_space, pidns) remote_syscall_fd = base_task.make_fd_handle( near.FileDescriptor(describe_struct.syscall_fd)) base_task.sysif = SyscallConnection( logger.getChild(str(process)), access_syscall_sock, access_syscall_sock, remote_syscall_fd, remote_syscall_fd, ) allocator = memory.AllocatorClient.make_allocator(base_task) base_task.sigmask = Sigset( {SIG(bit) for bit in rsyscall.struct.bits(describe_struct.sigmask)}) ram = RAM( base_task, SocketMemoryTransport( access_data_sock, base_task.make_fd_handle( near.FileDescriptor(describe_struct.data_fd))), allocator) # TODO I think I can maybe elide creating this epollcenter and instead inherit it or share it, maybe? # I guess I need to write out the set too in describe epoller = await Epoller.make_root(ram, base_task) child_monitor = await ChildProcessMonitor.make(ram, base_task, epoller) connection = make_connection( base_task, ram, base_task.make_fd_handle( near.FileDescriptor(describe_struct.connecting_fd))) new_thread = Thread( task=base_task, ram=ram, connection=connection, loader=NativeLoader.make_from_symbols(base_task, describe_struct.symbols), epoller=epoller, child_monitor=child_monitor, environ=Environment.make_from_environ(base_task, ram, environ), stdin=base_task.make_fd_handle(near.FileDescriptor(0)), stdout=base_task.make_fd_handle(near.FileDescriptor(1)), stderr=base_task.make_fd_handle(near.FileDescriptor(2)), ) #### TODO set up futex I guess remote_futex_memfd = near.FileDescriptor(describe_struct.futex_memfd) return argv, new_thread
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct signalfd_siginfo const*', ffi.from_buffer(data)) return cls(signo=SIG(struct.ssi_signo), )
def make(code: CLD, pid: int, uid: int, status: int) -> ChildState: if code is CLD.EXITED: return ChildState(code, pid, uid, status, None) else: return ChildState(code, pid, uid, None, SIG(status))