<> <> <> <> <<>> <> <<>> DIRECTORY BasicTime USING [GetClockPulses, MicrosecondsToPulses, Pulses], Process USING [Pause, Yield], Xl USING [TQ], XlTQPrivate USING [TQRec, Job], XTkFastAccessPrivate; XTkFastAccessPrivateImpl: CEDAR MONITOR IMPORTS BasicTime, Process EXPORTS Xl<>, XTkFastAccessPrivate ~ BEGIN OPEN XTkFastAccessPrivate; <<>> TQRep: PUBLIC TYPE = XlTQPrivate.TQRec; TQ: TYPE = REF TQRep; pieceSize: INT = 8; TQSet: TYPE = REF TQSetRep; TQSetRep: PUBLIC TYPE = RECORD [ pieces: ARRAY [0..pieceSize) OF Xl.TQ ¬ ALL[NIL], --members of set state: ARRAY [0..pieceSize) OF XlTQPrivate.Job ¬ ALL[NIL], --previous state clientAccessible: BOOL ¬ FALSE, nextSet: TQSet ¬ NIL --rarely used as sets are typically quite small ]; freeList: TQSet ¬ NIL; --MONITORED New: ENTRY PROC [link: TQSet ¬ NIL] RETURNS [s: TQSet] = { s ¬ freeList; IF s#NIL THEN freeList ¬ s.nextSet ELSE s ¬ NEW[TQSetRep]; s.clientAccessible ¬ TRUE; s.nextSet ¬ link }; Free: ENTRY PROC [s: TQSet] = { s.pieces ¬ ALL[NIL]; s.state ¬ ALL[NIL]; s.nextSet ¬ freeList; freeList ¬ s }; Include: PUBLIC PROC [set: TQSet, tq: Xl.TQ] RETURNS [s: TQSet] = { <> IF set=NIL THEN set ¬ New[]; s ¬ set; IF ~s.clientAccessible THEN ERROR; --protects further refs to freed sets DO FOR idx: [0..pieceSize) IN [0..pieceSize) DO IF s.pieces[idx]=tq THEN RETURN; IF s.pieces[idx]=NIL THEN {s.pieces[idx] ¬ tq; RETURN}; ENDLOOP; s ¬ New[s]; ENDLOOP }; limit: BasicTime.Pulses ¬ BasicTime.MicrosecondsToPulses[5000000]; Synchronize: PUBLIC PROC [set: TQSet] = { Init: PROC [set: TQSet] = { <> WHILE set#NIL DO set.clientAccessible ¬ FALSE; FOR i: [0..pieceSize) IN [0..pieceSize) DO t: TQ ¬ set.pieces[i]; IF t#NIL THEN { IF t.this=NIL AND t.lockCount=0 <> THEN set.pieces[i] ¬ NIL ELSE set.state[i] ¬ t.this; }; ENDLOOP; set ¬ set.nextSet; ENDLOOP; }; Check: PROC [set: TQSet] RETURNS [mustWait: BOOL ¬ FALSE] = { <> WHILE set#NIL DO FOR i: [0..pieceSize) IN [0..pieceSize) DO t: TQ ¬ set.pieces[i]; IF t#NIL THEN { IF t.this=NIL AND t.lockCount=0 <> THEN set.pieces[i] ¬ NIL ELSE { IF set.state[i] # t.this THEN set.pieces[i] ¬ NIL ELSE {mustWait ¬ TRUE; RETURN} }; }; ENDLOOP; set ¬ set.nextSet; ENDLOOP; }; IF set#NIL THEN { pulses: BasicTime.Pulses; Init[set]; Process.Yield[]; IF Check[set].mustWait THEN { start: BasicTime.Pulses ¬ BasicTime.GetClockPulses[]; DO Process.Pause[5]; Process.Pause[5]; IF ~Check[set].mustWait THEN RETURN; pulses ¬ BasicTime.GetClockPulses[]; IF (pulses-start <>) > limit THEN EXIT; <> ENDLOOP }; Free[set]; --return only the first piece; thats ok since sets are normally small }; }; END.