-- StallWatcherImpl.mesa
-- Russ Atkinson, November 1, 1982 3:54 pm

DIRECTORY
AMBridge USING [TVToCardinal],
BBAction USING
[Action, ActionId, NextPendingAction, WaitForChange],
Process USING [Detach],
StallWatcher,
ViewersStallNotifier USING [NotifyProcessStalled];

StallWatcherImpl: CEDAR PROGRAM
IMPORTS AMBridge, BBAction, Process, ViewersStallNotifier
EXPORTS StallWatcher
SHARES ViewersStallNotifier
= BEGIN OPEN StallWatcher;

RegisterStallNotifier: PUBLIC PROC
[p: StallNotifyProcType, data: REFNIL] = TRUSTED {
-- this proc registers a notifier to be called whenever a process
-- "stalls" due to a breakpoint or uncaught signal in BugBane
-- each call to RegisterStallNotifier will fork a new watchdog
-- process, so don't be greedy!
Process.Detach[FORK StallWatchProcess[p, data]];
};

StallWatchProcess: PROC [p: StallNotifyProcType, data: REF] = {
-- this proc watches the world to find all stalled processes
-- whenever there is a change, the current list is reported to the user
-- by calling p[list,data]
count: INT ← 0;
lastId: BBAction.ActionId ← 0;
DO
maxId: BBAction.ActionId ← lastId;
count ← BBAction.WaitForChange[count];
-- second, add new pending actions to the list
FOR act: BBAction.Action ← BBAction.NextPendingAction[NIL],
BBAction.NextPendingAction[act] WHILE act # NIL DO
IF act.id <= lastId THEN LOOP;
IF act.kind # break AND act.kind # signal THEN LOOP;
p[act, data];
IF act.id > maxId THEN maxId ← act.id;
ENDLOOP;
lastId ← maxId;
ENDLOOP;
};

CallOut: StallNotifyProcType = TRUSTED {
psb: CARDINAL ← AMBridge.TVToCardinal[action.event.process];
ViewersStallNotifier.NotifyProcessStalled
[LOOPHOLE[psb], -- CROCK!
IF action.kind = break THEN $Break ELSE $Signal];
};

RegisterStallNotifier[CallOut, NIL];

END.