-- SchedulerImpl.mesa -- last edited: 25-Nov-81 9:47:59 DIRECTORY Scheduler, Process, RandomCard; SchedulerImpl: MONITOR IMPORTS Process, RandomCard EXPORTS Scheduler = { currentProcessSize: CARDINAL; Pool: TYPE = RECORD [ cond: CONDITION, free: POINTER TO Pool]; MaxCond: CARDINAL = 100; ConditionPool: ARRAY [0..MaxCond) OF Pool; FreePool: POINTER TO Pool; UniversalTime: LONG CARDINAL; TimeQueue: TYPE = RECORD [ next: REF TimeQueue, time: LONG CARDINAL, size: CARDINAL, events: POINTER TO Pool]; AllTime: REF TimeQueue ← NIL; Fork: PUBLIC PROC[newProcess: PROC] RETURNS[PROCESS] = { p: PROCESS; IncCurrent[]; p ← FORK newProcess[]; Process.Yield[]; RETURN[p] }; Join: PUBLIC PROC[process: PROCESS] = { [] ← JOIN process; }; ProcessEnd: PUBLIC ENTRY PROC = { DecCurrentInternal[]; IF AllTime = NIL THEN RETURN; IF ~CurrentMore[] THEN NotifyEarliest[]; }; GetProcessSize: PUBLIC ENTRY PROC RETURNS[CARDINAL] = { RETURN[currentProcessSize]}; Delay: PUBLIC PROC [max: CARDINAL] = { DelayInternal[max]; Process.Yield[]; }; RandomDelay: PUBLIC PROC [min, max: CARDINAL] = { DelayInternal[RandomCard.Choose[min, max]] }; DelayInternal: ENTRY PROC [max: CARDINAL] = { index: CARDINAL; startTime: LONG CARDINAL ← UniversalTime+max; DecCurrentInternal[]; IF currentProcessSize#0 THEN { PutThisProcess[startTime]; RETURN}; IF startTime<Earliest[] THEN { currentProcessSize ← currentProcessSize+1; UniversalTime ← startTime; RETURN}; IF startTime>Earliest[] THEN { NotifyEarliest[]; PutThisProcess[startTime]; RETURN}; index ← RandomCard.Choose[0,EarliestSize[]]; IF index=0 THEN { currentProcessSize ← currentProcessSize+1; UniversalTime ← startTime; RETURN}; NotifyEarliestAt[index-1]; PutThisProcess[startTime] }; StandardDelay: PUBLIC PROC = { DelayInternal[RandomCard.Choose[1, 2]]; Process.Yield[]; }; NotifyQueue: PUBLIC ENTRY PROC = { IF currentProcessSize = 0 THEN ERROR; currentProcessSize ← currentProcessSize-1; IF AllTime=NIL THEN RETURN; IF currentProcessSize = 0 THEN NotifyEarliest[]; }; IncCurrent: PUBLIC PROC = { IncCurrentEntry[]; Process.Yield[]}; -- Current process size manipulation CurrentMore: INTERNAL PROC RETURNS[BOOLEAN] = { RETURN[currentProcessSize#0] }; DecCurrentInternal: INTERNAL PROC = { IF currentProcessSize = 0 THEN ERROR; currentProcessSize ← currentProcessSize-1; }; IncCurrentEntry: ENTRY PROC = { currentProcessSize ← currentProcessSize+1; }; -- Time queue manipulation Earliest: INTERNAL PROC RETURNS[LONG CARDINAL] = { IF AllTime=NIL THEN RETURN[LAST[LONG CARDINAL]]; RETURN[AllTime.time]}; EarliestSize: INTERNAL PROC RETURNS[CARDINAL] = { RETURN[AllTime.size]}; NotifyEarliest: INTERNAL PROC = { index: CARDINAL ← RandomCard.Choose[0,AllTime.size-1]; NotifyEarliestAt[index] }; NotifyEarliestAt: INTERNAL PROC [index: CARDINAL] = { eventQueue: POINTER TO Pool ← AllTime.events; back: POINTER TO Pool; currentProcessSize ← currentProcessSize+1; UniversalTime ← AllTime.time; IF index=0 THEN { AllTime.events ← eventQueue.free; NOTIFY eventQueue.cond; eventQueue.free ← FreePool; FreePool ← eventQueue; IF AllTime.size=1 THEN { time: REF TimeQueue ← AllTime; AllTime ← AllTime.next} ELSE AllTime.size ← AllTime.size-1; RETURN}; THROUGH [0..index-1) DO eventQueue ← eventQueue.free; ENDLOOP; back ← eventQueue; eventQueue ← eventQueue.free; NOTIFY eventQueue.cond; back.free ← eventQueue.free; eventQueue.free ← FreePool; FreePool ← eventQueue; AllTime.size ← AllTime.size-1; }; PutToQueue: PROC[newProcess: PROC] = { LockAndPutThisProcess[UniversalTime]; newProcess[] }; LockAndPutThisProcess: ENTRY PROC[startTime: LONG CARDINAL] = { PutThisProcess[startTime] }; PutThisProcess: INTERNAL PROC[startTime: LONG CARDINAL] = { timeQueue: REF TimeQueue; {IF AllTime=NIL OR AllTime.time>startTime THEN GOTO PutFront; timeQueue ← AllTime; IF AllTime.time=startTime THEN GOTO PutHere; FOR timeQueue← AllTime, timeQueue.next UNTIL timeQueue.next=NIL DO IF timeQueue.time=startTime THEN GOTO PutHere; IF timeQueue.next.time>startTime THEN GOTO PutAfter REPEAT FINISHED => IF timeQueue.time=startTime THEN GOTO PutHere ELSE GOTO PutAfter ENDLOOP; EXITS PutFront => { time: REF TimeQueue ← NEW[TimeQueue]; event: POINTER TO Pool; time.next ← AllTime; AllTime ← time; time.time ← startTime; time.size ← 1; time.events ← FreePool; IF FreePool = NIL THEN ERROR; FreePool ← FreePool.free; time.events.free ← NIL; event ← time.events; WAIT event.cond}; PutHere => { pool: POINTER TO Pool ← FreePool; IF FreePool=NIL THEN ERROR; FreePool ← FreePool.free; pool.free ← timeQueue.events; timeQueue.events ← pool; timeQueue.size ← timeQueue.size+1; WAIT pool.cond}; PutAfter => { time: REF TimeQueue ← NEW[TimeQueue]; event: POINTER TO Pool; time.next ← timeQueue.next; timeQueue.next ← time; time.time ← startTime; time.size ← 1; time.events ← FreePool; IF FreePool = NIL THEN ERROR; FreePool ← FreePool.free; time.events.free ← NIL; event ← time.events; WAIT event.cond}; }}; -- Main part [] ← RandomCard.InitRandom[seed: -1]; FreePool ← @ConditionPool[0]; {i: CARDINAL; FOR i IN [0..MaxCond) DO Process.DisableTimeout[@ConditionPool[i].cond]; ENDLOOP; FOR i IN [0..MaxCond-1) DO ConditionPool[i].free ← @ConditionPool[i+1] ENDLOOP}; ConditionPool[MaxCond-1].free ← NIL; UniversalTime ← 0; currentProcessSize ← 0; }.