(*$R-*)
IMPLEMENTATION MODULE Processes [1];
(*
  Module:       Processes
  From:         "Programming in Modula-2", 3rd, corrected edition, by N. Wirth
  Version:      $Header: /cvsup/minix/src/lib/ack/libm2/Processes.mod,v 1.1 2005/10/10 15:27:46 beng Exp $
*)

  FROM	SYSTEM IMPORT	ADDRESS, TSIZE, NEWPROCESS, TRANSFER;
  FROM	Storage IMPORT	Allocate;
  FROM	Traps IMPORT	Message;

  TYPE	SIGNAL = POINTER TO ProcessDescriptor;

	ProcessDescriptor =
		RECORD	next: SIGNAL;	(* ring *)
			queue: SIGNAL;	(* queue of waiting processes *)
			cor: ADDRESS;
			ready: BOOLEAN;
		END;

  VAR	cp: SIGNAL;			(* current process *)

  PROCEDURE StartProcess(P: PROC; n: CARDINAL);
    VAR	s0: SIGNAL;
	wsp: ADDRESS;
  BEGIN
	s0 := cp;
	Allocate(wsp, n);
	Allocate(cp, TSIZE(ProcessDescriptor));
	WITH cp^ DO
		next := s0^.next;
		s0^.next := cp;
		ready := TRUE;
		queue := NIL
	END;
	NEWPROCESS(P, wsp, n, cp^.cor);
	TRANSFER(s0^.cor, cp^.cor);
  END StartProcess;

  PROCEDURE SEND(VAR s: SIGNAL);
    VAR	s0: SIGNAL;
  BEGIN
	IF s # NIL THEN
		s0 := cp;
		cp := s;
		WITH cp^ DO
			s := queue;
			ready := TRUE;
			queue := NIL
		END;
		TRANSFER(s0^.cor, cp^.cor);
	END
  END SEND;

  PROCEDURE WAIT(VAR s: SIGNAL);
    VAR	s0, s1: SIGNAL;
  BEGIN
	(* insert cp in queue s *)
	IF s = NIL THEN
		s := cp
	ELSE
		s0 := s;
		s1 := s0^.queue;
		WHILE s1 # NIL DO
			s0 := s1;
			s1 := s0^.queue
		END;
		s0^.queue := cp
	END;
	s0 := cp;
	REPEAT
		cp := cp^.next
	UNTIL cp^.ready;
	IF cp = s0 THEN
		(* deadlock *)
		Message("deadlock");
		HALT
	END;
	s0^.ready := FALSE;
	TRANSFER(s0^.cor, cp^.cor)
  END WAIT;

  PROCEDURE Awaited(s: SIGNAL): BOOLEAN;
  BEGIN
	RETURN s # NIL
  END Awaited;

  PROCEDURE Init(VAR s: SIGNAL);
  BEGIN
	s := NIL
  END Init;

BEGIN
	Allocate(cp, TSIZE(ProcessDescriptor));
	WITH cp^ DO
		next := cp;
		ready := TRUE;
		queue := NIL
	END
END Processes.
