English Amiga Board


Go Back   English Amiga Board > Coders > Coders. General

 
 
Thread Tools
Old 29 November 2011, 05:58   #1
tygre
Returning fan!
 
tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 1,442
Amiga, vfork(), and pipe()

Dear all!

In my endless quest to use my Amiga as a Web server, I am analysing the source code of THTTPd to adapt it to AmigaOS. THTTPd uses fork() to spawn a new process when a CGI script is called.

The function fork() does not exist in AmigaOS (at least 3.1, m68k), so it must be replaced and vfork() seems like a good idea but for the fact that it spawns a process that run in parallel to the parent process only if execve() is called.

This behaviour is fine except that, before calling execve(), THTTPd sets up a listener to listen to the output of the CGI script... which is spawned using vfork(), which prevent the call to execve()!

Any suggestions to solve this "deadlock" problem?

Cheers!
Tygre
tygre is offline  
Old 01 December 2011, 02:47   #2
tygre
Returning fan!
 
tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 1,442
PS. Digging in the Internet, I found out that ixemul.library provide replacement functions to vfork():
  • ix_vfork()
  • vfork_setup_child()
  • ix_vfork_resume()

Even better, I found an example of using these functions to "fork" a function call in binkd, a Binkley deamon - TCP/IP Fidonet mailer. Its executable is available in Aminet (v2.0). Its source code is available in launchpad.net (v0.9.9) .

Let's see if I can draw inspiration from binkd!
tygre is offline  
Old 01 December 2011, 03:09   #3
Kalms
Registered User
 
Join Date: Nov 2006
Location: Stockholm, Sweden
Posts: 237
Quoting a bit from ixemul manual:

"In some cases, such as a Unix shell (pdksh for example), you really want to
be able to port a program that uses a fork() that cannot be replaced with
vfork(). There is a way to do this, although it is a lot of work. First
of all, the program has to be compiled with -resident. Now you replace the
fork() by a ix_vfork() call, and in the child code you call vfork_setup_child()
(new for 44.0! Replaces the ix_resident()/ix_get_vars2() pair) to copy the
original data hunk to a new location. Next you have to copy all the
parent's data structures to the child. In other words, you have to copy
the complete state of the parent process to the child process. This can be
a lot of work. Finally, you call vfork_resume() which unblocks the parent
so that you now have two processes running separately from each other.

It is important to realize that you should never exit() from the parent
before all vfork()'ed children have died. Since exiting from the parent
causes the parents code and data segments to be deallocated, the child
would find itself without code space to run on, and would probably cause a
severe machine crash!

So always call at least `wait(0)' before returning from the parent."

Yeah, you might be able to do it via ix_vfork(). it's not 100% clear whether stdin/stout redirection will work as intended though.

You might have to bite the bullet and use the native AmigaOS function instead (CreateNewProc).
Kalms is offline  
Old 01 December 2011, 03:22   #4
tygre
Returning fan!
 
tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 1,442
@Kalms!

Yes, I read that , that's how I bumped into binkd. I also considered using CreateProc() and friends: would you know good source of information (especially books) about them?

Thanks!
tygre is offline  
Old 02 December 2011, 05:33   #5
tygre
Returning fan!
 
tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 1,442
Dear all!

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:

Code:
/*
 *  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 the function "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:

Code:
/usr/local/amiga/bin/m68k-amigaos-gcc.exe fork.c -o fork
Running the fork program in WinUAE typically outputs:

Code:
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!
I believe that this code is correct, please let me know if I overlooked something! Now, back to THTTPd...

Cheers!
Tygre

Last edited by tygre; 03 December 2011 at 02:12. Reason: Slightly improved the example code
tygre is offline  
Old 03 December 2011, 01:35   #6
Slayer
Amiga Member
 
Slayer's Avatar
 
Join Date: Aug 2003
Location: New Zealand
Age: 57
Posts: 695
I must remember this if I ever go back to compiling some of my mud codebases

My solution back in the day was simply to remove the sprawling task and I don't think I even did that cleanly LOL I'm a cut and paster not a coder... but I can compile, insert missing headers and insert the odd missing function...
Slayer is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Project: Blizzard 1230 IV - Heat Pipe Cooling System Yoto support.Hardware 45 17 December 2012 05:45
Pipe Dream (original) MethodGit request.Old Rare Games 3 16 December 2010 22:17
Pipe Mania - AGA-fixed/1-filed by Galahad MethodGit request.Old Rare Games 10 28 May 2009 01:34

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 21:00.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.08054 seconds with 13 queries