private long _result; // Using long since this needs to be used in Interlocked APIs // Using RunContinuationsAsynchronously for compat reasons (old API used Task.Factory.StartNew for continuations) internal FileStreamCompletionSource(IFileStreamCompletionSourceStrategy strategy, PreAllocatedOverlapped?preallocatedOverlapped, int numBufferedBytes, byte[]?bytes) : base(TaskCreationOptions.RunContinuationsAsynchronously) { _numBufferedBytes = numBufferedBytes; _strategy = strategy; _result = NoResult; // The _preallocatedOverlapped is null if the internal buffer was never created, so we check for // a non-null bytes before using the stream's _preallocatedOverlapped _overlapped = bytes != null && strategy.CompareExchangeCurrentOverlappedOwner(this, null) == null ? strategy.FileHandle.ThreadPoolBinding !.AllocateNativeOverlapped(preallocatedOverlapped !) : // allocated when buffer was created, and buffer is non-null strategy.FileHandle.ThreadPoolBinding !.AllocateNativeOverlapped(s_ioCallback, this, bytes); Debug.Assert(_overlapped != null, "AllocateNativeOverlapped returned null"); }
internal virtual void ReleaseNativeResource() { // Ensure that cancellation has been completed and cleaned up. _cancellationRegistration.Dispose(); // Free the overlapped. // NOTE: The cancellation must *NOT* be running at this point, or it may observe freed memory // (this is why we disposed the registration above). if (_overlapped != null) { _strategy.FileHandle.ThreadPoolBinding !.FreeNativeOverlapped(_overlapped); _overlapped = null; } // Ensure we're no longer set as the current completion source (we may not have been to begin with). // Only one operation at a time is eligible to use the preallocated overlapped, _strategy.CompareExchangeCurrentOverlappedOwner(null, this); }