DIRECTORY BasicTime, Camelot, CamelotRecoverable, CountedVM, File, FileStream, FS, FSBackdoor, IO, Mach, PBasics, Process, RedBlackTree, Rope, YggDID, YggDIDPrivate, YggDIDMap, YggDIDMapPrivate, YggdrasilInit, YggLock, YggLog, YggLogControl, YggFixedNames, YggEnvironment, YggFile, YggFileStream, YggIndexMaint, YggInternal, YggMonitoringLog, YggRep, YggRestartFile, YggTransaction, VM; MachCamelotEmulationForSunOS: CEDAR MONITOR IMPORTS BasicTime, CamelotRecoverable, CountedVM, FS, PBasics, Process, RedBlackTree, YggLog, YggLogControl, YggdrasilInit, YggRestartFile, YggTransaction, VM EXPORTS Camelot, Mach, YggdrasilInit, YggMonitoringLog = BEGIN OPEN Camelot, Mach; ROPE: TYPE = Rope.ROPE; notice: PUBLIC YggMonitoringLog.ProcsRecord _ []; DID: PUBLIC TYPE ~ REF DIDRep; DIDRep: PUBLIC TYPE ~ YggDIDPrivate.DIDRep; Document: TYPE = REF DocumentRep; DocumentRep: PUBLIC TYPE = YggDIDMapPrivate.DocumentRep; NextTransCount: CARD _ 10001; CheckPointEphocNumber: CARD _ 1; MachCall: PUBLIC SIGNAL [errorCode: msgReturnT, explanation: Rope.ROPE] = CODE; MachAnomaly: PUBLIC SIGNAL [explanation: Rope.ROPE] = CODE; taskSelf: PUBLIC PROC RETURNS [targetTask: taskT] ~ { targetTask _ [1]; }; taskNotify: PUBLIC PROC RETURNS [notifyPort: portT] ~ { notifyPort _ [2]; }; vmAllocate: PUBLIC PROC [targetTask: vmTaskT, address: vmAddressT, size: vmSizeT, anywhere: BOOL,raiseSignal: BOOL] RETURNS [mappedAddress: vmAddressT _ 0, kernCode: kernReturnT _ -1] ~ TRUSTED { interval: VM.Interval; interval _ VM.Allocate[count: VM.PagesForBytes[size]]; mappedAddress _ LOOPHOLE[VM.AddressForPageNumber[interval.page]]; kernCode _ KernSuccess; }; VMAllocList: LIST OF AllocItem _ NIL; AllocItem: TYPE = RECORD [ pagingObject: pagingObjectT, offset: vmOffsetT, size: vmSizeT, mappedAddress: vmAddressT, cvmHandle: CountedVM.Handle, allocated: BOOL _ TRUE, dirtied: BOOL _ FALSE, timeOfLastDirty: BasicTime.GMT _ BasicTime.earliestGMT, timeOfLastWrite: BasicTime.GMT _ BasicTime.earliestGMT, dirtiedDuringEphoc: CARD _ 0, ephocOfLastWrite: CARD _ 0, ownedByCheckpointProcess: BOOL _ FALSE ]; vmAllocateWithPager: PUBLIC PROC [targetTask: vmTaskT, address: vmAddressT, size: vmSizeT, anywhere: BOOL, pagingObject: pagingObjectT, offset: vmOffsetT, raiseSignal: BOOL] RETURNS [mappedAddress: vmAddressT _ 0, kernCode: kernReturnT _ -1] ~ TRUSTED { [mappedAddress, kernCode] _ vmAllocateWithPagerInner[size, pagingObject, offset, FALSE]; }; vmAllocateWithPagerInner: ENTRY PROC [size: vmSizeT, pagingObject: pagingObjectT, offset: vmOffsetT, zeroFillOnly: BOOL] RETURNS [mappedAddress: vmAddressT _ 0, kernCode: kernReturnT _ -1] ~ TRUSTED { loai: LIST OF AllocItem; cvmHandle: CountedVM.Handle; pages: INT _ -1; firstPage: INT _ -1; FOR loai _ VMAllocList, loai.rest UNTIL loai = NIL DO IF loai.first.pagingObject # pagingObject THEN LOOP; IF loai.first.offset > offset+size THEN LOOP; IF offset > loai.first.offset+loai.first.size THEN LOOP; IF loai.first.offset = offset AND loai.first.size = size THEN { IF loai.first.allocated THEN ERROR; EXIT; }; ENDLOOP; cvmHandle _ CountedVM.Allocate[words:size/BYTES[WORD]]; mappedAddress _ LOOPHOLE[cvmHandle.pointer]; pages _ FS.PagesForBytes[size]; IF INT[size] # FS.BytesForPages[pages] THEN ERROR; firstPage _ FS.PagesForBytes[offset]; IF INT[offset] # FS.BytesForPages[firstPage] THEN ERROR; IF loai = NIL THEN { loai _ VMAllocList _ CONS[[pagingObject: pagingObject, offset: offset, size: size, mappedAddress: mappedAddress, cvmHandle: cvmHandle], VMAllocList]; }; IF zeroFillOnly THEN { where: LONG POINTER _ LOOPHOLE[mappedAddress]; nWordsLeft: CARD32 _ size/PBasics.bytesPerWord; WHILE nWordsLeft > 0 DO fillThisTime: CARD32 _ MIN[nWordsLeft, 10000]; PBasics.Fill[where: where, nWords: fillThisTime, value: 0]; where _ where + fillThisTime * UNITS[PBasics.Word]; nWordsLeft _ nWordsLeft - fillThisTime; ENDLOOP; loai.first.allocated _ FALSE; loai.first.mappedAddress _ mappedAddress; loai.first.cvmHandle _ cvmHandle; } ELSE { IF loai.first.cvmHandle = NIL THEN { FS.Read[file: FileForPagingObject[loai.first.pagingObject], from: firstPage, nPages: pages, to: LOOPHOLE[mappedAddress]]; loai.first.allocated _ TRUE; loai.first.mappedAddress _ mappedAddress; loai.first.cvmHandle _ cvmHandle; }; }; kernCode _ KernSuccess; }; vmDeallocate: PUBLIC ENTRY PROC [targetTask: vmTaskT, address: vmAddressT, size: vmSizeT, raiseSignal: BOOL] RETURNS [kernCode: kernReturnT _ -1] ~ { FOR loai: LIST OF AllocItem _ VMAllocList, loai.rest UNTIL loai = NIL DO IF loai.first.mappedAddress = address THEN { pages: INT _ -1; firstPage: INT _ -1; IF size # loai.first.size THEN ERROR; pages _ FS.PagesForBytes[loai.first.size]; firstPage _ FS.PagesForBytes[loai.first.offset]; FS.Write[file: FileForPagingObject[loai.first.pagingObject], to: firstPage, nPages: pages, from: LOOPHOLE[address]]; loai.first.allocated _ FALSE; loai.first.mappedAddress _ 0; loai.first.cvmHandle _ NIL; EXIT; }; ENDLOOP; }; noteDirtyOfMemory: ENTRY PROC [optr: optrT, size: uInt] ~ { FOR loai: LIST OF AllocItem _ VMAllocList, loai.rest UNTIL loai = NIL DO IF (loai.first.offset > optr.lowOffset + size) AND (loai.first.offset + loai.first.size < optr.lowOffset) THEN { } ELSE { loai.first.dirtied _ TRUE; loai.first.timeOfLastDirty _ BasicTime.Now[]; loai.first.dirtiedDuringEphoc _ CheckPointEphocNumber }; REPEAT FINISHED => ERROR; ENDLOOP; }; msgSend: PUBLIC PROC [header: REF msgHeaderT, option: msgOptionT, timeout: INT, raiseSignal: BOOL] RETURNS [msgCode: msgReturnT _ -1] ~ { ERROR; }; msgReceive: PUBLIC PROC [header: REF msgHeaderT, option: msgOptionT, timeout: INT, raiseSignal: BOOL] RETURNS [msgCode: msgReturnT _ -1] ~ { DO Process.Pause[33]; ENDLOOP; }; nameServerPort: PUBLIC PROC RETURNS [p: portT] ~ { p _ [3]; }; MachPortsLookup: PUBLIC PROC [targetTask: taskT, raiseSignal: BOOL] RETURNS [intPortSet: portArrayT, intPortArrayCount: INT, kernCode: kernReturnT] ~ { xPortArray: REF ARRAY[0..3] OF portT _ NEW[ARRAY[0..3] OF portT _ [[0], [1], [2], [3]]]; intPortArrayCount _ 4; kernCode _ KernSuccess; intPortSet _ LOOPHOLE[xPortArray]; }; nextPort: portT _ [10]; portAllocate: PUBLIC PROC [targetTask: taskT, raiseSignal: BOOL] RETURNS [newPort: portT, kernCode: kernReturnT _ -1] ~ TRUSTED { nextPort _ [nextPort + 1]; newPort _ nextPort; kernCode _ KernSuccess; }; portRestrict: PUBLIC PROC [targetTask: taskT, port: portT, raiseSignal: BOOL] RETURNS [kernCode: kernReturnT _ -1] ~ { kernCode _ KernSuccess; }; portUnrestrict: PUBLIC PROC [targetTask: taskT, port: portT, raiseSignal: BOOL] RETURNS [kernCode: kernReturnT _ -1] ~ { kernCode _ KernSuccess; }; netnameCheckIn: PUBLIC PROC [ServPort: portT, portName: Rope.ROPE, signature: portT, portId: portT, raiseSignal: BOOL] RETURNS [kernCode: kernReturnT] ~ { kernCode _ KernSuccess; }; 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 { serverID _ [1989]; tsPort _ [4]; mPort _ [5]; sPort _ [6]; sharedMemAddr _ 0; seqDescList _ LIST[[serverId: [1234], segmentId: [1066], logicalDisk: 'Z, unused: 'z, highSize: 0, lowSize: 40960000], [serverId: [1234], segmentId: [42], logicalDisk: 'K, unused: 'k, highSize: 0, lowSize: 1048576], [serverId: [1234], segmentId: [1492], logicalDisk: 'R, unused: 'r, highSize: 0, lowSize: 4096]]; seqPortList _ LIST[[7], LogPagingObject, [9]]; SegmentIdPagingObjectMap _ LIST[ [[1066], [7], CamelotRecoverable.CamelotRecoverableFile], [[42], LogPagingObject, CamelotRecoverable.CamelotLogFile], [[1492], [9], CamelotRecoverable.RestartFile]]; kernCode _ KernSuccess; }; LogPagingObject: pagingObjectT _ [8]; SegmentIdPagingObjectMap: LIST OF SegmentIdPagingObjectMapItem; SegmentIdPagingObjectMapItem: TYPE = RECORD[ segmentId: segmentIdT, pagingObject: pagingObjectT, backingFile: FS.OpenFile ]; PagingObjectForSegementId: PROC [segmentId: segmentIdT] RETURNS [pagingObject: pagingObjectT] ~ { FOR lospom: LIST OF SegmentIdPagingObjectMapItem _ SegmentIdPagingObjectMap, lospom.rest UNTIL lospom = NIL DO IF lospom.first.segmentId = segmentId THEN RETURN[lospom.first.pagingObject]; REPEAT FINISHED => ERROR ENDLOOP; }; FileForPagingObject: PROC [pagingObject: pagingObjectT] RETURNS [backingFile: FS.OpenFile] ~ { FOR lospom: LIST OF SegmentIdPagingObjectMapItem _ SegmentIdPagingObjectMap, lospom.rest UNTIL lospom = NIL DO IF lospom.first.pagingObject = pagingObject THEN RETURN[lospom.first.backingFile]; REPEAT FINISHED => ERROR ENDLOOP; }; DSPinObject: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, size: uInt, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT _ -1] ~ { rememberPin[tid, optr, size]; noteDirtyOfMemory[optr, size]; kernCode _ KernSuccess; }; DSLogNewValue: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, newValue: pointerT, newValueCnt: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT _ -1] ~ { [] _ YggLog.Write[trans: tid, logRecordPhaseType: redo, recordType: writeBytes, optr: optr, recordData: [base: LOOPHOLE[newValue], length: (newValueCnt+3)/4, rest: NIL], force: FALSE]; monitoredChangePin[transID: tid, loggingNow: TRUE]; kernCode _ KernSuccess; }; DSLogOldValueNewValue: PUBLIC PROC [dsPort: portT, tid: tidT, optr: optrT, oldValue: pointerT, oldValueCnt: INT, newValue: pointerT, newValueCnt: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT _ -1] ~ { [] _ YggLog.Write[trans: tid, logRecordPhaseType: undo, recordType: writeBytes, optr: optr, recordData: [base: LOOPHOLE[oldValue], length: (newValueCnt+3)/4, rest: NIL], force: FALSE]; [] _ YggLog.Write[trans: tid, logRecordPhaseType: redo, recordType: writeBytes, optr: optr, recordData: [base: LOOPHOLE[newValue], length: (newValueCnt+3)/4, rest: NIL], force: FALSE]; monitoredChangePin[transID: tid, loggingNow: TRUE]; kernCode _ KernSuccess; }; DSQInit: PUBLIC PROC [sharedMemAddr: Mach.vmAddressT] ~ { }; DSQPreflush: PUBLIC PROC [dsPort: Mach.portT, optr: optrT, sizeInBytes: uInt] ~ { po: pagingObjectT; po _ PagingObjectForSegementId[optr.segmentId]; FOR loai: LIST OF AllocItem _ VMAllocList, loai.rest UNTIL loai = NIL DO IF loai.first.pagingObject = po AND loai.first.offset = optr.lowOffset THEN { backingFile: FS.OpenFile; pages: INT _ -1; firstPage: INT _ -1; IF sizeInBytes # loai.first.size THEN ERROR; pages _ FS.PagesForBytes[loai.first.size]; firstPage _ FS.PagesForBytes[loai.first.offset]; backingFile _ FileForPagingObject[loai.first.pagingObject]; FS.Write[file: backingFile, to: firstPage, nPages: pages, from: LOOPHOLE[loai.first.mappedAddress]]; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; }; DSQZeroFill: PUBLIC PROC [dsPort: Mach.portT, optr: optrT, sizeInBytes: uInt] ~ { po: pagingObjectT; po _ PagingObjectForSegementId[optr.segmentId]; [] _ vmAllocateWithPagerInner[sizeInBytes, po, optr.lowOffset, TRUE]; }; TAAddApplication: PUBLIC PROC [tPort: portT, atPort: portT, authName: Rope.ROPE, raiseSignal: BOOL] RETURNS [applicationID: applicationIdT, taPort: portT, kernCode: Mach.kernReturnT _ -1] ~ TRUSTED { kernCode _ KernSuccess; }; TABegin: PUBLIC ENTRY PROC [taPort: portT, parentTid: tidT, transType: transactionTypeT, raiseSignal: BOOL] RETURNS [newTid: tidT, kernCode: Mach.kernReturnT _ -1] ~ TRUSTED { newTid _ GetNextTrans[]; IF ~noteNewTrans[newTid] THEN ERROR; kernCode _ KernSuccess; }; TAEnd: PUBLIC PROC [taPort: portT, tid: tidT, protocolType: protocolTypeT, raiseSignal: BOOL] RETURNS [timestamp: timestampT, status: INT, kernCode: Mach.kernReturnT _ -1] ~ TRUSTED { transID: YggTransaction.TransID _ LOOPHOLE[tid]; block: LIST OF YggLog.Block; blockArrayOfWords: LONG POINTER TO ARRAY[0..1024/4) OF CARD32; block _ getScratchBlock[]; block.first.length _ 2; blockArrayOfWords _ LOOPHOLE[block.first.base]; blockArrayOfWords[0] _ tid.top.highTicker; blockArrayOfWords[1] _ tid.top.lowTicker; [] _ YggLog.Write[trans: tid, logRecordPhaseType: analysis, recordType: commitTrans, optr: [[0],0,0], recordData: block.first, force: TRUE]; returnScratchBlock[block]; monitoredChangePin[transID: transID, loggingNow: FALSE]; IF ~removeTrans[transID] THEN ERROR; status _ ErSuccess; kernCode _ KernSuccess; }; TAKill: PUBLIC PROC [taPort: portT, tid: tidT, status: INT, raiseSignal: BOOL] RETURNS [kernCode: Mach.kernReturnT _ -1] ~ TRUSTED { transID: YggTransaction.TransID _ LOOPHOLE[tid]; block: LIST OF YggLog.Block; blockArrayOfWords: LONG POINTER TO ARRAY[0..1024/4) OF CARD32; block _ getScratchBlock[]; block.first.length _ 2; blockArrayOfWords _ LOOPHOLE[block.first.base]; blockArrayOfWords[0] _ tid.top.highTicker; blockArrayOfWords[1] _ tid.top.lowTicker; YggTransaction.Suspend[transID, ErWaitingTransAborted]; [] _ YggLog.Write[trans: tid, logRecordPhaseType: analysis, recordType: abortTrans, optr: [[0],0,0], recordData: block.first, force: TRUE]; monitoredChangePin[transID: tid, loggingNow: FALSE]; returnScratchBlock[block]; kernCode _ KernSuccess; }; savedScratchBlocks: LIST OF YggLog.Block _ NIL; getScratchBlock: ENTRY PROC RETURNS [block: LIST OF YggLog.Block] ~ { ENABLE UNWIND => {}; IF savedScratchBlocks # NIL THEN { block _ savedScratchBlocks; savedScratchBlocks _ savedScratchBlocks.rest; } ELSE { interval: VM.Interval; interval _ VM.Allocate[count: VM.PagesForBytes[1024]]; block _ LIST[[base: LOOPHOLE[VM.AddressForPageNumber[interval.page]], length: 1024/4, rest: NIL]]; }; }; returnScratchBlock: ENTRY PROC [block: LIST OF YggLog.Block] ~ { block.rest _ savedScratchBlocks; savedScratchBlocks _ block; }; savedScratchTrans: Trans; savedScratchTransForEntries: Trans _ NEW[TransRep]; subtransactionAndTransactionMap: RedBlackTree.Table; checkpointNullTransObj: Trans _ NEW[TransRep]; Trans: TYPE = REF TransRep; TransRep: TYPE = RECORD [ transID: YggEnvironment.TransID, outcome: YggEnvironment.Outcome, latched: BOOL _ FALSE, finishTime: BasicTime.GMT _ BasicTime.nullGMT, suspendTime: BasicTime.GMT _ BasicTime.nullGMT, pageBucketsModified: RECORD[ low32: CARD32, high32: CARD32 ] ]; forABit: CONDITION; getScratchTrans: ENTRY PROC RETURNS [scratchTrans: Trans] ~ { ENABLE UNWIND => {}; IF savedScratchTrans # NIL THEN { scratchTrans _ savedScratchTrans; savedScratchTrans _ NIL; } ELSE { scratchTrans _ NEW[TransRep]; }; }; noteNewTrans: PROC [transID: YggEnvironment.TransID] RETURNS [parentOK: BOOL _ FALSE] ~ { newTrans: Trans; insertTrans: ENTRY PROC ~ { ENABLE UNWIND => {}; data: RedBlackTree.UserData; IF ~YggTransaction.IsTopLevel[transID] THEN { savedScratchTransForEntries.transID _ transID; data _ RedBlackTree.Lookup[subtransactionAndTransactionMap, savedScratchTransForEntries]; IF data # NIL THEN ERROR; } ELSE ERROR; RedBlackTree.Insert[subtransactionAndTransactionMap, newTrans, newTrans]; }; newTrans _ NEW[TransRep _ [transID: transID, outcome: active, pageBucketsModified: [0, 0] ]]; insertTrans[]; }; innerFindTrans: INTERNAL PROC [transID: YggEnvironment.TransID, setLatch: BOOL _ FALSE] RETURNS [transFound: BOOL _ FALSE, trans: Trans _ NIL] ~ { ENABLE UNWIND => {}; data: RedBlackTree.UserData; IF YggTransaction.IsNullTrans[transID] THEN RETURN [transFound: TRUE, trans: checkpointNullTransObj]; savedScratchTransForEntries.transID _ transID; data _ RedBlackTree.Lookup[subtransactionAndTransactionMap, savedScratchTransForEntries]; IF data = NIL THEN { RETURN[FALSE, NIL]; } ELSE { trans _ NARROW[data]; WHILE trans.latched DO WAIT forABit ENDLOOP; trans.latched _ TRUE; RETURN[TRUE, trans]; }; }; unlatchTrans: ENTRY PROC [trans: Trans] ~ { trans.latched _ FALSE; }; removeTrans: ENTRY PROC [transID: YggEnvironment.TransID] RETURNS [transFound: BOOL _ FALSE] ~ { data: RedBlackTree.UserData; savedScratchTransForEntries.transID _ transID; data _ RedBlackTree.Lookup[subtransactionAndTransactionMap, savedScratchTransForEntries]; IF data = NIL THEN { RETURN[FALSE]; } ELSE { trans: Trans; trans _ NARROW[data]; [] _ RedBlackTree.Delete[subtransactionAndTransactionMap, savedScratchTransForEntries]; RETURN[TRUE]; }; }; GetKeyProc: RedBlackTree.GetKey = { trans: Trans _ NARROW[data]; RETURN[ trans ]; }; CompareProc: RedBlackTree.Compare = { dataTrans: Trans _ NARROW[data]; keyTrans: Trans _ NARROW[k]; SELECT keyTrans.transID.bottom.nodeId.value FROM > dataTrans.transID.bottom.nodeId.value => RETURN [greater]; < dataTrans.transID.bottom.nodeId.value => RETURN [less]; ENDCASE => { SELECT keyTrans.transID.bottom.highTicker FROM > dataTrans.transID.bottom.highTicker => RETURN [greater]; < dataTrans.transID.bottom.highTicker => RETURN [less]; ENDCASE => { SELECT keyTrans.transID.bottom.lowTicker FROM > dataTrans.transID.bottom.lowTicker => RETURN [greater]; < dataTrans.transID.bottom.lowTicker => RETURN [less]; ENDCASE => RETURN [equal]; }; }; }; pageMask: CARD32 = 077B; noBuckets: CARD = 64; byteMask: CARD32 = 01777B; bytesPerBucket: CARD = 1024; pageBuckets: ARRAY [0..noBuckets) OF LIST OF pinItem; pinItem: TYPE = RECORD[ transID: YggEnvironment.TransID, optr: optrT, size: uInt, pc: pinCode ]; pinCode: TYPE = {pin, pinAndLogged, preventPin}; hashOptr: PROC [optr: optrT] RETURNS [CARD] ~ { lowPageNo: CARD32; lowPageNo _ PBasics.BITRSHIFT[optr.lowOffset, 10]; RETURN[PBasics.BITAND[lowPageNo, pageMask]]; }; rememberPin: ENTRY PROC [transID: YggEnvironment.TransID, optr: optrT, size: uInt, doPreventPin: BOOL _ FALSE] ~ { nowOptr: optrT; sizeLeft: uInt; innerRememberPin: INTERNAL PROC [thisOptr: optrT, bytes: CARD] RETURNS [tryAgain: BOOL _ FALSE] ~ { ENABLE UNWIND => {}; hashPage: CARD; lowPageNo: CARD32; transFound: BOOL _ FALSE; trans: Trans _ NIL; lowPageNo _ PBasics.BITRSHIFT[thisOptr.lowOffset, 10]; hashPage _ hashOptr[thisOptr]; FOR lopi: LIST OF pinItem _ pageBuckets[hashPage], lopi.rest UNTIL lopi = NIL DO loopLowPageNo: CARD32; loopLowPageNo _ PBasics.BITRSHIFT[lopi.first.optr.lowOffset, 10]; IF loopLowPageNo = lowPageNo AND lopi.first.pc = preventPin THEN RETURN[TRUE] ENDLOOP; pageBuckets[hashPage] _ CONS[[transID, thisOptr, bytes, pin], pageBuckets[hashPage]]; [transFound, trans] _ innerFindTrans[transID]; IF ~transFound THEN ERROR; IF hashPage < 32 THEN { trans.pageBucketsModified.low32 _ PBasics.BITOR[PBasics.BITLSHIFT[value: 1, count: hashPage], trans.pageBucketsModified.low32]; } ELSE { trans.pageBucketsModified.high32 _ PBasics.BITOR[PBasics.BITLSHIFT[value: 1, count: hashPage-32], trans.pageBucketsModified.high32]; }; }; nowOptr _ optr; sizeLeft _ size; WHILE sizeLeft > 0 DO firstByteOnPage: CARD; bytesThisPage: CARD; firstByteOnPage _ PBasics.BITAND[nowOptr.lowOffset, byteMask]; bytesThisPage _ bytesPerBucket - firstByteOnPage; IF bytesThisPage = 0 OR bytesThisPage > bytesPerBucket THEN ERROR; IF innerRememberPin[nowOptr, bytesThisPage] THEN { WAIT forABit; LOOP; }; sizeLeft _ sizeLeft - bytesThisPage; nowOptr.lowOffset _ nowOptr.lowOffset + bytesThisPage; IF PBasics.BITAND[nowOptr.lowOffset, byteMask] # 0 THEN ERROR; ENDLOOP; }; monitoredChangePin: ENTRY PROC [transID: YggTransaction.TransID, loggingNow: BOOL] ~ { changePin[transID, loggingNow]; }; changePin: INTERNAL PROC [transID: YggTransaction.TransID, loggingNow: BOOL] ~ { trans: Trans; transFound: BOOL _ TRUE; lowMod: CARD32; highMod: CARD32; removePinFromBucket: PROC [bucket: CARD] ~ { gotOne: BOOL _ FALSE; prev: LIST OF pinItem _ NIL; FOR lopi: LIST OF pinItem _ pageBuckets[bucket], lopi.rest UNTIL lopi = NIL DO IF YggTransaction.EqualTrans[trans.transID, lopi.first.transID] THEN { IF loggingNow THEN { IF lopi.first.pc # pin THEN ERROR; lopi.first.pc _ pinAndLogged; } ELSE { IF lopi.first.pc # pinAndLogged THEN ERROR; IF prev = NIL THEN pageBuckets[bucket] _ lopi.rest ELSE prev.rest _ lopi.rest; }; gotOne _ TRUE; LOOP; }; prev _ lopi; ENDLOOP; IF ~gotOne THEN ERROR; }; [transFound, trans] _ innerFindTrans[transID]; IF ~transFound THEN ERROR; lowMod _ trans.pageBucketsModified.low32; FOR bucktNo: INT IN [0..32) DO IF PBasics.BITAND[lowMod, 1] = 1 THEN { removePinFromBucket[bucktNo]; }; lowMod _ PBasics.BITRSHIFT[value: lowMod, count: 1]; ENDLOOP; highMod _ trans.pageBucketsModified.high32; FOR bucktNo: INT IN [32..64) DO IF PBasics.BITAND[lowMod, 1] = 1 THEN { removePinFromBucket[bucktNo]; }; lowMod _ PBasics.BITRSHIFT[value: lowMod, count: 1]; ENDLOOP; }; 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] ~ { portList _ LIST[[9]]; kernCode _ KernSuccess; }; GetNextTrans: PROC RETURNS [transID: YggTransaction.TransID] ~ { NextTransCount _ NextTransCount + 1; transID _ [top: [lowTicker: NextTransCount], bottom: [lowTicker: NextTransCount]]; }; DoCommit: PROC [transID: YggTransaction.TransID, doCommit: BOOL] ~ { [] _ YggTransaction.Finish[transID, IF doCommit THEN commit ELSE abort]; }; STServer: PUBLIC PROC [inMsg: REF Camelot.camlibSysReqMsgT, outMsg: REF Camelot.camlibSysRepMsgT] RETURNS [messageUnderstood: BOOL _ FALSE] ~ { }; SRServer: PUBLIC PROC [inMsg: REF Camelot.camlibSysReqMsgT, outMsg: REF Camelot.camlibSysRepMsgT] RETURNS [messageUnderstood: BOOL _ FALSE] ~ { }; ATServer: PUBLIC PROC [inMsg: REF Camelot.camlibSysReqMsgT, outMsg: REF Camelot.camlibSysRepMsgT] RETURNS [messageUnderstood: BOOL _ FALSE] ~ { }; milliSecondsBetweenCheckpoint: INT _ 30000; ephocsBetweenCleans: CARD _ 2; CheckpointProcess: PROC ~ { DO loai: LIST OF AllocItem; now: BasicTime.GMT; segmentId: segmentIdT; Process.PauseMsec[milliSecondsBetweenCheckpoint]; now _ BasicTime.Now[]; CheckPointEphocNumber _ CheckPointEphocNumber + 1; DO findABufferToFlush: ENTRY PROC RETURNS [gotOne: BOOL _ FALSE] ~ { FOR loai _ VMAllocList, loai.rest UNTIL loai = NIL DO IF loai.first.dirtied AND loai.first.pagingObject # LogPagingObject THEN { IF CheckPointEphocNumber - loai.first.ephocOfLastWrite > 2 THEN { loai.first.ownedByCheckpointProcess _ TRUE; RETURN [TRUE]; }; }; ENDLOOP; }; IF ~findABufferToFlush[] THEN EXIT; checkpointNullTransObj.pageBucketsModified _ [0, 0]; segmentId _ [loai.first.pagingObject.portNumber]; rememberPin[transID: YggEnvironment.nullTransID, optr: [segmentId: segmentId, highOffset: 0, lowOffset: loai.first.offset], size: loai.first.size, doPreventPin: TRUE]; { pages: INT _ -1; firstPage: INT _ -1; pages _ FS.PagesForBytes[loai.first.size]; firstPage _ FS.PagesForBytes[loai.first.offset]; FS.Write[file: CamelotRecoverable.CamelotRecoverableFile, to: firstPage, nPages: pages, from: LOOPHOLE[loai.first.mappedAddress]]; loai.first.timeOfLastWrite _ now; loai.first.ephocOfLastWrite _ CheckPointEphocNumber; loai.first.dirtied _ FALSE; loai.first.ownedByCheckpointProcess _ FALSE; }; monitoredChangePin [transID: YggEnvironment.nullTransID, loggingNow: FALSE]; ENDLOOP; { block: LIST OF YggLog.Block; blockArrayOfWords: LONG POINTER TO ARRAY[0..1024/4) OF CARD32; thisRecord: YggLog.RecordID; block _ getScratchBlock[]; block.first.length _ 1; blockArrayOfWords _ LOOPHOLE[block.first.base]; TRUSTED {blockArrayOfWords[0] _ CheckPointEphocNumber;}; [thisRecord: thisRecord] _ YggLog.Write[trans: YggEnvironment.nullTransID, logRecordPhaseType: other, recordType: checkpointComplete, optr: [[0],0,0], recordData: block.first, force: TRUE]; returnScratchBlock[block]; YggRestartFile.WriteRestartRecord[recordIDForCheckpointCompleteRecord: thisRecord]; }; ENDLOOP; }; Init: PROC = { subtransactionAndTransactionMap _ RedBlackTree.Create[getKey: GetKeyProc, compare: CompareProc]; TRUSTED {Process.InitializeCondition[@forABit, Process.MsecToTicks[10]]; }; TRUSTED {Process.Detach[FORK CheckpointProcess[]]}; YggLogControl.Recover[]; YggdrasilInit.RecoveryComplete[]; }; Init[]; END. hMachCamelotEmulationForSunOS.mesa Copyright Ó 1988, 1989 by Xerox Corporation. All rights reserved. Bob Hagmann May 8, 1989 3:11:02 pm PDT Exported junk Global data Exported task procedures get my task get my notify port (task_notify) Exported virtual memory procedures Grab some VM. Map some externally backed memory into VM. Map some externally backed memory into VM. interval: VM.Interval; interval _ VM.Allocate[count: VM.PagesForBytes[size]]; Unmap some externally backed memory into VM, whether externally backed or not. TRUSTED{VM.Free[interval: loai.first.interval];}; REPEAT FINISHED => ERROR; Exported message procedures send a message Receive a message. Modifies the header! Exported port procedures get my port to the name server (name_server_port) get my port to the service port (service_port) send a message restricts port so that msgReceive must be used the port number, not PortDefault unrestricts port so that PortDefault to msgReceive can receive from this port Netname "check in a name into the local name space" Exported recoverable storage management procedures Initialize the data server. Pin an object in preparation for modification. optr is the Camelot recoverable storage "address", not the VM address Send a new value of an object to the log. Send a new value of an object to the log. Init the shared memory queue (emulation does nothing). Preflush some dirty memory TRUSTED{VM.Free[interval: loai.first.interval];}; Zero some memory. Exported transaction management procedures Initialize an application to the transaction manager. Start a new transaction. Try to commit a transaction. Try to abort a transaction. Insert backwards scan of log, calling CamelotMIG.SRRestoreObjectX Internal block allocation Internal transaction procedures Internal red black procs A Red Black tree is used to store and find transactions/subtransactions. The tree is indexed by subtransaction. PROC [data: UserData] RETURNS [Key] PROC [k: Key, data: UserData] RETURNS [Basics.Comparison] Internal transaction procedures pin => it's pinned and maybe updated pinAndLogged => it's pinned and updated, and the log write has been buffered. A flush of the log will make everything OK. preventPin => disallow pins for this page Name server Lookup for applications. Local procs YggdrasilInit Checkpoint process data: RedBlackTree.UserData; Initialization �Ê˘šœ!™!IcodešœB™BKšœ&™&K˜šÏk ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kš�œ˜Kšœ˜Kšœ˜Kšœ˜K˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜K˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜Kšœ˜Kšœ˜——headšœ�œ�˜+Kš�œ—˜žKš�œ/˜6K˜Kšœ�˜Kš�œ˜Kš�œ�œ�œ˜K˜—™ K˜Kšœ�œ#˜1K˜Kš�œ� œ�œ˜Kšœ�œ�œ˜+K˜Kšœ �œ�œ ˜!Kšœ �œ�œ ˜8K˜K˜—™ K˜Kšœ�œ ˜K˜Kšœ�œ˜ —šœ™Kš Ïnœ�œ�œ+�œ�œ˜OKš ž œ�œ�œ�œ�œÏb˜�œ˜dKš�œ�œ'™1Kš�œ˜K˜—Kš�œ�œ�œ˜Kš�œ˜—K˜K™K™—šž œ�œ�œ9˜QKšœ™Kšœ˜Kšœ/˜/Kšœ?�œ˜EK˜K™——šœ*™*š žœ� œ.�œ�œ�œS�œ˜ÇKšœ5™5Kšœ˜K˜K™—š žœ�œ� œL�œ�œ3�œ˜¯Kšœ™Kšœ˜Kš�œ�œ�œ˜$Kšœ˜K˜K™—šžœ�œ�œF�œ�œ!�œ%�œ˜·Kšœ™Kšœ"�œ˜0Kšœ�œ�œ˜Kš œ�œ�œ�œ�œ �œ�œ˜>Kšœ˜Kšœ˜Kšœ�œ˜/Kšœ*˜*Kšœ)˜)Jšœ†�œ˜ŒKšœ˜Kšœ1�œ˜8Kš�œ�œ�œ˜$Kšœ˜Kšœ˜K˜K™—šžœ�œ�œ$�œ�œ�œ%�œ˜„Kšœ™Kšœ"�œ˜0Kšœ�œ�œ˜Kš œ�œ�œ�œ�œ �œ�œ˜>Kšœ˜Kšœ˜Kšœ�œ˜/Kšœ*˜*Kšœ)˜)Kšœ7˜7Jšœ…�œ˜‹KšÐbl0Ñbln™AKšœ-�œ˜4Kšœ˜Kšœ˜K˜K™——™Kšœ�œ�œ�œ˜/K˜K˜š Ÿœ�œ�œ�œ �œ�œ˜EJš�œ�œ˜š�œ�œ�œ˜"Kšœ˜Kšœ-˜-K˜—šœ�œ˜Kšœ �œ ˜Kšœ �œ�œ˜6Kš œ�œ�œ�œ=�œ˜bK˜—K˜K˜—š Ÿœ�œ�œ �œ�œ˜@Kšœ ˜ Kšœ˜K˜—K˜—™Kšœ˜Kšœ%�œ ˜3K˜Kšœ4˜4K˜Kšœ �œ ˜.K˜Kšœ�œ�œ ˜šœ �œ�œ˜Kšœ ˜ Kšœ ˜ Kšœ �œ�œ˜Kšœ�œ˜.Kšœ�œ˜/˜Kšœ�œ˜Kšœ�˜K˜—K˜—K˜Kšœ � œ˜K˜šŸœ�œ�œ�œ˜=Jš�œ�œ˜š�œ�œ�œ˜!Kšœ!˜!Kšœ�œ˜K˜—šœ�œ˜Kšœ�œ ˜K˜—K˜K˜—š Ÿ œ�œ#�œ �œ�œ˜YKšœ˜šŸ œ�œ�œ˜Jš�œ�œ˜Jšœ˜š�œ%�œ˜-Jšœ.˜.JšœY˜YKš�œ�œ�œ�œ˜K˜—Kšœ�œ�œ˜ KšœI˜IK˜—Kšœ �œO˜]Kšœ˜K˜K˜—šŸœ�œ�œ-�œ�œ�œ�œ�œ�œ˜’Jš�œ�œ˜Jšœ˜Jš�œ%�œ�œ�œ!˜eJšœ.˜.JšœY˜Yš�œ�œ�œ˜Kš�œ�œ�œ˜K˜—šœ�œ˜Jšœ�œ˜Jš�œ�œ�œ �œ˜,Jšœ�œ˜Jš�œ�œ ˜K˜—J˜J˜—šŸ œ�œ�œ˜+Jšœ˜J˜J˜—š Ÿ œ� œ#�œ�œ�œ˜`Jšœ˜Jšœ.˜.JšœY˜Yš�œ�œ�œ˜Kš�œ�œ˜K˜—šœ�œ˜Jšœ ˜ Jšœ�œ˜KšœW˜WKš�œ�œ˜ K˜—J˜——šœ™J™rJ˜šž œ˜&Jš�œ�œ™#Jšœ�œ˜Jš�œ ˜J˜J˜—•StartOfExpansion[]šž œ˜%Jš�œ�œ™9Jšœ�œ˜ Jšœ�œ˜š�œ&�˜0Jšœ+�œ ˜˜J˜—šœ�œ˜Jšœ+�œ � œB˜„J˜—K˜—Kšœ˜Kšœ˜š�œ�˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜>Kšœ1˜1Kš�œ�œ �œ�œ˜Bš�œ*�œ˜2Kš�œ ˜ Kš�œ˜K˜—Kšœ$˜$Kšœ6˜6Kš�œ �œ"�œ�œ˜>Kš�œ˜—K˜K˜—šŸœ�œ�œ/�œ˜VJšœ˜J˜J˜—šŸ œ�œ�œ/�œ˜PJ˜ Jšœ �œ�œ˜Jšœ�œ˜Jšœ �œ˜šŸœ�œ �œ˜,Jšœ�œ�œ˜Jšœ�œ�œ �œ˜š �œ�œ�œ*�œ�œ�˜Nš�œ>�œ˜Fš�œ �œ˜Jš�œ�œ�œ˜"Jšœ˜J˜—šœ�œ˜Jš�œ�œ�œ˜+Jš�œ�œ�œ ˜2Jšœ�œ˜J˜—Jšœ �œ˜Jš�œ˜J˜—Jšœ ˜ Jš�œ˜—Jš�œ �œ�œ˜J˜—Jšœ.˜.Jš�œ �œ�œ˜Jšœ)˜)š�œ �œ�œ �˜š�œ �œ�œ˜'J˜J˜—Jšœ� œ˜4Jš�œ˜—Jšœ+˜+š�œ �œ�œ �˜š�œ �œ�œ˜'J˜J˜—Jšœ� œ˜4Jš�œ˜—J˜——™ K™šžœ� œ)�œ �œ�œ�œ�œ�œ=˜ÐKšœ™Kšœ˜Kšœ˜K˜—K™—™ K˜unitšž œ�œ�œ&˜@Kšœ$˜$KšœR˜RK˜—šžœ�œ6˜DKšœH˜HK˜—K™—™ K™šÐbnœ� œ �œ#�œ�œ�œ�œ˜�K˜—š¢œ� œ �œ#�œ�œ�œ�œ˜�K˜—šžœ� œ �œ#�œ�œ�œ�œ˜�K˜—K™—™Kšœ�œ ˜+Kšœ�œ˜K˜šžœ�œ˜š�˜Jšœ™Kšœ�œ�œ ˜Kšœ�œ˜Kšœ˜Kšœ1˜1K˜Kšœ2˜2š�˜š œ�œ�œ�œ � œ˜Aš�œ�œ�œ�˜5š�œ�œ+�œ˜JšœA˜AKšœ&�œ˜+Kš�œ�œ˜K˜—K˜—Kš�œ˜—K˜K˜—Kš�œ�œ�œ˜#Kšœ4˜4Kšœ1˜1Kšœ¡�œ˜§š�˜Kšœ�œ˜Kšœ �œ˜Kšœ�œ ˜*Kšœ �œ"˜0Kš�œ\�œ˜‚Kšœ!˜!Kšœ4˜4Kšœ�œ˜Kšœ&�œ˜,Kšœ˜—KšœE�œ˜LKš�œ˜—šœ˜Kšœ�œ�œ˜Kš œ�œ�œ�œ�œ �œ�œ˜>Kšœ˜Kšœ˜Kšœ˜Kšœ�œ˜/Kšœ8˜8Jšœ·�œ˜½Kšœ˜KšœS˜SJ˜—Kš�œ˜—K˜——™K˜šžœ�œ˜Kšœ`˜`Kš�œD˜KKš�œ�œ˜3Kšœ˜Kšœ!˜!K˜K˜—K˜—K˜Kš�œ˜K™J˜—…—\8‚k