/* Dieses Programm demonstriert die Task-Generation
 * und eine mögliche Kommunikationsfähigekeit.
 * Beim Kompilieren unbedingt die StackCheck-Option
 * deaktivieren.
 * Programmautor: Rainer Zeitler
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <stdio.h>

#define TASKPRI   0L
#define TASKNAME  "TochterTask"
#define STACKSIZE 1000L

/* Darüber läßt sich nachvollziehen, daß der
 * Tochtertask überhaupt seine Arbeit verrichtete
 */
ULONG TochterCounter=0;

/* Signal-Bits für die Kommunikation */
ULONG TochterStartedSig=0,StopTochterTaskSig=0;

/* Der Task des Hauptprogramms */
struct Task *MainTask;

void __saveds __interrupt TochterTask(void) {
  /* Das Stopsignal anlegen */
  StopTochterTaskSig=AllocSignal(-1L);

  /* Dem Haupttask mitteilen, daß wir soweit sind */
  Signal( MainTask, 1L<<TochterStartedSig );

  /* Solange die Variable hochzählen, bis das Stop-
   * Signal geschickt wird
   */
  while( (SetSignal(0L,0L) &
                    (1L<<StopTochterTaskSig)) == 0)
    TochterCounter++;

  /* Signal wieder freigeben */
  FreeSignal( StopTochterTaskSig );

  /* Beenden bestätigen */
  Signal( MainTask, 1L<<TochterStartedSig );

  /* Wichtig: So schläft der Task für immer und
   * wir können ihn gefahrlos via RemTask()
   * entfernen
   */
  Wait(0);
}

main(long argc, char **argv) {
  struct Task *Tochter=AllocMem(sizeof(struct Task),
                            MEMF_CLEAR|MEMF_PUBLIC);
  APTR   TaskStack=AllocMem(STACKSIZE,
                            MEMF_CLEAR|MEMF_PUBLIC);

  /* Die Adresse unseres Tasks */
  MainTask=FindTask(NULL);

  if( Tochter && TaskStack )
  {
    TochterStartedSig=AllocSignal(-1L);
    if( TochterStartedSig )
    {
      /* Priorität des Tochter-Tasks */
      Tochter->tc_Node.ln_Pri = TASKPRI;
      /* Jawoll, es ist ein Task */
      Tochter->tc_Node.ln_Type = NT_TASK;
      /* Der Name des Tochter-Tasks */
      Tochter->tc_Node.ln_Name = TASKNAME;

      /* Untere Grenze des Tochter-Task-Stacks */
      Tochter->tc_SPLower = TaskStack;
      /* Obere Grenze des Tochter-Task-Stacks */
      Tochter->tc_SPUpper = Tochter->tc_SPReg =
              (APTR)((ULONG)TaskStack+STACKSIZE);
      /* Task starten */
      AddTask(Tochter,(APTR)TochterTask,0L);

      /* Warten, bis der TochterTask sich meldet */
      printf("Warte auf TochterTask\n");
      Wait( 1L<<TochterStartedSig );
      printf("TochterTask hat sich gemeldet\n"
                            "5 Sekunden warten\n");
      Delay( 5 * 50 );

      /* Den TochterTask beenden */
      printf("Beende TochterTask und warte"
                             " auf Bestätigung\n");
      Signal( Tochter, 1L<<StopTochterTaskSig );

      /* Auf Bestätigung warten */
      Wait( 1L<<TochterStartedSig );
      printf("TochterTask beendet\n");

      printf("Zählerstand: %ld\n",TochterCounter);

      /* Task entfernen */
      RemTask( Tochter );
      /* Signal freigeben */
      FreeSignal( TochterStartedSig );
    }
  }

  /* Speicher freigeben */
  if( TaskStack )
    FreeMem( TaskStack, STACKSIZE );
  if( Tochter )
    FreeMem( Tochter, sizeof(struct Task) );
}
