Forking processes / 2012-01-11 16:06:43

Thanks to binkd and other sources on the Internet, I think that I was able to correctly use the ixemul.library to "fork" processes . Here is a code snippet:

/*
 *  fork.c -- An example of using ixemul.library pseudo-forking function
 *
 *  Copyright (c) 2011 Tygre (yann-gael@gueheneuc.net)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
    
#include  <errno.h>
#include  <stdio.h>
#include  <ix.h>

#define   MAX_COUNT  5
#define   BUF_SIZE   100


/* 
 * The function that will be called by two separate processes.
 * It just prints out MAX_COUNT times a counter while sleeping
 * in between each print to show the "forking". 
 */
static void forked_print(char *id) 
{
    pid_t   pid = getpid();
    int     i;
    char    buf[BUF_SIZE];

    srand(time(NULL));

    sprintf(buf, "%s pid is %d\n", id, pid);
    write(1, buf, strlen(buf));

    for (i = 1; i <= MAX_COUNT; i++) {
        sprintf(buf, "%s, with pid %d, value = %d\n", id, pid, i);
        write(1, buf, strlen(buf));
        sleep(rand() % 4);
    } 
    sprintf(buf, "%s, with pid %d, just quitted!\n", id, pid);
    write(1, buf, strlen(buf));
}



/*
 * This function does the "magic" of "forking" the main process.
 * It is heavily inspired by the function "branch" available in
 * the 0.9.9 release of "binkd" in the file "branch.c".
 * Below is the copying permission statement from "branch.c":
 *
 *  branch.c -- Create co-processes
 *
 *  branch.c is a part of binkd project
 *
 *  Copyright (C) 1996-1998  Dima Maloff, 5047/13
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version. See COPYING.
 */
static int branch(
    register void (*F) (void *),
    register void *arg,
    register size_t size)
{
    char            buf[BUF_SIZE];
    register int    rc;
    static char    *tmp;
    
    /* 
     * We print out some information regarding the "arg" and its "size".
     */
    sprintf(buf, "Before ix_vfork, arg: %d, size: %d\n", arg, size);
    write(1, buf, strlen(buf));

    if(!(rc = ix_vfork()))
    {
        vfork_setup_child();    

        /* 
         * We make our own copy of arg for the child as the parent 
         * may destroy it before the child finish to use it. 
         */
        if(size > 0)
        {
            if((tmp = malloc(size)) == NULL)
            {
                perror("Malloc failed");
                return -1;
            }
            else
            {
                memcpy(tmp, arg, size);
            }
        }
        else
        {
            tmp = 0;
        }
    
        /* 
         * We print out some information regarding the "arg" and its copy,
         * "tmp". It is important to note that the pointer value for "arg" 
         * did not change after the "forking" because it is not a true 
         * "forking" but rather the creation of a thread. 
         * See http://binkd.sourcearchive.com/documentation/
         *     0.9.9plus-p20060809-1/branch_8c-source.html
         */
        sprintf(buf, "Before ix_vfork, arg: %d, tmp: %d\n", arg, tmp);
        write(1, buf, strlen(buf));

        ix_vfork_resume();
        F(tmp);
        free(tmp);
        _exit(0);
    }
    else if (rc < 0)
    {
        sprintf(buf, "ix_vfork: %s\n", strerror(errno));
        write(1, buf, strlen(buf));
    }
    
    return rc;
}



int main(void)
{
    char id[2];

    /*
     * We "fork" the function "forked_print", using "C" to denote the child.
     */
    sprintf(id, "C");
    if(branch((void *) forked_print, (void *) id, sizeof(id)) < 0)
    {
        perror("Cannot branch!");
    }
    else 
    {
        /*
         * We call "forked_print" in the parent process, using "P".
         */
        sprintf(id, "P");
        sleep(3);
        forked_print(id);
    }
    exit(0);
}

 

To (cross-)compile this code (for example in CygWin), just call:

/usr/local/amiga/bin/m68k-amigaos-gcc.exe fork.c -o fork 

 

Running the fork program in WinUAE typically outputs:

Before ix_vfork, arg: ...10, size: 2
Before ix_vfork, arg: ...10, tmp: ...28
C pid is ...60
C, with pid ...60, value = 1
C, with pid ...60, value = 2
C pid is ...36
P, with pid ...36, value = 1
C, with pid ...60, value = 3
P, with pid ...36, value = 2
C, with pid ...60, value = 4
P, with pid ...36, value = 3
P, with pid ...36, value = 4
C, with pid ...60, value = 5
P, with pid ...36, value = 5
P, with pid ...36, just quitted!
C, with pid ...60, just quitted!