Last edited by
MBrown on November 21, 1982 3:40 pm
Hauser, March 28, 1985 9:48:22 am PST
Bob Hagmann May 2, 1988 2:29:54 pm PDT
YggCoordinatorRemoteCallsImpl:
CEDAR MONITOR
IMPORTS
YggImport,
YggDummyProcess
EXPORTS
YggCoordinatorInternal
= BEGIN
Conversation: TYPE = YggEnvironment.Conversation;
TransID: TYPE = YggEnvironment.TransID;
nProcessesCalling:
INT ← 0;
number of processes engaged in remote calls.
maxProcessesCalling: INT = 20;
nProcessesIdle:
INT ← 0;
number of processes waiting on parmsArrived condition.
maxProcessesIdle: INT = 10;
parmsTaken:
CONDITION;
A process calling PassParms waits here if parms is occupied on entry.
parmsArrived:
CONDITION;
A process calling GetParms waits here if parms is empty on entry.
Parms: TYPE = YggCoordinatorInternal.Parms;
parms: Parms;
parmsOccupied:
BOOL ←
FALSE;
If parmsOccupied, then parms is meaningful.
Results: TYPE = YggCoordinator.Results;
Statistics on module usage:
timesCalledPassParms: INT ← 0;
timesWaitedOnParmsTaken: INT ← 0;
Returns from the procs PassParms and GetParms below are strictly interleaved, due to
the single-element parms buffer.
PassParms:
PUBLIC
ENTRY
PROC [p: Parms] = {
ENABLE UNWIND => NULL;
timesCalledPassParms ← timesCalledPassParms + 1;
WHILE parmsOccupied
DO
timesWaitedOnParmsTaken ← timesWaitedOnParmsTaken + 1;
WAIT parmsTaken;
ENDLOOP;
parms ← p;
parmsOccupied ← TRUE;
IF nProcessesIdle > 0 THEN NOTIFY parmsArrived
ELSE
IF nProcessesCalling < maxProcessesCalling
THEN {
nProcessesCalling ← nProcessesCalling + 1;
TRUSTED {YggDummyProcess.Detach[FORK CallerProcess[]];};
};
};
This proc has had the RPC calls commented out
CallerProcess:
PROC [] = {
A caller process is outside the monitor except while calling GetParms.
parms: Parms;
conversation: YggDummyRPC.Conversation;
alpineTransMgr: REF ← NIL;
alpineTransMgr: AlpineTransMgrRpcControl.InterfaceRecord;
whyCallFailed: YggDummyRPC.CallFailure;
result: Results;
DO
TRUSTED {GetParms[@parms ! Stop => GOTO stop];};
conversation ← YggConversationTable.Fetch[parms.w.first.worker];
alpineTransMgr ← YggImport.GetTransMgrInterface[parms.w.first.worker];
IF conversation = NIL OR alpineTransMgr = NIL THEN {
result ← [bindingFailed, none[]];
}
ELSE {
ENABLE {
YggDummyRPC.CallFailed => CHECKED { whyCallFailed ← why; GOTO callFailed };
alpineTransMgr.Refused => { };
};
SELECT parms.proc FROM
prepare => {
state: YggEnvironment.WorkerState ← alpineTransMgr.WorkerPrepare[
conversation, parms.c.transID, parms.newTrans];
result ← [none, prepare[state]];
};
finish => {
alpineTransMgr.WorkerFinish[conversation, parms.c.transID, parms.requiredOutcome];
result ← [none, finish[]];
};
ENDCASE => ERROR;
EXITS
callFailed => {
SELECT whyCallFailed FROM
timeout, unbound => {
parms.w.first.worker.TransMgrInterfaceCallFailed[alpineTransMgr];
result ← [callFailed, none[]] };
busy => result ← [busy, none[]];
runtimeProtocol, stubProtocol => ERROR;
ENDCASE => ERROR;
};
};
alpineTransMgr ← NIL;
YggCoordinatorInternal.ReturnResults[parms.c, parms.w, result];
ENDLOOP;
};
GetParms:
ENTRY
PROC [parmsPtr:
--RESULT--
POINTER
TO Parms] =
INLINE {
! Stop -> calling process should die.
Pass a POINTER TO Parms instead of returning Parms, to avoid warnings about
potentially unsafe long REF-containing return record.
ENABLE UNWIND => nProcessesIdle ← nProcessesIdle - 1;
nProcessesCalling ← nProcessesCalling - 1;
WHILE
NOT parmsOccupied
DO
IF nProcessesIdle = maxProcessesIdle
THEN
no call to make and already enough idle processes, so terminate process.
RETURN WITH ERROR Stop;
nProcessesIdle ← nProcessesIdle + 1;
WAIT parmsArrived;
nProcessesIdle ← nProcessesIdle - 1;
ENDLOOP;
TRUSTED {parmsPtr^ ← parms;};
parmsOccupied ← FALSE;
nProcessesCalling ← nProcessesCalling + 1;
NOTIFY parmsTaken;
};
Stop: ERROR = CODE;
TRUSTED {
YggDummyProcess.DisableTimeout[@parmsTaken];
YggDummyProcess.EnableAborts[@parmsTaken];
YggDummyProcess.DisableTimeout[@parmsArrived];
YggDummyProcess.EnableAborts[@parmsArrived];
};
END.