public static Operand EmitRetryFromAccessViolation(EmitterContext context) { IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState; IntPtr localCountsPtr = IntPtr.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset); // Get the lock first. EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset)); IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc(); Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32); Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0)); Operand endLabel = Label(); Operand retry = context.AllocateLocal(OperandType.I32); Operand threadIndexValidLabel = Label(); context.BranchIfFalse(threadIndexValidLabel, context.ICompareEqual(threadIndex, Const(-1))); context.Copy(retry, Const(1)); // Always retry when thread local cannot be allocated. context.Branch(endLabel); context.MarkLabel(threadIndexValidLabel); Operand threadLocalPartialUnmapsPtr = EmitThreadLocalMapIntGetValuePtr(context, localCountsPtr, threadIndex); Operand threadLocalPartialUnmaps = context.Load(OperandType.I32, threadLocalPartialUnmapsPtr); Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset))); context.Copy(retry, context.ICompareNotEqual(threadLocalPartialUnmaps, partialUnmapsCount)); Operand noRetryLabel = Label(); context.BranchIfFalse(noRetryLabel, retry); // if (retry) { context.Store(threadLocalPartialUnmapsPtr, partialUnmapsCount); context.Branch(endLabel); context.MarkLabel(noRetryLabel); // } context.MarkLabel(endLabel); // Finally, release the lock and return the retry value. EmitNativeReaderLockRelease(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset)); return(retry); }
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand initialState) { Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap <int> .ThreadIdsOffset)); Operand i = context.AllocateLocal(OperandType.I32); context.Copy(i, Const(0)); // (Loop 1) Check all slots for a matching Thread ID (while also trying to allocate) Operand endLabel = Label(); Operand loopLabel = Label(); context.MarkLabel(loopLabel); Operand offset = context.Multiply(i, Const(sizeof(int))); Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset)); // Check that this slot has the thread ID. Operand existingId = context.CompareAndSwap(idPtr, threadId, threadId); // If it was already the thread ID, then we just need to return i. context.BranchIfTrue(endLabel, context.ICompareEqual(existingId, threadId)); context.Copy(i, context.Add(i, Const(1))); context.BranchIfTrue(loopLabel, context.ICompareLess(i, Const(ThreadLocalMap <int> .MapSize))); // (Loop 2) Try take a slot that is 0 with our Thread ID. context.Copy(i, Const(0)); // Reset i. Operand loop2Label = Label(); context.MarkLabel(loop2Label); Operand offset2 = context.Multiply(i, Const(sizeof(int))); Operand idPtr2 = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset2)); // Try and swap in the thread id on top of 0. Operand existingId2 = context.CompareAndSwap(idPtr2, Const(0), threadId); Operand idNot0Label = Label(); // If it was 0, then we need to initialize the struct entry and return i. context.BranchIfFalse(idNot0Label, context.ICompareEqual(existingId2, Const(0))); Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap <int> .StructsOffset)); Operand structPtr = context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset2)); context.Store(structPtr, initialState); context.Branch(endLabel); context.MarkLabel(idNot0Label); context.Copy(i, context.Add(i, Const(1))); context.BranchIfTrue(loop2Label, context.ICompareLess(i, Const(ThreadLocalMap <int> .MapSize))); context.Copy(i, Const(-1)); // Could not place the thread in the list. context.MarkLabel(endLabel); return(context.Copy(i)); }