Exemple #1
0
        /// <summary>Creates a SafeHandle class.</summary>
        protected SafeHandle(IntPtr invalidHandleValue, bool ownsHandle)
        {
            handle      = invalidHandleValue;
            _state      = StateBits.RefCountOne; // Ref count 1 and not closed or disposed.
            _ownsHandle = ownsHandle;

            if (!ownsHandle)
            {
                GC.SuppressFinalize(this);
            }
#if DEBUG
            else if (s_logFinalization)
            {
                int lastError = Marshal.GetLastPInvokeError();
                _ctorStackTrace = Environment.StackTrace;
                Marshal.SetLastPInvokeError(lastError);
            }
#endif

            _fullyInitialized = true;
        }
Exemple #2
0
        private void Cleanup()
        {
            if (IsClosed)
            {
                return;
            }
            _isClosed = true;

            if (IsInvalid)
            {
                return;
            }

            // Save last error from P/Invoke in case the implementation of
            // ReleaseHandle trashes it (important because this ReleaseHandle could
            // occur implicitly as part of unmarshaling another P/Invoke).
            int lastError = Marshal.GetLastPInvokeError();

            ReleaseHandle();

            Marshal.SetLastPInvokeError(lastError);
            GC.SuppressFinalize(this);
        }
Exemple #3
0
        private void InternalRelease(bool disposeOrFinalizeOperation)
        {
            Debug.Assert(_fullyInitialized || disposeOrFinalizeOperation);

            // See AddRef above for the design of the synchronization here. Basically we
            // will try to decrement the current ref count and, if that would take us to
            // zero refs, set the closed state on the handle as well.
            bool performRelease = false;

            // Might have to perform the following steps multiple times due to
            // interference from other AddRef's and Release's.
            int oldState, newState;

            do
            {
                // First step is to read the current handle state. We use this cached
                // value to predicate any modification we might decide to make to the
                // state).
                oldState = _state;

                // If this is a Dispose operation we have additional requirements (to
                // ensure that Dispose happens at most once as the comments in AddRef
                // detail). We must check that the dispose bit is not set in the old
                // state and, in the case of successful state update, leave the disposed
                // bit set. Silently do nothing if Dispose has already been called.
                if (disposeOrFinalizeOperation && ((oldState & StateBits.Disposed) != 0))
                {
                    return;
                }

                // 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 ((oldState & StateBits.RefCount) == 0)
                {
                    throw new ObjectDisposedException(nameof(SafeHandle), SR.ObjectDisposed_SafeHandleClosed);
                }

                // If we're proposing a decrement to zero and the handle is not closed
                // and we own the handle then we need to release the handle upon a
                // successful state update. If so we need to check whether the handle is
                // currently invalid by asking the SafeHandle subclass. We must do this before
                // transitioning the handle to closed, however, since setting the closed
                // state will cause IsInvalid to always return true.
                performRelease = ((oldState & (StateBits.RefCount | StateBits.Closed)) == StateBits.RefCountOne) &&
                                 _ownsHandle &&
                                 !IsInvalid;

                // 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 StateBits.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).
                newState = oldState - StateBits.RefCountOne;
                if ((oldState & StateBits.RefCount) == StateBits.RefCountOne)
                {
                    newState |= StateBits.Closed;
                }
                if (disposeOrFinalizeOperation)
                {
                    newState |= StateBits.Disposed;
                }
            } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState);

            // If we get here we successfully decremented the ref count. Additionally we
            // may have decremented it to zero and set the handle state as closed. In
            // this case (providng we own the handle) we will call the ReleaseHandle
            // method on the SafeHandle subclass.
            if (performRelease)
            {
                // Save last error from P/Invoke in case the implementation of ReleaseHandle
                // trashes it (important because this ReleaseHandle could occur implicitly
                // as part of unmarshaling another P/Invoke).
                int lastError = Marshal.GetLastPInvokeError();
                ReleaseHandle();
                Marshal.SetLastPInvokeError(lastError);
            }
        }