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>
