-- BBActionImpl.mesa -- Russ Atkinson, November 1, 1982 3:42 pm DIRECTORY AMEvents USING [Event], BBAction USING [Action, ActionId, ActionKind, ActionRep, ActionStatus], BBZones USING [GetQuantizedZone]; BBActionImpl: CEDAR MONITOR IMPORTS BBZones EXPORTS BBAction = BEGIN OPEN BBAction, AMEvents; z: ZONE _ BBZones.GetQuantizedZone[]; LastId: ActionId _ 0; actionList: Action _ NIL; pendingCount: INT _ 0; globalChangeCount: INT _ 1; -- must stay > 0 change: CONDITION; Change: INTERNAL PROC = INLINE { globalChangeCount _ globalChangeCount + 1; IF globalChangeCount <= 0 THEN globalChangeCount _ 1; BROADCAST change }; ActionError: PUBLIC ERROR = CODE; -- error given when pre-condition not met NewAction: PUBLIC ENTRY PROC [event: Event, kind: ActionKind _ other] RETURNS [Action] = { -- creates a new action with new id ENABLE UNWIND => NULL; id: ActionId _ LastId _ LastId + 1; action: Action _ NIL; IF id <= 0 THEN ERROR; -- how did we get 2**31 actions? action _ z.NEW[ActionRep _ [id: id, rest: actionList, kind: kind, status: new, event: event, in: NIL, out: NIL]]; actionList _ action; RETURN [action]; }; WaitForDataGiven: PUBLIC ENTRY PROC [action: Action] RETURNS [REF] = { -- (PRE: status = busy OR status = other) -- suspends caller (as pendingIn) until data is given -- data is returned from the call when proceding -- (POST: status = busy) ENABLE UNWIND => NULL; IF action = NIL THEN RETURN WITH ERROR ActionError; SELECT action.status FROM busy, new => {}; ENDCASE => RETURN WITH ERROR ActionError; action.status _ pendingIn; pendingCount _ pendingCount + 1; Change[]; WHILE action.status # busy DO IF action.status = dead THEN RETURN WITH ERROR ABORTED; WAIT change; ENDLOOP; RETURN [action.in]; }; WaitForDataTaken: PUBLIC ENTRY PROC [action: Action, out: REF] = { -- (PRE: status = busy OR status = other) -- suspends caller (as pendingOut) until data (out) is taken -- when the data is taken, the process proceeds (busy) -- (POST: status = busy) ENABLE UNWIND => NULL; IF action = NIL THEN RETURN WITH ERROR ActionError; SELECT action.status FROM busy, new => {}; ENDCASE => RETURN WITH ERROR ActionError; action.out _ out; action.status _ pendingOut; pendingCount _ pendingCount + 1; Change[]; WHILE action.status # busy DO IF action.status = dead THEN RETURN WITH ERROR ABORTED; WAIT change; ENDLOOP; }; WaitForChange: PUBLIC ENTRY PROC [changeCount: INT] RETURNS [INT] = { -- suspends caller until the change count is different than -- the given changeCount, then returns the new change count -- the changeCount will change for every time a process becomes pending, -- busy, or dead; the change count may wrap around, but will always -- be > 0 ENABLE UNWIND => NULL; WHILE changeCount = globalChangeCount DO WAIT change; ENDLOOP; RETURN [globalChangeCount]; }; ForceChange: PUBLIC ENTRY PROC = { -- forces a change to the change count globalChangeCount _ globalChangeCount + 1; Change[]; }; GetChangeCount: PUBLIC PROC RETURNS [INT] = { -- get the current change count RETURN [globalChangeCount]; }; NextPendingAction: PUBLIC ENTRY PROC [action: Action] RETURNS [Action] = { -- (PRE: status # dead) -- returns the next eldest pending action -- returns NIL if no pending actions in list -- start with NIL to get most recent ENABLE UNWIND => NULL; IF action = NIL OR action.status = dead THEN {action _ actionList; IF action = NIL THEN RETURN [NIL]} ELSE action _ action.rest; FOR al: Action _ action, al.rest WHILE al # NIL DO SELECT al.status FROM pendingIn, pendingOut => RETURN [al]; dead => ERROR; -- HELP!!! ENDCASE; ENDLOOP; RETURN [NIL]; }; NextAction: PUBLIC ENTRY PROC [action: Action] RETURNS [Action] = { -- (PRE: status # dead) -- returns the next eldest action -- returns NIL if no actions in list -- start with NIL to get most recent ENABLE UNWIND => NULL; IF action = NIL OR action.status = dead THEN RETURN [actionList]; RETURN [action.rest]; }; GiveData: PUBLIC ENTRY PROC [action: Action, in: REF] = { -- (PRE: status = pendingIn) -- supplies the input data, allows the action to proceed -- (POST: status = busy) ENABLE UNWIND => NULL; IF action = NIL OR action.status # pendingIn THEN RETURN WITH ERROR ActionError; action.in _ in; action.status _ busy; pendingCount _ pendingCount - 1; Change[]; }; TakeData: PUBLIC ENTRY PROC [action: Action] RETURNS [REF] = { -- (PRE: status = pendingOut) -- obtains the output data, allows the action to proceed -- (POST: status = busy) ENABLE UNWIND => NULL; IF action = NIL OR action.status # pendingOut THEN RETURN WITH ERROR ActionError; action.status _ busy; pendingCount _ pendingCount - 1; Change[]; RETURN [action.out]; }; PeekData: PUBLIC ENTRY PROC [action: Action] RETURNS [REF] = { -- (PRE: status = pendingOut) -- obtains the output data, does not allow process to proceed -- (POST: status = pendingOut) ENABLE UNWIND => NULL; IF action = NIL OR action.status # pendingOut THEN RETURN WITH ERROR ActionError; RETURN [action.out]; }; Abort: PUBLIC ENTRY PROC [action: Action] = { -- (PRE: status # dead) -- aborts the pending action -- (aborts the process if status # other) -- (POST: status = dead, action not in list) ENABLE UNWIND => NULL; IF action = NIL OR action.status = dead THEN RETURN WITH ERROR ActionError; InternalRemove[action]; Change[]; }; InternalRemove: PROC [action: Action] = { al: Action _ actionList; -- trailing list node SELECT action.status FROM pendingIn, pendingOut => pendingCount _ pendingCount - 1; ENDCASE; action.status _ dead; IF al = action THEN { actionList _ al.rest; al.rest _ NIL; RETURN}; DO rest: Action _ al.rest; IF rest = NIL THEN ERROR; -- HELP!!! IF rest = action THEN { al.rest _ rest.rest; action.rest _ NIL; EXIT}; al _ rest; ENDLOOP; }; END. Κ―– "Mesa" style˜IprocšΌΟc@œΟk œ žœžœHžœ$žœžœžœ žœžœžœžœPžœžœžœœ ž œΟnœžœžœžœ6žœžœž œž œžœ*œŸ œž œžœ*žœ$œžœžœžœ?žœžœ žœžœ!œžœvžœžœ!žœŸœž œžœžœžœ *œ6œ1œœžœžœžœžœ žœžœžœžœžœžœžœžœžœžœžœdžœžœžœžœžœžœžœžœžœžœžœŸœž œžœžœ *œ=œ7œœžœžœžœžœ žœžœžœžœžœžœžœžœžœžœžœ{žœžœžœžœžœžœžœžœžœžœ Ÿ œž œžœžœžœžœ <œ<œIœEœ œžœžœžœžœ!žœžœžœžœ Ÿ œž œžœ 'œGŸœž œžœžœ  œžœ"Ÿœž œžœžœœ*œ-œ%œžœžœžœžœ žœžœžœ*žœ žœžœžœžœ žœ$žœžœžœžœ žœ žœžœžœ œžœ žœžœžœ Ÿ œž œžœžœœ"œ%œ%œžœžœžœžœ žœžœžœžœžœŸœž œžœžœ œ9œœžœžœžœžœ žœžœ"žœžœžœžœyŸœž œžœžœžœ œ9œœžœžœžœžœ žœžœ#žœžœžœžœ_žœŸœž œžœžœžœ œ>œœžœžœžœžœ žœžœ#žœžœžœžœžœŸœž œžœœœ*œ-œžœžœžœžœ žœžœžœžœžœžœBŸœžœ4œžœžœGžœ žœ žœ1žœ žœžœ'žœžœžœžœ œžœžœ3žœžœžœ žœ˜Š3—…—ŒA