[comp.sys.atari.st] Process control functions for dLibs

daemon@stag.UUCP (11/02/87)

    I'm working on putting process control routines into dLibs and would
like the opinions of those on the net about the merits of various approachs
to their implmentation.

    For background information, the way Un*x systems implment process control
is basically as follows.  Three functions, fork(), exec() and wait(), are
used.  The fork() function takes no argument and creates a duplicate of the
current process.  Now there are two process, the parent and the child.  The
fork() function returns 0 (zero) in the child, indicating that it is the
child process, and returns the process id of the child in the parent.  Now
you have two copies of the same program running concurrently.  Typically,
the child will then call exec() to load and execute a program.  There are
many variants of exec() that differ based on the form of the parameters, but
I'll simply use the name exec() to describe all of them.  The exec() function
loads a new program over the one currently in memory, thereby destroying the
original program, it never returns.  The old program BECOMES the new program.
There is no parent/child relationship thus it is not possible to "return" to
the old program.  When the new program terminates, the process (the child
of the process which did the fork() originally) puts a return value in the
process table and terminates.  The original parent process may, at any time
after the fork(), call wait().  The wait() function retrieves the return
value for the child after the child terminates.  If the child is still
running, the parent is suspended until the child terminates.  The wait()
function returns the process id of the child that terminated, since there
may be more than one child of a given parent.  These functions are very
often used to allow subroutine-like execution of another program from within
the parent.  In this case, the parent does a fork() followed by a wait(),
and the child does an exec() immediately after the fork, like this...

	if(fork() == 0)
		execlp("more", "read.me", NULL);
	else
		wait(&return_value);

    Under TOS, it is possible to do something like the above code fragment
by using the Pexec() gemdos trap, and that is sufficient for most process
control applications.  However, there are time when it would be nice to be
able to execute concurrent children (assuming you're running under a multi-
tasker) and it would be nice to have C library functions for process control
which worked like their Un*x counterparts.  So far, I've found no practical
way to implement a true fork() function under TOS, so there's an inherent
problem with implementing fork()/exec()/wait() "properly".  With the help
of some local developers, I've arrived at two plausible ways to implement
a useful set of process control functions to include in dLibs and I'd like
your input on which you'd prefer to use and why.

    Method #1:  Stress emulation of Un*x entry points.  The fork() call
saves contextual information and does a setjmp(), then pushes a copy of
it's return address on the stack (to allow it to return a second time) and
returns 0 indicating that you are the child process.  At this point there
are NOT* two processes, and you MUST NOT change data because your data
space is not separate from your parent's.  The exec() call starts up a
process (concurrent if possible) to execute the new program and does a
longjmp() back into fork().  The fork() function, on re-entry through the
longjmp(), returns again, but this time with the process id of the child,
indicating that you are the parent (still with me so far?).  The wait()
call retrieves the return value of the child, if it has terminated already
(which will always be the case for non-concurrent exec() calls), or waits
for a child to terminate.  This method is contorted to give a look-alike
interface, but it only works for "typical" applications.

    Method #2:  Stress usefulness and simplicity.  There is no fork() call,
since it's not possible to fork() properly under TOS.  The exec() call
combines the functions of the Un*x fork()/exec() combination.  A process id
is returned to the parent by exec() and the child executes concurrently if
possible.  The wait() call retrieves the return value of the child, if it
has terminated already (which will always be the case for non-concurrent
exec() calls), or waits for a child to terminate.  This method may cause
some confusion in porting Un*x applications, since the functions don't work
like they do under Un*x, but it also naturally constrains the programmer to
applications which will work as expected and greatly simplfies the calls.

    There you have it.  I hope you can make sense of my explainations and
can give me a well-thought-out response.  I want this implmentation to be
of greatest use to the greatest number of people, so I need your feedback.

                Dale Schumacher
                ..ihnp4!meccts!stag!syntel!dal
                (alias: Dalnefre')

ftw@datacube.UUCP (11/05/87)

I would vote for method two.  Since TOS can't multitask, it seems a little
dangerous to create a fork() function that doesn't quite work the way
one might "expect" it to.  I'd rather have method number two, which
is like vfork()/exec().


				Farrell T. Woods 

Datacube Inc. Systems / Software Group	4 Dearborn Rd. Peabody, Ma 01960
VOICE:	617-535-6644;	FAX: (617) 535-5643;  TWX: (710) 347-0125
INTERNET: ftw@datacube.COM
UUCP: {rutgers, ihnp4, mirror}!datacube!ftw