public void Register(THandleClass handleClass, THandle obj, UnmanagedObjectContext <THandleClass, THandle> .DestroyHandleDelegate destroyHandle = null, HandleCollection <THandleClass, THandle> parentCollection = null) { UnmanagedObjectContext <THandleClass, THandle> existingContextObj; var handleContainer = new HandleContainer(handleClass, obj); var trackedObject = new UnmanagedObjectContext <THandleClass, THandle> { DestroyHandle = destroyHandle, parentCollection = parentCollection }; do { if ((existingContextObj = _trackedObjects.GetOrAdd(handleContainer, trackedObject)) == trackedObject) { if (parentCollection == null) { return; } foreach (var dep in trackedObject.parentCollection) { UnmanagedObjectContext <THandleClass, THandle> depContext; if (!_trackedObjects.TryGetValue(dep, out depContext)) { throw new EObjectNotFound <THandleClass, THandle>(dep.Item1, dep.Item2); } depContext.AddRefCount(); } return; } /* If object already existed, under normal conditions AddRefCount() must return a value > 1. * If it returns <= 1 it means it just got decremented in another thread, reached zero and * it's about to be destroyed. So we will have to wait for that to happen and try again our * entire operation */ var newRefCount = existingContextObj.AddRefCount(); if (newRefCount <= 0) { throw new EInvalidRefCount <THandleClass, THandle>(handleClass, obj, newRefCount); } if (newRefCount > 1) { break; } /* Object is getting removed in another thread. Let's spin while we wait for it to be gone * from our _trackedObjects container */ while (_trackedObjects.TryGetValue(handleContainer, out existingContextObj)) { Thread.Yield(); } } while (true); /* Object already exists, could be an stale object not yet garbage collected, * so we will set the new cleanup methods in place of the current ones */ existingContextObj.DestroyHandle = destroyHandle; if (parentCollection == null) { return; } foreach (var dep in parentCollection) { AddParent(existingContextObj, dep); } }
public void InitParentCollection() { parentCollection = new HandleCollection <THandleClass, THandle>(); }