Example #1
0
        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>();
 }