public void SpinLock() { // Check for a re-entrant lock. if (threadLockedRecord == (RecordInfo *)Unsafe.AsPointer(ref this)) { Debug.Assert(threadLockedRecordEntryCount > 0); ++threadLockedRecordEntryCount; return; } // RecordInfo locking is intended for use in concurrent callbacks only (ConcurrentReader, ConcurrentWriter, InPlaceUpdater), // so only the RecordInfo for that callback should be locked. A different RecordInfo being locked implies a missing Unlock. Debug.Assert(threadLockedRecord == null); Debug.Assert(threadLockedRecordEntryCount == 0); while (true) { long expected_word = word; if ((expected_word & kLatchBitMask) == 0) { var found_word = Interlocked.CompareExchange(ref word, expected_word | kLatchBitMask, expected_word); if (found_word == expected_word) { threadLockedRecord = (RecordInfo *)Unsafe.AsPointer(ref this); threadLockedRecordEntryCount = 1; return; } } Thread.Yield(); } }
public static void WriteInfo(RecordInfo *info, int checkpointVersion, bool tombstone, bool invalidBit, long previousAddress) { info->word = default(long); info->Tombstone = tombstone; info->Invalid = invalidBit; info->PreviousAddress = previousAddress; info->Version = checkpointVersion; info->access_data = 0; }
public unsafe void RecordInfoLockTest() { for (var ii = 0; ii < 5; ++ii) { RecordInfo recordInfo = new RecordInfo(); RecordInfo *ri = &recordInfo; XLockTest(() => ri->SpinLock(), () => ri->Unlock()); } }
public void Unlock() { Debug.Assert(threadLockedRecord == (RecordInfo *)Unsafe.AsPointer(ref this)); if (threadLockedRecord == (RecordInfo *)Unsafe.AsPointer(ref this)) { Debug.Assert(threadLockedRecordEntryCount > 0); if (--threadLockedRecordEntryCount == 0) { word &= ~kLatchBitMask; threadLockedRecord = null; } } }
public unsafe void RecordInfoLockTest() { for (var ii = 0; ii < 5; ++ii) { RecordInfo recordInfo = new(); RecordInfo *ri = &recordInfo; // We are not sealing in this test, so there is no need to check the return XLockTest(() => ri->LockExclusive(), () => ri->UnlockExclusive()); SLockTest(() => ri->LockShared(), () => ri->UnlockShared()); XSLockTest(() => ri->LockExclusive(), () => ri->UnlockExclusive(), () => ri->LockShared(), () => ri->UnlockShared()); } }
public static string ToString(RecordInfo *info) { return("RecordHeader Word = " + info->word); }