Date: Sun, 21 Mar 1999 00:48:07 -0800 (PST) From: Matthew Dillon <dillon@apollo.backplane.com> To: Brian Feldman <green@unixhelp.org>, Alfred Perlstein <bright@rush.net>, "John S. Dyson" <dyson@iquest.net>, samit@usa.ltindia.com, commiters@FreeBSD.ORG, freebsd-current@FreeBSD.ORG Subject: Re: rfork() Message-ID: <199903210848.AAA09712@apollo.backplane.com> References: <Pine.BSF.4.05.9903210528300.97734-100000@zone.syracuse.net> <199903210743.XAA09505@apollo.backplane.com>
next in thread | previous in thread | raw e-mail | index | archive | help
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 <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> 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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199903210848.AAA09712>