-- TiogaPGMonitorImpl.Mesa

-- last written by Paxton.  February 8, 1981  5:47 PM


DIRECTORY

  TiogaFiles: FROM "TiogaFiles" USING [controlBlock, textBlock],
  TiogaPGStreams;

TiogaPGMonitorImpl: MONITOR
	LOCKS pgm USING pgm: PGM


EXPORTS TiogaPGStreams =

BEGIN OPEN filesI: TiogaFiles, TiogaPGStreams;

PGM:  TYPE = REF PGMBody;

PGMBody: PUBLIC TYPE = MONITORED RECORD [
	text, control, writes, deferred: MList
	];

MList: TYPE = REF MListBody;
MListBody: TYPE = RECORD [
	first, last: BlockList,
	done: BOOLEAN ← FALSE,
	available: CONDITION
	];

BlockList: TYPE = REF BlockListBody;
BlockListBody: TYPE = RECORD [
	next: BlockList,
	block: Block ];

CreatePGM: PUBLIC PROC [mode: PGStreamMode]
	RETURNS [pgm: PGM] =
	BEGIN
	pgm ← NEW[PGMBody];
	SELECT mode FROM
		read => { pgm.text ← NEW[MListBody]; pgm.control ← NEW[MListBody] };
		write => { pgm.writes ← NEW[MListBody]; pgm.deferred ← NEW[MListBody] };
		ENDCASE => ERROR;
	END;

AddToMList: INTERNAL PROC [mlst: MList, block: Block] =
	BEGIN
	itm: BlockList ← NEW[BlockListBody ← [NIL, block]];
	IF mlst.first # NIL THEN mlst.last.next ← itm
	ELSE mlst.first ← itm;
	mlst.last ← itm;
	NOTIFY mlst.available;
	END;

GetFromMList: INTERNAL PROC [mlst: MList, pgm: PGM] RETURNS [block: Block] =
	BEGIN
	itm: BlockList;
	WHILE (itm ← mlst.first) = NIL AND ~mlst.done DO
		WAIT mlst.available;
		ENDLOOP;
	IF itm=NIL THEN RETURN [NIL]; -- done
	block ← itm.block;
	IF itm = mlst.last THEN mlst.first ← mlst.last ← NIL
	ELSE mlst.first ← mlst.first.next;
	END;

AddToControlList: PUBLIC ENTRY PROC [pgm: PGM, block: Block] =
	{ ENABLE UNWIND => NULL;
		AddToMList[pgm.control, block] };

GetFromControlList: PUBLIC ENTRY PROC [pgm: PGM] RETURNS [Block] =
	{ ENABLE UNWIND => NULL;
		RETURN [GetFromMList[pgm.control, pgm]] };

SetDone: INTERNAL PROC [mlst: MList] = INLINE
	{ mlst.done ← TRUE; NOTIFY mlst.available };

ControlReadsDone: PUBLIC ENTRY PROC [pgm: PGM] =
	{ ENABLE UNWIND => NULL;
		SetDone[pgm.control] };

TextReadsDone: PUBLIC ENTRY PROC [pgm: PGM] =
	{ ENABLE UNWIND => NULL;
		SetDone[pgm.text] };

WriteTextBlock: PUBLIC ENTRY PROC [pgm: PGM, block: Block] =
	{ ENABLE UNWIND => NULL;
		AddToMList[pgm.writes, block] };

WriteControlBlock: PUBLIC ENTRY PROC [pgm: PGM, block: Block] =
	{ ENABLE UNWIND => NULL;
		AddToMList[pgm.deferred, block] };

GetFromWriteList: PUBLIC ENTRY PROC [pgm: PGM] RETURNS [Block] =
	{ ENABLE UNWIND => NULL;
		RETURN[GetFromMList[pgm.writes, pgm]] };

WritesDone: PUBLIC ENTRY PROC [pgm: PGM] = {
	ENABLE UNWIND => NULL;
	writes, deferred: MList;
	deferred ← pgm.deferred;
	IF deferred.first # NIL THEN -- move to writes
		IF (writes ← pgm.writes).first # NIL THEN
			BEGIN
			writes.last.next ← deferred.first;
			writes.last ← deferred.last;
			deferred.first ← deferred.last ← NIL;
			END
		ELSE
			BEGIN
			writes.first ← deferred.first;
			writes.last ← deferred.last;
			deferred.first ← deferred.last ← NIL;
			END;
	SetDone[pgm.writes] };

END.