From: Todd_Lewis@unc.edu (Todd M. Lewis)
Subject: Re: task communication and forbid()
Organization: UNC Office of Information Technology
Date: Fri, 18 Dec 1992 20:48:44 GMT

In article <1992Dec18.055155.18152@umr.edu> quandt@mcs213b.cs.umr.edu (Brian  
Quandt) writes:
>I have a question on how to communicate from a subtask to the parent.
>The main problem is that I need to call forbid so that I can
>ensure that I get timely response during the while loop.  Is it
>legit to use globals?  Is there any special way that these
>globals need to be declared (memory model) ?  I know that task
>communication via globals and assumed constant memory addresses
>is ugly but it seems to be the correct way on the amiga.  Is it?
>Is there a better way? 
> 
> {
> CreateTask( some task that reads keyboard input and sets globalKILL
> 		appropriatly )
> 
> forbid();
> 
> while(!globalKILL)
>	{
>        
> 	}
> 
> permit();
> }

Ugh.  That's not good.  You will waste half of your cycles busy-waiting.
You want to do a for-real Wait().  Some notes on the code that follows.
  1)  This is off the top of my head--I don't have an Amiga here to
      test it with, so it may not compile, much less work.
  2)  The signal SIGF_SINGLE is pre-allocated for every task so if
      you are just waiting on one thing you can use this "well-known signal".
      Always clear it before waiting on it.  That's what simple_wait() is for.
  3)  When you call CreateTask(), you have no way to know if the subtask has
      gotten to run at all by time the call returns, so coordination between
      parent and child tasks is really tricky.
  4)  carefully study the Forbid()/Permit() pairs around the state variable
      examination/change/simple_wait() groups.  Follow both threads of
      execution and at every line in the program ask yourself "What happens
      if a task switch occurs here?"  I think I've considered all the pitfalls.

================== coordinate.c =============================
#include <exec/tasks.h>

#define STARRUNNING 1
#define RUNNING     2
#define DROPDEAD    3
#define DEAD        4

struct Process *mamma_ptr;
struct Process *child_ptr;
int             state      = 0;
ULONG           counter    = 0;

void simple_wait( void )
  {
    SetSignal( 0L, SIGF_SINGLE );  /* Clear the signal.    */
    Wait( SIGF_SINGLE );           /* Wait for the signal. */
  }

void child( void )
  {
    Forbid();
      while ( state < STARTRUNNING )
        simple_wait();
    Permit();

    Forbid();
      state = RUNNING;
      Signal( mamma_ptr, SIGF_SINGLE);
    Permit();

    while( state == RUNNING )  /* Do something wonderful.   */
       counter++;

    Forbid();                  /* state should be DROPDEAD. */
      state = DEAD;
      Signal( mamma_ptr, SIGF_SINGLE );
    /* Hanging Forbid() ensures child exits before main() resumes. */
  }

int main( int argc, char *argv[] )
  {
    mamma_ptr = FindTask(0);
    child_ptr = CreatTask("the kid", 0, child, 2048 );
    if ( child_ptr )
       {
         state = STARTRUNNING; /* Tell child to run some more. */
         Signal( child_ptr, SIGF_SINGLE );

         Forbid();             /* Wait for child to start running. */
           while ( state < RUNNING )
             simple_wait();
         Permit();             /* Child is running.       */

         Delay( 250L );        /* Sleep for 5 seconds.    */
                               /* Do something wonderful. */
         Forbid();
           state = DROPDEAD;   /* Tell child to die.      */
           simple_wait();      /* Wait for child to die.  */
         permit();
                     /* child (and state) should be DEAD. */
       }
    return 0;
  }
=====================================================================

--
 _/_/_/  _/     Todd_Lewis@unc.edu          You can lead a horse to 
  _/    _/     utoddl@guitar.oit.unc.edu   Mohammad, but you can't make
 _/    _/_/_/                             a mountain drink a mole hill.