From owner-freebsd-current Sun Mar 21 0:48:27 1999 Delivered-To: freebsd-current@freebsd.org Received: from apollo.backplane.com (apollo.backplane.com [209.157.86.2]) by hub.freebsd.org (Postfix) with ESMTP id 4C65E150EB; Sun, 21 Mar 1999 00:48:26 -0800 (PST) (envelope-from dillon@apollo.backplane.com) Received: (from dillon@localhost) by apollo.backplane.com (8.9.3/8.9.1) id AAA09712; Sun, 21 Mar 1999 00:48:07 -0800 (PST) (envelope-from dillon) Date: Sun, 21 Mar 1999 00:48:07 -0800 (PST) From: Matthew Dillon Message-Id: <199903210848.AAA09712@apollo.backplane.com> To: Brian Feldman , Alfred Perlstein , "John S. Dyson" , samit@usa.ltindia.com, commiters@FreeBSD.ORG, freebsd-current@FreeBSD.ORG Subject: Re: rfork() References: <199903210743.XAA09505@apollo.backplane.com> Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG This is an example only. It takes a *BUNCH* of arcane assembly to make it work. I would suggest *EXTREME* caution when using a completely cloned address space such as RFPROC|RFMEM generate. Normal library calls cannot be made by the child safely. Thread libraries will also not work since they expect the pthread model. This is not portable. The assembly is designed for ELF libraries. -Matt /* * FTEST.C */ #include #include #include #include void fubar(void *data); int main(int ac, char **av) { pid_t pid; int stackSize = 64 * 1024; char *stack = malloc(stackSize); volatile int v = 0; printf("parent pid %d\n", (int)getpid()); fflush(stdout); pid = ffork(fubar, &v, stack, stackSize); printf("child pid returned to parent %d\n", pid); /* * If stack is not split, then child should be able to * increment v. */ for (;;) { sleep(1); printf("%d\n", v); } exit(1); } void fubar(void *data) { int *pdata = data; for (;;) ++*pdata; _exit(0); } /* * FFORK.S */ .globl ffork .text /* * ffork(func, data, stack, stackSize) */ ffork: /* * Setup stack frame for new stack and store in register * which will not be destroyed by call to rfork, %ebx. * * newsp -> func * data */ pushl %ebx movl 12+4(%esp),%ebx addl 16+4(%esp),%ebx subl $16,%ebx /* newsp = %ebx = stack + stackSize - 16 */ movl 4+4(%esp),%eax movl %eax,0(%ebx) /* func */ movl 8+4(%esp),%eax movl %eax,4(%ebx) /* data */ /* * Call rfork() syscall. This is arcane I'm afraid because we cannot * use a 'call' due to possible stack reuse by one or the other * process. Instead we do a direct syscall. * * %edx is returned non-zero to the child, zero to the parent. %eax * is returned as the child pid to the parent, and garbage to the * child. */ pushl $48 /* RFPROC|RFMEM */ pushl $0 /* dummy */ movl $0xfb,%eax /* rfork syscall number */ int $0x80 /* syscall */ cmpl $0,%edx /* edx returns 0 to parent, pid in %eax */ jne child /* * parent returns pid of child in %eax ( returned by syscall ), and * controls original stack. */ addl $8,%esp /* scrap syscall args */ popl %ebx /* pop saved registers */ ret /* return to parent */ /* * child must run function in new stack frame without messing with * old stack frame ( which might already be popped and reused by the * parent ) */ child: movl %ebx,%esp /* switch stacks */ movl %esp,%ebp /* setup new frame pointer */ popl %eax /* pop function address */ call *%eax /* call function */ jmp __exit /* system exit on return*/ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message