(**********************************************************************

    :Program.    MultitaskDemo.mod
    :Contents.   Zeigt die Häufigkeit von einzelnen Zeichen einer Datei an
    :Remark.     benutzt im Gegensatz zu SyncDemo parallele Tasks
    :Author.     Nicolas Benezan [bne]
    :Address.    Postwiesenstr. 2, D7000 Stuttgart 60
    :Phone.      711/333679
    :Copyright.  Public Domain
    :Language.   Modula-2
    :Translator. M2Amiga A+L V3.27d
    :Imports.    BackDrop [Bernd Preusing], TaskSupport, TaskMemory [bne]
    :History.    V1.0 [bne] 12.Jan.1990

**********************************************************************)

MODULE MultitaskDemo;

FROM Arguments   IMPORT GetArg, NumArgs;
FROM Arts        IMPORT Assert, TermProcedure;
FROM BackDrop    IMPORT BdRp, OpenBackDrop;
FROM Dos         IMPORT Close, Delay, Examine, FileHandlePtr,
                        FileInfoBlock, FileInfoBlockPtr, FileLockPtr, Lock,
                        oldFile, Open, Read, sharedLock, UnLock;
FROM Exec        IMPORT AllocSignal, FindTask, FreeSignal, Signal, TaskPtr,
                        Wait;
FROM Graphics    IMPORT SetAPen, WritePixel;
FROM RingBuffers IMPORT CreateRingBuffer, DiscardRingBuffer, GetEmptyBlock,
                        GetFullBlock, PutEmptyBlock, PutFullBlock,
                        RingBuffer, RingBufferBlock;
FROM TaskMemory  IMPORT Allocate, Deallocate;
FROM TaskSupport IMPORT CreateTask, DeleteTask;
FROM SYSTEM      IMPORT ADDRESS, ADR, LONGSET;

TYPE
  BufferPtr = POINTER TO Buffer;
  Buffer = RECORD
    size: LONGINT;
    data: ARRAY [0..255] OF CHAR;
  END;

CONST
  BufferSize = SIZE (Buffer);
  NumBuffers = 8;
  Usage = 'Usage = "MultitaskDemo" FileName.';

VAR
  Count: ARRAY CHAR OF LONGINT;
  File: FileHandlePtr;
  FileName: ARRAY [0..31] OF CHAR;
  TotalSize, Position: LONGINT;
  Len: INTEGER;
  DataBuffer: RingBuffer;
  MainTask, ReadTask: TaskPtr;
  FullSignal, EmptySignal, ReadySignal, StartSignal: INTEGER;
  DummySet: LONGSET;
  ReadCompleted: BOOLEAN;

PROCEDURE Cleanup;
  BEGIN
    IF File # NIL THEN
      Close (File);
      File:= NIL;
    END;
    IF ReadySignal >= 0 THEN
      FreeSignal (ReadySignal);
    END;
    IF FullSignal >= 0 THEN
      FreeSignal (FullSignal);
    END;
  END Cleanup;

PROCEDURE Draw (DataPtr: BufferPtr);
  VAR
    i: INTEGER;
    Char: CHAR;
    Dummy: LONGINT;
  BEGIN
    FOR i:= 0 TO DataPtr^.size - 1 DO
      Char:= DataPtr^.data[i];
      INC (Position);
      SetAPen (BdRp, 3);
      Dummy:= WritePixel (BdRp, Position * 640 DIV TotalSize, 0);
      INC (Count[Char]);
      SetAPen (BdRp, 2);
      Dummy:= WritePixel (BdRp, Count[Char], ORD (Char) + 1);
      SetAPen (BdRp, 1);
      Dummy:= WritePixel (BdRp, Count[Char] * 640 DIV TotalSize,
                          ORD (Char) + 1);
    END;
  END Draw;

PROCEDURE FileSize (Name: ARRAY OF CHAR): LONGINT;
  VAR
    FileLock: FileLockPtr;
    Info: FileInfoBlockPtr;
    Size: LONGINT;
  BEGIN
    Allocate (Info, SIZE (FileInfoBlock));
    Assert (Info # NIL, ADR ("No free store"));
    FileLock:= Lock (ADR (Name), sharedLock);
    Assert (FileLock # NIL, ADR ("Lock() failed"));
    Assert (Examine (FileLock, Info), ADR ("Examine() failed"));
    Size:= Info^.size;
    Deallocate (Info);
    UnLock (FileLock);
    RETURN Size;
  END FileSize;

PROCEDURE ReadProcess (MainTaskPtr: ADDRESS);
  VAR
    Block: RingBufferBlock;
    DataPtr: BufferPtr;
    CurrentSize: LONGINT;
  CONST
    DataSize = SIZE (DataPtr^.data);
  BEGIN
    EmptySignal:= AllocSignal (-1); (* cannot fail, new task *)
    StartSignal:= AllocSignal (-1);
    Signal (MainTaskPtr, LONGSET{ReadySignal});
    DummySet:= Wait (LONGSET{StartSignal});
    REPEAT
      WHILE NOT GetEmptyBlock (DataBuffer, Block, DataPtr) DO
        DummySet:= Wait (LONGSET{EmptySignal});
      END;
      CurrentSize:= Read (File, ADR (DataPtr^.data), DataSize);
      DataPtr^.size:= CurrentSize;
      IF CurrentSize > 0 THEN
        PutFullBlock (DataBuffer, Block);
      END;
    UNTIL CurrentSize < DataSize;
    ReadCompleted:= TRUE;
    Signal (MainTaskPtr, LONGSET{FullSignal}); (* prevent deadlock *)
    FreeSignal (EmptySignal);
  END ReadProcess;

PROCEDURE MainProcess;
  VAR
    Block: RingBufferBlock;
    DataPtr: BufferPtr;
  BEGIN
    LOOP
      WHILE NOT GetFullBlock (DataBuffer, Block, DataPtr) DO
        IF ReadCompleted THEN (* no more blocks *)
          EXIT
        END;
        DummySet:= Wait (LONGSET{FullSignal});
      END;
      Draw (DataPtr);
      PutEmptyBlock (DataBuffer, Block);
    END;
  END MainProcess;

BEGIN
  File:= NIL;
  ReadySignal:= -1;
  FullSignal:= -1;
  ReadCompleted:= FALSE;
  TermProcedure (Cleanup);
  Assert (NumArgs () = 1, ADR (Usage));
  GetArg (1, FileName, Len);
  File:= Open (ADR (FileName), oldFile);
  Assert (File # NIL, ADR ("File not found"));
  TotalSize:= FileSize (FileName);
  OpenBackDrop (2, 640, 257, ADR ("MultitaskDemo"));
  Position:= 0;
  ReadySignal:= AllocSignal (-1);
  Assert (ReadySignal >= 0, ADR ("No signal free"));
  FullSignal:= AllocSignal (-1);
  Assert (FullSignal >= 0, ADR ("No signal free"));
  MainTask:= FindTask (NIL);
  ReadTask:= CreateTask (ReadProcess, MainTask,
                         ADR ("MultitaskDemo.readtask"), 4096, 0);
  IF ReadTask # NIL THEN
    DummySet:= Wait (LONGSET{ReadySignal});
    IF CreateRingBuffer (DataBuffer, BufferSize, NumBuffers, MainTask,
                         FullSignal, ReadTask, EmptySignal) THEN
      Signal (ReadTask, LONGSET{StartSignal});
      MainProcess;
      DiscardRingBuffer (DataBuffer);
    END;
  END;
  Delay (250);
END MultitaskDemo.

