packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/PMOS/sources/general/semaphor.mod

IMPLEMENTATION MODULE Semaphores;

	(********************************************************)
	(*							*)
	(*	Implements the Wait and Signal operations on	*)
	(*	semaphores.					*)
	(*							*)
	(*	Programmer:	P. Moylan			*)
	(*	Last edited:	27 February 1995		*)
	(*	Status:		Working				*)
	(*							*)
	(********************************************************)

FROM TaskControl IMPORT
    (* type *)	TaskQueue,
    (* proc *)	CreateQueue, MarkAsReady, QueueAndSwitchTasks,
		QueueWithTimeout;

FROM InnerKernel IMPORT
    (* proc *)	EnterKernel, LeaveKernel;

FROM Storage IMPORT
    (* proc *)	ALLOCATE, DEALLOCATE;

FROM TerminationControl IMPORT
    (* proc *)	Crash;

(************************************************************************)

TYPE Semaphore = POINTER TO RECORD
				value	:	INTEGER;
				blockedlist :	TaskQueue
			    END;

(************************************************************************)

PROCEDURE CreateSemaphore (VAR (*OUT*) s: Semaphore;
					InitialValue: CARDINAL);

    (* Creates semaphore s, with the given initial value and an empty	*)
    (* queue.								*)

    VAR savedPSW: CARDINAL;

    BEGIN
	savedPSW := EnterKernel();
	NEW(s);
	s^.value := InitialValue;
	CreateQueue (s^.blockedlist);
	LeaveKernel (savedPSW);
    END CreateSemaphore;

(************************************************************************)

PROCEDURE DestroySemaphore (VAR (*INOUT*) s: Semaphore);

    (* Reclaims any space used by semaphore s.  Remark:  It is not at	*)
    (* all obvious what should be done with any tasks which happen to	*)
    (* be blocked on this semaphore (should they be unblocked, or	*)
    (* killed?).  At present we take the easy way out and assume that	*)
    (* there are no pending operations on s at the time that it is	*)
    (* destroyed.							*)

    VAR savedPSW: CARDINAL;

    BEGIN
	savedPSW := EnterKernel();
	DISPOSE (s);
	LeaveKernel (savedPSW);
    END DestroySemaphore;

(************************************************************************)

PROCEDURE Wait (VAR (*INOUT*) s: Semaphore);

    (* Decrements the semaphore value.  If the value goes negative, the	*)
    (* calling task is blocked and there is a task switch.		*)

    VAR savedPSW: CARDINAL;

    BEGIN
	IF s = NIL THEN Crash ("Wait on nonexistent semaphore"); END(*IF*);
	savedPSW := EnterKernel();
	DEC (s^.value);
	IF s^.value < 0 THEN
	    QueueAndSwitchTasks (s^.blockedlist)
	END (*IF*);
	LeaveKernel (savedPSW);
    END Wait;

(************************************************************************)

PROCEDURE TimedWaitT (VAR (*INOUT*) s: Semaphore;  TimeLimit: INTEGER;
			VAR (*OUT*) TimedOut: BOOLEAN);

    (* Like procedure Wait, except that it returns with TimedOut TRUE	*)
    (* if the corresponding Signal does not occur within TimeLimit	*)
    (* clock ticks.							*)

    VAR savedPSW: CARDINAL;

    BEGIN
	IF s = NIL THEN
	    Crash ("Timed Wait on nonexistent semaphore");
	END(*IF*);
	savedPSW := EnterKernel();
	TimedOut := FALSE;
	DEC (s^.value);
	IF s^.value < 0 THEN
	    IF TimeLimit <= 0 THEN
		TimedOut := TRUE;
	    ELSE
		TimedOut := QueueWithTimeout (s^.blockedlist, TimeLimit);
	    END (*IF*);

	    IF TimedOut THEN
		INC (s^.value);
	    END (*IF*);

	END (*IF s^.value < 0 *);
	LeaveKernel (savedPSW);

    END TimedWaitT;

(************************************************************************)

PROCEDURE Signal (VAR (*INOUT*) s: Semaphore);

    (* Increments the semaphore value.  Unblocks one task, if there was	*)
    (* one waiting on this semaphore.					*)

    VAR savedPSW: CARDINAL;

    BEGIN
	IF s = NIL THEN Crash ("Signal on nonexistent semaphore"); END(*IF*);
	savedPSW := EnterKernel();
	INC (s^.value);
	IF s^.value <= 0 THEN

	    (* If the semaphore initial value is nonnegative, the test	*)
	    (* (s^.value<=0) is equivalent to the more obvious test	*)
	    (* for nonempty blocked list.  Negative initial values are	*)
	    (* not permitted in this implementation.			*)

	    MarkAsReady (s^.blockedlist);

	END (*IF*);
	LeaveKernel (savedPSW);
    END Signal;

END Semaphores.