program test;
{ Test multi-tasking under MP/M with Pascal MT+86
  Uses simple booleans for task exclusion
  ABORT used for subtask termination		  }

  const
    pd_max = 61;  {max byte address in process descriptor table}
    uda_max = 255;  {max byte address in user data area table}
    def_prior = 201;  {default process priority}

  type
    name_type = packed array [1..8] of char;

    pd_size = 0..pd_max;  {Process Descriptor}
    pd_type =
      record
	case boolean of
	  true:
	    (z1: packed array [1..5] of byte;
	     prior: byte;
	     flag: word;
	     name: name_type;
	     uda: word;
	     user, disk: byte;
	     z2: packed array [1..12] of byte;
	     cns: byte;
	     z3: packed array [1..3] of byte;
	     list: byte;
	     z4: packed array [1..15] of byte;
	     cns2: byte;
	     z5: byte;
	     name2: name_type);
	  false:
	    (ray: array [pd_size] of byte);
      end;

    uda_size = 0..uda_max;  {User Data Area for Process}
    uda_type = array [uda_size] of byte;

    ptr = ^integer;
    pdp = ^pd_type;
    udap = ^uda_type;

    ptrtype = (ptrp, pdpp, udapp, offseg);
    pointer =
      record  {kludge to allow any type of pointer reference}
	case ptrtype of
	  ptrp:
	    (pptr: ptr);
	  pdpp:
	    (ppdp: pdp);
	  udapp:
	    (puda: udap);
	  offseg:
	    (off: word;
	     seg: word)
      end;

  var
    uda_b, uda_a: uda_type;  {user data area for sub-processes}
    pd_b, pd_a: pd_type;  {process descriptor for sub-processes}
    count_b, count_a: integer;
    flag_b, flag_a: boolean;
    done_b, done_a: boolean;

  external procedure init_mpm_util(size: integer);
  external procedure fix_stack(taskp: ptr;
			       var uda: uda_type;
			       size: integer);
  external procedure delay(ticks: integer);
  external procedure dispatch;
  external procedure abort(var pd: pd_type);
  external function create_process(var pd: pd_type): boolean;
  external function set_priority(priority: byte): boolean;

{ ********************************************************** }


  procedure startup(var pd: pd_type;
		    var uda: uda_type;
		    task: ptr;
		    name: string;
		    priority: integer;
		    size: integer);

    var
      i: integer;
      p: pointer;

    begin
      for i := 0 to pd_max do
	pd.ray[i] := 0;
      for i := 0 to uda_max do
	uda[i] := 0;

      pd.prior := priority;
      for i := 1 to 8 do
	begin
	pd.name[i] := name[i];
	pd.name2[i] := name[i]
	end;
      p.puda := addr(uda);
      pd.uda := shr(p.off, 4);  {make into paragraph address}
      fix_stack(task, uda, size);

      if create_process(pd) then
	writeln('Starting ', name)
      else
	writeln('Startup of ', name, ' failed');
    end;


  procedure task_a;

    begin
      while true do
	begin
	while flag_a do
	  delay(40);  {wait for flag to be cleared}
	count_a := count_a + 1;
	flag_a := true;
	end;
    end;


  procedure task_b;

    begin
      while true do
	begin
	while flag_b do
	  delay(50);  {wait for flag to be cleared}
	count_b := count_b + 1;
	flag_b := true;
	end;
    end;


  begin  {main program}
    writeln('Entered MAIN');
    if not set_priority(def_prior) then
      begin
      writeln('Unable to set main program priority');
      exit
      end;
    count_a := 0;	count_b := 0;
    flag_a := false;	flag_b := false;
    done_a := false;	done_b := false;
    init_mpm_util(6000);
    startup(pd_a, uda_a, addr(task_a), 'TASK_A  ', def_prior, 900);
    startup(pd_b, uda_b, addr(task_b), 'TASK_B  ', def_prior, 900);

    repeat
      dispatch;
      if flag_a then
	begin
	writeln('loop A count = ', count_a);
	flag_a := false
	end;
      if (count_a >= 10) and (not done_a) then
	begin
	abort(pd_a);
	writeln('Task A complete');
	done_a := true;
	end;
      if flag_b then
	begin
	writeln('loop B count = ', count_b);
	flag_b := false
	end;
      if (count_b >= 10) and (not done_b) then
	begin
	abort(pd_b);
	writeln('Task B complete');
	done_b := true;
	end;
    until done_a and done_b;

  end.
