private static CancellationTokenHelper GetStaticDisposedHelper() { CancellationTokenHelper helper = new CancellationTokenHelper(false); helper.Dispose(); return(helper); }
private static CancellationTokenHelper GetStaticDisposedHelper() { CancellationTokenHelper helper = new CancellationTokenHelper(false); helper.Dispose(); return helper; }
internal bool TryGetClientDisconnectedCancellationToken(out CancellationToken cancellationToken) { // This API is not supported on IIS versions prior to IIS 7.5. if (HttpRuntime.IISVersion < IIS_VERSION_75) { cancellationToken = CancellationToken.None; return false; } // The registration is done inside of the dispose lock because we don't want to // allow registration while the native context object is being destroyed. If we // didn't have this lock, there is a potential race condition where the // registration could take place at the same time as a call to Dispose, at which // point we lose our guarantees about the unmanaged code not trying to call back // into this AppDomain. // // If you change the below code, be judicious with how much work is performed // within the lock on _disposeLockObj. The p/invoke call that takes place within // the lock will itself try to enter a critical section in the class // MGD_CONNECTION_STORED_CONTEXT, and this could very easily lead to deadlock // scenarios. The particular usage below is safe because the _disposeLockObj // lock is always taken before entering the unmanaged critical section, never // the other way around. So code that is within the unmanaged critical section // is guaranteed to execute quickly without blocking. if (_clientDisconnectTokenHelper == null) { lock (_disposeLockObj) { if (_clientDisconnectTokenHelper == null) { if (_context == IntPtr.Zero) { // A call to Dispose already took place, so we'll just return a pre-disposed helper. _clientDisconnectTokenHelper = CancellationTokenHelper.StaticDisposed; } else { bool isClientConnected; int hr = IIS.MgdConfigureAsyncDisconnectNotification(_context, true /* fEnabled */, out isClientConnected); Marshal.ThrowExceptionForHR(hr); // Seed the helper's initial state with the known client connection status. // Pay attention to the race condition mentioned in NotifyOfAsyncDisconnect. LazyInitializer.EnsureInitialized(ref _clientDisconnectTokenHelper, () => new CancellationTokenHelper(canceled: !isClientConnected)); } } } } cancellationToken = _clientDisconnectTokenHelper.Token; return true; }