118 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
(*
 | 
						|
  (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
  See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
*)
 | 
						|
 | 
						|
(*$R-*)
 | 
						|
IMPLEMENTATION MODULE Semaphores [1];
 | 
						|
(*
 | 
						|
  Module:       Processes with semaphores
 | 
						|
  Author:       Ceriel J.H. Jacobs
 | 
						|
  Version:      $Header$
 | 
						|
 | 
						|
  Quasi-concurrency implementation
 | 
						|
*)
 | 
						|
 | 
						|
  FROM	SYSTEM IMPORT	ADDRESS, NEWPROCESS, TRANSFER;
 | 
						|
  FROM	Storage IMPORT	Allocate;
 | 
						|
  FROM	random IMPORT	Uniform;
 | 
						|
  FROM	Traps IMPORT	Message;
 | 
						|
 | 
						|
  TYPE	Sema = POINTER TO Semaphore;
 | 
						|
	Processes = POINTER TO Process;
 | 
						|
	Semaphore =
 | 
						|
		RECORD
 | 
						|
			level: CARDINAL;
 | 
						|
		END;
 | 
						|
	Process =
 | 
						|
		RECORD	next: Processes;
 | 
						|
			proc: ADDRESS;
 | 
						|
			waiting: Sema;
 | 
						|
		END;
 | 
						|
 | 
						|
  VAR	cp: Processes;			(* current process *)
 | 
						|
 | 
						|
  PROCEDURE StartProcess(P: PROC; n: CARDINAL);
 | 
						|
    VAR	s0: Processes;
 | 
						|
	wsp: ADDRESS;
 | 
						|
  BEGIN
 | 
						|
	s0 := cp;
 | 
						|
	Allocate(wsp, n);
 | 
						|
	Allocate(cp, SIZE(Process));
 | 
						|
	WITH cp^ DO
 | 
						|
		next := s0^.next;
 | 
						|
		s0^.next := cp;
 | 
						|
		waiting := NIL;
 | 
						|
	END;
 | 
						|
	NEWPROCESS(P, wsp, n, cp^.proc);
 | 
						|
	TRANSFER(s0^.proc, cp^.proc);
 | 
						|
  END StartProcess;
 | 
						|
 | 
						|
  PROCEDURE Up(VAR s: Sema);
 | 
						|
  BEGIN
 | 
						|
	s^.level := s^.level + 1;
 | 
						|
	ReSchedule;
 | 
						|
  END Up;
 | 
						|
 | 
						|
  PROCEDURE Down(VAR s: Sema);
 | 
						|
  BEGIN
 | 
						|
	IF s^.level = 0 THEN
 | 
						|
		cp^.waiting := s;
 | 
						|
	ELSE
 | 
						|
		s^.level := s^.level - 1;
 | 
						|
	END;
 | 
						|
	ReSchedule;
 | 
						|
  END Down;
 | 
						|
 | 
						|
  PROCEDURE NewSema(n: CARDINAL): Sema;
 | 
						|
  VAR	s: Sema;
 | 
						|
  BEGIN
 | 
						|
	Allocate(s, SIZE(Semaphore));
 | 
						|
	s^.level := n;
 | 
						|
	RETURN s;
 | 
						|
  END NewSema;
 | 
						|
 | 
						|
  PROCEDURE Level(s: Sema): CARDINAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN s^.level;
 | 
						|
  END Level;
 | 
						|
 | 
						|
  PROCEDURE ReSchedule;
 | 
						|
  VAR s0: Processes;
 | 
						|
      i, j: CARDINAL;
 | 
						|
  BEGIN
 | 
						|
	s0 := cp;
 | 
						|
	i := Uniform(1, 5);
 | 
						|
	j := i;
 | 
						|
	LOOP
 | 
						|
		cp := cp^.next;
 | 
						|
		IF Runnable(cp) THEN
 | 
						|
			DEC(i);
 | 
						|
			IF i = 0 THEN EXIT END;
 | 
						|
		END;
 | 
						|
		IF (cp = s0) AND (j = i) THEN
 | 
						|
			(* deadlock *)
 | 
						|
			Message("deadlock");
 | 
						|
			HALT
 | 
						|
		END;
 | 
						|
	END;
 | 
						|
	IF cp # s0 THEN TRANSFER(s0^.proc, cp^.proc); END;
 | 
						|
  END ReSchedule;
 | 
						|
 | 
						|
  PROCEDURE Runnable(p: Processes): BOOLEAN;
 | 
						|
  BEGIN
 | 
						|
	IF p^.waiting = NIL THEN RETURN TRUE; END;
 | 
						|
	IF p^.waiting^.level > 0 THEN
 | 
						|
		p^.waiting^.level := p^.waiting^.level - 1;
 | 
						|
		p^.waiting := NIL;
 | 
						|
		RETURN TRUE;
 | 
						|
	END;
 | 
						|
	RETURN FALSE;
 | 
						|
  END Runnable;
 | 
						|
BEGIN
 | 
						|
	Allocate(cp, SIZE(Process));
 | 
						|
	WITH cp^ DO
 | 
						|
		next := cp;
 | 
						|
		waiting := NIL;
 | 
						|
	END
 | 
						|
END Semaphores.
 |