CamelotImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Bob Hagmann May 4, 1989 8:58:50 am PDT
Handle calls to Camelot from Cedar.
Parameters to Camelot from C have IN, OUT, and INOUT parameters, at least when used with MIG. They are processed to (sometimes) change the real calling sequence to the C code. To find out what the real calling sequence for XX←someRoutine is, look in XX.h somewhere in the ~camelot directory subtree (e.g., ~camelot/camelot/alpha/include/camlib/ts.h).
I (rbh) think that the following is the algorithm to change parameters:
IN - no change (pass by copy)
OUT and INOUT - normally make it indirect, that is pass by address. However, for lists (I don't know how it guesses that something is a list) the argument is divided into two new arguments. The first one is passed by address and is of type of "pointer to the type of the argument". This is just the indirect passing of the argument. It has the same name as the argument. But then a pointer to an "unsigned int" (read CARD) is passed! This will get the number of items in the list. Its name is the argument's name with "Cnt" appended.
To see this in action, open ~camelot/alpha/src/lib/camlib/ds.h ( the same contents seem to be in ~camelot/alpha/include/camlib/ds.h) and look at the DS←Initialize call (you'll have to modify this name after the alpha release). Compare with ~camelot/alpha/src/lib/camlib/ds.defs -- which matches the documentation.
DIRECTORY
Camelot,
IO USING [int, PutFR, PutFR1],
Mach,
Rope USING [Cat, Fetch, Length, ROPE];
CamelotImpl: CEDAR PROGRAM
IMPORTS IO, Mach, Rope
EXPORTS Camelot
~ BEGIN
OPEN Camelot, Mach;
Exported recoverable storage management procedures
DSInitialize: PUBLIC PROC [dsPort: portT, raiseSignal: BOOL] RETURNS [serverID: serverIdT, tsPort, mPort, sPort: portT, sharedMemAddr: vmAddressT, seqDescList: ListOfSegmentDesc ← NIL, seqPortList: ListOfPorts, kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Initialize the data server.
innerDSInitialize: PROC [idsPort: portT, iserverID: POINTER TO serverIdT, itsPort, imPort, isPort: POINTER TO portT, isharedMemAddr: POINTER TO vmAddressT, iseqDescList: POINTER TO segmentDescListT, isegDescListCnt: POINTER TO INT, iseqPortList: POINTER TO portArrayT, isegPortListCnt: POINTER TO INT] RETURNS [kernReturnT]~ TRUSTED MACHINE CODE {
"<ds.h>.DS←Initialize"
};
ZsegDescList, DsegDescList: segmentDescListT ← NIL;
ZsegDescListCnt: INT ← -1;
ZsegPortList, DsegPortList: portArrayT ← NIL;
ZsegPortListCnt: INT ← -1;
initCode: INT ← SendErrorsStart;
initCode ← innerDSInitialize[dsPort, @serverID, @tsPort, @mPort, @sPort, @sharedMemAddr, @ZsegDescList, @ZsegDescListCnt, @ZsegPortList, @ZsegPortListCnt];
IF raiseSignal AND initCode # KernSuccess THEN SIGNAL MachCall[initCode, Rope.Cat["DS←Initialize failed; code = ", IO.PutFR1["%g", IO.int[initCode]]]];
IF ZsegDescListCnt # ZsegPortListCnt AND raiseSignal THEN SIGNAL MachCall[-1, IO.PutFR["DS←Initialize failed; different number of segments and ports = %g segments and %g ports", IO.int[ZsegDescListCnt], IO.int[ZsegPortListCnt]]];
IF ZsegDescListCnt > 0 THEN TRUSTED {
newItem: PROC RETURNS [lsd: ListOfSegmentDesc] ~ TRUSTED {
lsd ← LIST[[ZsegDescList.serverId, ZsegDescList.segmentId, ZsegDescList.logicalDisk, ZsegDescList.unused, ZsegDescList.highSize, ZsegDescList.lowSize]];
ZsegDescList ← ZsegDescList + UNITS[segmentDescT];
};
DsegDescList ← ZsegDescList;
seqDescList ← newItem[];
IF ZsegDescListCnt > 1 THEN {
lastItem: ListOfSegmentDesc ← seqDescList;
FOR item: INT IN [1..ZsegDescListCnt) DO
lastItem.rest ← newItem[];
lastItem ← lastItem.rest;
ENDLOOP;
};
[] ← vmDeallocate[targetTask: taskSelf[], address: LOOPHOLE[DsegDescList], size: BYTES[segmentDescT]*ZsegDescListCnt, raiseSignal: TRUE];
};
IF ZsegPortListCnt > 0 THEN TRUSTED {
newPort: PROC RETURNS [lp: ListOfPorts] ~ TRUSTED {
lp ← LIST[[ZsegPortList.portNumber]];
ZsegPortList ← ZsegPortList + UNITS[portT];
};
DsegPortList ← ZsegPortList;
seqPortList ← newPort[];
IF ZsegPortListCnt > 1 THEN {
lastPort: ListOfPorts ← seqPortList;
FOR item: INT IN [1..ZsegPortListCnt) DO
lastPort.rest ← newPort[];
lastPort ← lastPort.rest;
ENDLOOP;
};
[] ← vmDeallocate[targetTask: taskSelf[], address: LOOPHOLE[DsegPortList], size: BYTES[portT]*ZsegPortListCnt, raiseSignal: TRUE];
};
};
DSPinObject: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, size: uInt, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ {
Pin an object in preparation for modification.
innerDSPinObject: PROC [idsPort: portT, itid: tidT, ioptr: optrT, isize: uInt] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ds.h>.DS←PinObject"
};
pinCode: INT ← -1;
pinCode ← innerDSPinObject[dsPort, tid, optr, size];
IF raiseSignal AND pinCode # KernSuccess THEN SIGNAL MachCall[pinCode, Rope.Cat["DS←PinObject failed; code = ", IO.PutFR1["%g", IO.int[pinCode]]]];
RETURN[pinCode];
};
DSLogNewValue: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, newValue: pointerT, newValueCnt: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ {
Send a new value of an object to the log.
innerDSLogNewValue: PROC [idsPort: portT, itid: tidT, ioptr: optrT, inewValue: pointerT, inewValueCnt: INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ds.h>.DS←LogNewValue"
};
logCode: INT ← -1;
logCode ← innerDSLogNewValue[dsPort, tid, optr, newValue, newValueCnt];
IF raiseSignal AND logCode # KernSuccess THEN SIGNAL MachCall[logCode, Rope.Cat["DS←LogNewValue failed; code = ", IO.PutFR1["%g", IO.int[logCode]]]];
RETURN[logCode];
};
DSLogOldValueNewValue: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, oldValue: pointerT, oldValueCnt: INT, newValue: pointerT, newValueCnt: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ {
Send a new value of an object to the log.
innerDSLogOldValueNewValue: PROC [idsPort: portT, itid: tidT, ioptr: optrT, ioldValue: pointerT, ioldValueCnt: INT, inewValue: pointerT, inewValueCnt: INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ds.h>.DS←LogOldValueNewValue"
};
logCode: INT ← -1;
logCode ← innerDSLogOldValueNewValue[dsPort, tid, optr, oldValue, oldValueCnt, newValue, newValueCnt];
IF raiseSignal AND logCode # KernSuccess THEN SIGNAL MachCall[logCode, Rope.Cat["DS←LogOldValueNewValue failed; code = ", IO.PutFR1["%g", IO.int[logCode]]]];
RETURN[logCode];
};
DSPrepare: PUBLIC PROC [dsPort: portT, topBTid: btidT, prepareData: pointerT, prepareDataCnt: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ {
Send a new value of an object to the log.
innerDSPrepare: PROC [idsPort: portT, itopBTid: btidT, iprepareData: pointerT, iprepareDataCnt: INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ds.h>.DS←Prepare"
};
prepareCode: INT ← -1;
prepareCode ← innerDSPrepare[dsPort, topBTid, prepareData, prepareDataCnt];
IF prepareCode # KernSuccess THEN SIGNAL MachCall[prepareCode, Rope.Cat["DS←Prepare failed; code = ", IO.PutFR1["%g", IO.int[prepareCode]]]];
RETURN[prepareCode];
};
DSQInit: PUBLIC PROC [sharedMemAddr: Mach.vmAddressT] ~ {
Send a new value of an object to the log.
innerDSQInit: PROC [XsharedMemAddr: Mach.vmAddressT] ~ TRUSTED MACHINE CODE {
"<ds.h>.Dsq←Init"
};
innerDSQInit[sharedMemAddr];
};
DSQPreflush: PUBLIC PROC [dsPort: Mach.portT, optr: optrT, sizeInBytes: uInt] ~ {
Preflush some dirty memory.
ERROR; -- preflush should only be used in SunOS emulation for now
};
Exported transaction management procedures
camelotStringTFromRope: PROC [name: Rope.ROPE] RETURNS [camelotString: REF camelotStringT] ~ {
oNSize: INT ← 0;
camelotString ← NEW[camelotStringT];
oNSize ← Rope.Length[name];
IF oNSize >= Camelot.CAMELOTSTRINGLENGTH THEN ERROR;
FOR index: INT IN [0..oNSize) DO
camelotString[index] ← Rope.Fetch[name, index];
ENDLOOP;
camelotString[oNSize] ← 0C;
};
TAAddApplication: PUBLIC PROC [tPort: portT, atPort: portT, authName: Rope.ROPE, raiseSignal: BOOL] RETURNS [applicationID: applicationIdT, taPort: portT, kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Initialize an application to the transaction manager.
innerTAAddApplication: PROC [itPort: portT, iatPort: portT, iauthName: POINTER TO camelotStringT, iapplicationID: POINTER TO applicationIdT, itaPort: POINTER TO portT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ta.h>.TA�pplication"
};
camString: REF camelotStringT;
camString ← camelotStringTFromRope[authName];
kernCode ← innerTAAddApplication[tPort, atPort, LOOPHOLE[camString], @applicationID, @taPort];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TA�pplication failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
TABegin: PUBLIC PROC [taPort: portT, parentTid: tidT, transType: transactionTypeT, raiseSignal: BOOL] RETURNS [newTid: tidT, kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Start a new transaction.
innerTABegin: PROC [taPortInner: portT, parentTidInner: tidT, transTypeInner: transactionTypeT, newTidInner: POINTER TO tidT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ta.h>.TA�gin"
};
kernCode ← innerTABegin[taPort, parentTid, transType, @newTid];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TA�gin failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
TAEnd: PUBLIC PROC [taPort: portT, tid: tidT, protocolType: protocolTypeT, raiseSignal: BOOL] RETURNS [timestamp: timestampT, status: INT, kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Try to commit a transaction.
innerTAEnd: PROC [taPortInner: portT, tidInner: tidT, protocolTypeInner: protocolTypeT, timestampInner: POINTER TO timestampT, statusInner: POINTER TO INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ta.h>.TA𡤎nd"
};
kernCode ← innerTAEnd[taPort, tid, protocolType, @timestamp, @status];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TA𡤎nd failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
TAKill: PUBLIC PROC [taPort: portT, tid: tidT, status: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Try to abort a transaction.
innerTAKill: PROC [taPortInner: portT, tidInner: tidT, statusInner: INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ta.h>.TA←Kill"
};
kernCode ← innerTAKill[taPort, tid, status];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TA←Kill failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
TSJoin: PUBLIC PROC [tsPort: portT, tid: tidT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT ← -1] ~ {
Join a server to a transaction.
innerTSJoin: PROC [tsPortInner: portT, tidInner: tidT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ts.h>.TS←Join"
};
kernCode ← innerTSJoin[tsPort, tid];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TA←Join failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
TDAddDataServer: PUBLIC PROC [tdPort: portT, serverID: serverIdT, sendPort: portT, raiseSignal: BOOL] RETURNS [rcvPort: portT, kernCode: Mach.kernReturnT ← -1] ~ TRUSTED {
Join a server to a transaction.
Initialize the data server to the transaction manager.
innerTDAddDataServer: PROC [itdPort: portT, iserverID: serverIdT, isendPort: portT, ircvPort: POINTER TO portT] RETURNS [kernReturnT]~ TRUSTED MACHINE CODE {
"<td.h>.TD�taServer"
};
kernCode ← innerTDAddDataServer[tdPort, serverID, sendPort, @rcvPort];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["TD�taServer failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
Name server
objectNameTFromRope: PROC [name: Rope.ROPE] RETURNS [objectNameString: REF objectNameT] ~ {
oNSize: INT ← 0;
objectNameString ← NEW[objectNameT];
oNSize ← Rope.Length[name];
IF oNSize >= ObjectNameLength THEN ERROR;
FOR index: INT IN [0..oNSize) DO
objectNameString[index] ← Rope.Fetch[name, index];
ENDLOOP;
objectNameString[oNSize] ← 0C;
};
CSSignIn: PUBLIC PROC [nameServerPort: Mach.portT, name: Rope.ROPE, port: Mach.portT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT] ~ {
Sign in as a data server.
innerCSSignIn: PROC [inameServerPort: Mach.portT, iname: POINTER TO objectNameT, iport: Mach.portT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<cs.h>.CS←SignIn"
};
objectNameString: REF objectNameT;
objectNameString ← objectNameTFromRope[name];
kernCode ← innerCSSignIn[nameServerPort, LOOPHOLE[objectNameString], port];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["CS←SignIn failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
CSSignOut: PUBLIC PROC [nameServerPort: Mach.portT, name: Rope.ROPE, port: Mach.portT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT] ~ {
Sign out as a data server.
innerCSSignOut: PROC [inameServerPort: Mach.portT, iname: POINTER TO objectNameT, iport: Mach.portT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<cs.h>.CS←SignOut"
};
objectNameString: REF objectNameT;
objectNameString ← objectNameTFromRope[name];
kernCode ← innerCSSignOut[nameServerPort, LOOPHOLE[objectNameString], port];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["CS←SignOut failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
innerLookup: PROC [nameServerPort: Mach.portT, name: Rope.ROPE, site: Rope.ROPE, numberWanted: INT, maxSeconds: INT, raiseSignal: BOOL, cs: BOOL] RETURNS [portList: Mach.ListOfPorts, kernCode: Mach.kernReturnT] ~ {
Lookup for servers.
innerCSLookup: PROC [inameServerPort: Mach.portT, iname: POINTER TO objectNameT, isite: POINTER TO objectNameT, inumberWanted: INT, imaxSeconds: INT, iportList: POINTER TO portArrayT, iportListCnt: POINTER TO INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<cs.h>.CS←Lookup"
};
innerCALookup: PROC [inameServerPort: Mach.portT, iname: POINTER TO objectNameT, isite: POINTER TO objectNameT, inumberWanted: INT, imaxSeconds: INT, iportList: POINTER TO portArrayT, iportListCnt: POINTER TO INT] RETURNS [kernReturnT] ~ TRUSTED MACHINE CODE {
"<ca.h>.CA←Lookup"
};
objectNameString: REF objectNameT;
siteString: REF objectNameT;
ZportList, DportList: portArrayT ← NIL;
ZportListCnt: INT ← -1;
objectNameString ← objectNameTFromRope[name];
siteString ← objectNameTFromRope[site];
IF cs THEN TRUSTED {
kernCode ← innerCSLookup[nameServerPort, LOOPHOLE[objectNameString], LOOPHOLE[siteString], numberWanted, maxSeconds, @ZportList, @ZportListCnt];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["CS←Lookup failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
}
ELSE TRUSTED {
kernCode ← innerCALookup[nameServerPort, LOOPHOLE[objectNameString], LOOPHOLE[siteString], numberWanted, maxSeconds, @ZportList, @ZportListCnt];
IF raiseSignal AND kernCode # KernSuccess THEN SIGNAL MachCall[kernCode, Rope.Cat["CA←Lookup failed; code = ", IO.PutFR1["%g", IO.int[kernCode]]]];
};
IF ZportListCnt > 0 THEN TRUSTED {
newPort: PROC RETURNS [lp: ListOfPorts] ~ TRUSTED {
lp ← LIST[[ZportList.portNumber]];
ZportList ← ZportList + UNITS[portT];
};
DportList ← ZportList;
portList ← newPort[];
IF ZportListCnt > 1 THEN {
lastPort: ListOfPorts ← portList;
FOR item: INT IN [1..ZportListCnt) DO
lastPort.rest ← newPort[];
lastPort ← lastPort.rest;
ENDLOOP;
};
[] ← vmDeallocate[targetTask: taskSelf[], address: LOOPHOLE[DportList], size: BYTES[portT]*ZportListCnt, raiseSignal: TRUE];
};
};
CSLookup: PUBLIC PROC [nameServerPort: Mach.portT, name: Rope.ROPE, site: Rope.ROPE, numberWanted: INT, maxSeconds: INT, raiseSignal: BOOL] RETURNS [portList: Mach.ListOfPorts, kernCode: Mach.kernReturnT] ~ {
Lookup for servers.
[portList, kernCode] ← innerLookup[nameServerPort, name, site, numberWanted, maxSeconds, raiseSignal, TRUE];
};
CALookup: PUBLIC PROC [nameServerPort: Mach.portT, name: Rope.ROPE, site: Rope.ROPE, numberWanted: INT, maxSeconds: INT, raiseSignal: BOOL] RETURNS [portList: Mach.ListOfPorts, kernCode: Mach.kernReturnT] ~ {
Lookup for applications.
[portList, kernCode] ← innerLookup[nameServerPort, name, site, numberWanted, maxSeconds, raiseSignal, FALSE];
};
Exported lock procedures (if we are going to use CamLib)
Lock: PUBLIC PROC [tid: tidT, lockName: LockName, lockMode: lockModeT] ~ {
Obtain the lock for this transaction.
innerLOCK: PROC [lockNameInner: LockName, lockModeInner: lockModeT] ~ TRUSTED MACHINE CODE {
"LOCK"
};
MakeThisThreadPartOfTransaction[tid];
innerLOCK[lockName, lockMode];
};
TryLock: PUBLIC PROC [tid: tidT, lockName: LockName, lockMode: lockModeT] ~ {
Obtain the lock for this transaction if immediately available.
innerTryLock: PROC [lockNameInner: LockName, lockModeInner: lockModeT] ~ TRUSTED MACHINE CODE {
"TRY←LOCK"
};
MakeThisThreadPartOfTransaction[tid];
innerTryLock[lockName, lockMode];
};
Unlock: PUBLIC PROC [tid: tidT, lockName: LockName] ~ {
Release lock for this transaction.
innerUnlock: PROC [lockNameInner: LockName] ~ TRUSTED MACHINE CODE {
"UNLOCK"
};
MakeThisThreadPartOfTransaction[tid];
innerUnlock[lockName];
};
DemoteLock: PUBLIC PROC [tid: tidT, lockName: LockName] ~ {
Demote write lock to a read lock for this transaction.
innerDemoteLock: PROC [lockNameInner: LockName] ~ TRUSTED MACHINE CODE {
"UNLOCK"
};
MakeThisThreadPartOfTransaction[tid];
innerDemoteLock[lockName];
};
Initialization
END.