- public abstract bool IsInvalid {
- [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
- get;
+ /* We should never see a ref count of zero (that would imply we have
+ * unbalanced AddRef and Releases). (We might see a closed state before
+ * hitting zero though -- that can happen if SetHandleAsInvalid is
+ * used). */
+ if ((old_state & RefCount_Mask) == 0)
+ throw new ObjectDisposedException ("handle");
+
+ perform_release =
+ (old_state & RefCount_Mask) == RefCount_One
+ && (old_state & (int) State.Closed) == 0
+ && _ownsHandle;
+
+ if (perform_release && IsInvalid)
+ perform_release = false;
+
+ /* Attempt the update to the new state, fail and retry if the initial
+ * state has been modified in the meantime. Decrement the ref count by
+ * substracting SH_RefCountOne from the state then OR in the bits for
+ * Dispose (if that's the reason for the Release) and closed (if the
+ * initial ref count was 1). */
+ new_state =
+ (old_state - RefCount_One)
+ | ((old_state & RefCount_Mask) == RefCount_One ? (int) State.Closed : 0)
+ | (dispose ? (int) State.Disposed : 0);
+ } while (Interlocked.CompareExchange (ref _state, new_state, old_state) != old_state);
+
+ if (perform_release)
+ ReleaseHandle ();