-- Cedar Abstract Machine: interactions with client

-- AMEvents.mesa

-- Andrew Birrell November 1, 1982 8:58 am

DIRECTORY
AMModel  USING[ Section ],
Rope    USING[ ROPE ],
RTBasic   USING[ TV ],
WorldVM  USING[ Address, World ];

AMEvents: DEFINITIONS =

BEGIN

World: TYPE = WorldVM.World;

EventProc: TYPE = PROC[data: REF ANY, event: Event] RETURNS[outcome: Outcome];
-- "data" is as passed to "GetEvents".
-- An EventProc is called whenever something interesting happens
-- in the client world. Returning from the event allows the
-- client process to proceed, as specified by outcome.type:
-- quit => raise ABORTED in victim process
-- proceed => depending on the event.type:
-- breakpoints => execute saved byte and continue (result=NIL)
-- explicit call => return from the call (result=NIL)
-- signals => RESUME[result]
-- interrupt => continue (result=NIL)
-- retry => redo the call that caused specified local frame, with given arguments.
-- returnFrom => return control from specified local frame, with given result.
--
-- If the client world is not the local world, the client world
-- is frozen when the EventProc is called.
-- If the client world is booted, the event proc is called with
-- event.type = booted. When this happens, the debugger should
-- return from all previous events for this client (these returns
-- will have no effect on the client), and from the
-- "booted" event; the debugger should also arrange to flush
-- any cached client state. Outstanding calls to the client will
-- get the "Booted" error. Events that happen after the client has been
-- booted are delayed until previous events have returned.

Event: TYPE = REF EventRec;

Eventuality: TYPE = {
booted, break, call, signal, interrupt, unknown };

EventRec: TYPE = RECORD[
world: World, -- world requesting the debugger
process: RTBasic.TV, -- process requesting the debugger (compatible with AMProcess.Process)
frame: RTBasic.TV, -- local frame requesting the debugger
worry: BOOLEAN, -- TRUE => don't try to call client procedures --
detail: SELECT type: Eventuality FROM
booted =>  NULL, -- see comment under "EventProc".
break =>  [id: BreakID, clientData: REF ANY],
call =>   [msg: Rope.ROPE],
signal =>  [signal, args: RTBasic.TV ],
interrupt => NULL,
unknown => [why: Rope.ROPE], -- client bug; psbi and frame are valid.
ENDCASE];

Outcome: TYPE = RECORD[
SELECT type: * FROM
proceed =>  [result: RTBasic.TV],
quit =>   NULL,
retry =>   [frame, result: RTBasic.TV],
returnFrom => [frame, result: RTBasic.TV],
ENDCASE] ← [proceed[NIL]];

GetEvents: PROC[world: World, data: REF ANY, proc: EventProc];

StopEvents: PROC[world: World];

Debugging: --INFORMATIONAL-- SIGNAL;
Debugged: --INFORMATIONAL-- SIGNAL;
-- "Debugging" is raised in a process when it is about to be suspended for an event --
-- "Debugged" is raised in a process when the EventProc returns --
-- NOTE: These are raised as "informational" signals: clients may catch them, but must not
-- jump out of their catch-phrase. The signaller will resume them.

WorldSwapLocalSignals: PROC[BOOL];
-- Iff the last call of this procedure has argument "TRUE", signals in the local world
-- will be sent to the world-swap debugger instead of being reported locally.

CallDebugger: PROC[msg: Rope.ROPE];
-- Cause a local "call" event. If someone is handling local events, this will debug without
-- a world-swap, otherwise it will world-swap. Note that Pilot's Runtime.CallDebugger will
-- always cause a world-swap.



-- Breakpoints --


-- Multiple breaks at one place are illegal.

BreakID: TYPE = REF BreakRec;

BreakRec: TYPE;

BreakAt: PROC[world: World, section: AMModel.Section, clientData: REF ANY]
RETURNS[id: BreakID];
-- Sets breakpoint at beginning of the section (statement or procedure).

BreakAfter: PROC[world: World, section: AMModel.Section, clientData: REF ANY]
RETURNS[id: BreakID];
-- Sets breakpoint at end of the section (procedure only).

FrameBreak: PROC[gf: RTBasic.TV, pc: CARDINAL, clientData: REF ANY]
RETURNS[id: BreakID];
-- OctalBreak(1): Sets breakpoint at specified byte relative to "gf"s codebase --

SetBreak: PROC[world: World, addr: WorldVM.Address, pc: CARDINAL, clientData: REF ANY]
RETURNS[id: BreakID];
-- OctalBreak(2): Sets breakpoint at specified byte. "addr" is typically a codebase.

ClearBreak: PROC[id: BreakID];




-- Procedure invokation --


Apply: PROC[control, args: RTBasic.TV] RETURNS[result: RTBasic.TV];
-- "control" may have class "procedure", "signal" or "error",
-- corresponding to procedure calls or raising a
-- signal or error. Error's are treated the same as signals. This
-- may raise BadControlLink, BadArgType, BadResStack or Booted.

BadControlLink: ERROR; -- "control" had wrong type class
BadArgType: ERROR; -- type of "arg" # range of type of "control"
BadResStack: ERROR; -- result stack size was incorrect.
Booted: ERROR; -- client was booted instead of returning.

Kill: PROC[world: World];
-- Currently, calls TemporaryBooting.BootButton[] in client world.

END.