Skip site navigation (1)Skip section navigation (2)
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>