[comp.sys.amiga.tech] Need a few pointers :-)

pcooper@LUKE.EECS.WSU.EDU (Phil Cooper - CS495) (11/24/90)

Fellow Amigans:

     I would like some advice/examples on how to set up several functions
in a source code file as independent processes (using ports and messages
for inter-process communications.)  My problem can be described as follows:

main()
{
   /* brilliant code inserted here...*/
}

func_1()
{
  
}

func_2()
{

}

  I would like to set up func_1 and func_2 to run as completely independent
processes.  Also, After they are set up, is anything needed to get them to
actually start executing?  I have a project now where the tasks are being
set up correctly (even show up with TaskX), but they seem to never actually
execute.  Any suggestions?

   Phil

markv@kuhub.cc.ukans.edu (11/27/90)

> Fellow Amigans:
> 
>      I would like some advice/examples on how to set up several functions
> in a source code file as independent processes (using ports and messages
> for inter-process communications.)  My problem can be described as follows:
>... 

I've done exactly this thing with *tasks*.  Using functions as *tasks*
is easy.  Using functions as processes is tricky.  If you are a task
the only restriction is you can't call DOS or do anything that calls
DOS.  This isn't too hard actually, as you can have the parent process
do such things for you.

Some things to keep in mind...  Exec/DOS maintain NO parent-child
information.  It is up to the program to make sure the children are
removed before the parent exits (ie: the tasks are delete with from
the system b/4 parent exits so Exex doesn't try to execute
non-existant code).

Two, there is no guarenteed synchronization.  The children need some
way of signalling the parent they are ready, and the parent needs some
way of signaling the children to die.  (Plus any other inter-task
communication).  You can use Signals, semaphores, messages, and in the
case of functions as tasks, shared global variables (if using base
relative the children must fetch the global base either with geta4()
or __saveds).

Try this crude example  (I may be off in parameter order on some
functions, but it should be obvious which parameter is what).  I use
CreateTask() out of amiga.lib.

/*
** handy macro...
*/

#define BIT(x)	(1L << x)

/*
** Child to parent signals.
*/

BYTE	C1Sig, C2Sig;
BYTE	DieFlag;
TASK	*C1, *C2, *Main;

main()
{
  ULONG  WaitRet;

  /* CreateTask() takes the start address of the code, the stack size,
  ** the name, and the priority.
  */
  
  C1Sig = AllocSignal(-1);
  C2Sig = AllocSignal(-1);

  Main = FindTask(NULL);
  C1 = CreateTask(func_1, "TASK 1", 4000, 1);
  C2 = CreateTask(func_2, "TASK 2", 4000, 1);

  /*
  ** Wait for both children to signal they are ready.
  */

  WaitRet = 0;
  while(WaitRet != ((BIT(C1Sig) | BIT(C2Sig))
    WaitRet = WaitRet | Wait(BIT(C1Sig) | BIT(C2Sig));

  while (not time to quit) {
    /*
    ** brilliant inter-task communication code event loop...
    */
  }

  /*
  ** Time to kill children...
  */

  DieFlag = TRUE;

  /*
  ** Wait for both children to signal they are ready to die.
  */
  while(WaitRet != ((BIT(C1Sig) | BIT(C2Sig))
    WaitRet = WaitRet | Wait(BIT(C1Sig) | BIT(C2Sig));

  DeleteTask(C1);
  DeleteTask(C2);

  exit(0);
}
 
func_1()
{
  /*
  ** Ensure addressability of global data...
  */
  geta4();

  /* ..brilliant initialization code, then Signal we are ready */
  Signal(Main, BIT(C1));

  for (;;) {
    /*
    ** brilliant inter-task communication code event loop...
    */

    if (DieFlag) {
      Signal(Main, BIT(C1));
      Wait(0L); /* Wait() forever */
  }

     
}
 
func_2()
{
/* same as func_1 except use C2 */ 
}

This code does NOT check error returns from things like AllocSignal(),
etc which it should do.  For this particular example to be completely
safe, the children should be running at a higher priority than the
parent.  The children do a Wait(0L) to put them in a "safe" state to
remove them.  DeleteTask() calls RemoveTask() which isn't always safe
depending on the state that removed task is in, Wait(0L); is a safe
state.

Oh, obviously the parent and children should do any cleanup before
they wait or exit (FreeSignal() comes to mind).  Note that most
allocation calls can be done by either side, but certain things, like
AllocSignal() are "context dependant" and should be allocated by the
owning/receiving end.
 
>   I would like to set up func_1 and func_2 to run as completely independent
> processes.  Also, After they are set up, is anything needed to get them to
> actually start executing?  I have a project now where the tasks are being
> set up correctly (even show up with TaskX), but they seem to never actually
> execute.  Any suggestions?

When something is AddTask()ed (which is called by create task), it
will began executing as soon as it normally would, which is dependant
on its priority.  With multitasking programs its important to avoid
deadlock conditions (where task A is waiting on task B for something
at the same time task B is waiting on task A, so both tasks stop
forever).

You can use WaitMask = SetSignal(0, 0); as a safe way to check and
clear signals without blocking if the signals aren't there (such as
break checking).
 
>    Phil

Obviously all this code assumes tasks.  Processes are much trickier as
you have to create file handles, get around the SegList problem, etc.

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mark Gooderum                 /\     \ | /     H a p p y  
Academic Computing Services  / v\   -- * --         H o l i d a y s ! :-)
University of Kansas        /v  v\   / | \    ///
                           /__v___\   Only  ///  /|         __    _  
Bitnet:   MARKV@UKANVAX       ||     \\\  ///  /__| |\/| | | _   /_\  makes it
Internet: markv@kuhub.cc.ukans.edu     \/\/  /    | |  | | |__| /   \ possible
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

rick@rsami.UUCP (Rick Schaeffer) (12/04/90)

>In article <9011241137.AA24447@luke.eecs.wsu.edu> pcooper@LUKE.EECS.WSU.EDU (Phil Cooper - CS495) writes:
>Fellow Amigans:
>
>     I would like some advice/examples on how to set up several functions
>in a source code file as independent processes (using ports and messages
>for inter-process communications.)  My problem can be described as follows:
>
>   Phil

You might take a look at the popen example I posted to alt.sources.amiga
a while back.  The 2.0 version of it uses the new CreateNewProc() function
which can optionally create an entire process out of a function within
the current process.  I use that feature to start the background part
of the pipe.  If you don't yet have access to Dos2.0, there was an
example of exactly what you want posted a long time ago.  It was
called "proc.c" and illustrated how to create a process out of a function
by using the old CreateProc() function.  This function takes a pointer
to a "seglist"...well a seglist simply consists of a pointer to the
next segment followed by the actual code to be executed.  What he did
was to stuff a "jmp" instruction into a dummy seglist structure, set
the address of the jump to the function address, and then call CreateProc()
passing a pointer to this dummy seglist.  

Hopefully, this is enough to get you going.  If not, I can probably dig
up the source code and email it to you.  If you decide to email to me,
be sure to use the address in my .signature.  My news site is my amiga
and it isn't a registered site!
-- 
Rick Schaeffer          UUCP:  uunet!isc-br.isc-br.com!ricks
E. 13611 26th Ave.             ricks@isc-br.isc-br.com
Spokane, Wa.  99216     Phone: (509)928-3533