/// <summary> /// Get a object from the buffer manager. If no buffers exist, allocate a new one. /// </summary> internal object Allocate() { #if ENABLE // Check to see whether or not the cache is disabled. if (m_CacheName == null) { return(m_factory()); } #endif // Fast path, get it from our Gen2 aged m_FreeList. object returnBuffer; if (!m_FreeList.TryPop(out returnBuffer)) { Restock(out returnBuffer); } // Computing free count is expensive enough that we don't want to compute it unless logging is on. if (PinnableBufferCacheEventSource.Log.IsEnabled()) { int numAllocCalls = Interlocked.Increment(ref m_numAllocCalls); if (numAllocCalls >= 1024) { lock (this) { int previousNumAllocCalls = Interlocked.Exchange(ref m_numAllocCalls, 0); if (previousNumAllocCalls >= 1024) { int nonGen2Count = 0; foreach (object o in m_FreeList) { if (GC.GetGeneration(o) < GC.MaxGeneration) { nonGen2Count++; } } PinnableBufferCacheEventSource.Log.WalkFreeListResult(m_CacheName, m_FreeList.Count, nonGen2Count); } } } PinnableBufferCacheEventSource.Log.AllocateBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(returnBuffer), returnBuffer.GetHashCode(), GC.GetGeneration(returnBuffer), m_FreeList.Count); } return(returnBuffer); }
internal void Free(object buffer) { #if ENABLE // Check to see whether or not the cache is disabled. if (m_CacheName == null) { return; } #endif if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.FreeBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), m_FreeList.Count); } if (buffer == null) { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.FreeBufferNull(m_CacheName, m_FreeList.Count); } return; } // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. if ((m_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) { lock (this) { if (GC.GetGeneration(buffer) < GC.MaxGeneration) { // The buffer is not aged, so put it in the non-aged free list. m_moreThanFreeListNeeded = true; PinnableBufferCacheEventSource.Log.FreeBufferStillTooYoung(m_CacheName, m_NotGen2.Count); m_NotGen2.Add(buffer); m_gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); return; } } } // If we discovered that it is indeed Gen2, great, put it in the Gen2 list. m_FreeList.Push(buffer); }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback); } // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. if (count >= 0) { byte[] outBuffer = null; if (_PinnableOutputBufferInUse == null) { if (_PinnableOutputBuffer == null) { _PinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); } _PinnableOutputBufferInUse = buffer; outBuffer = _PinnableOutputBuffer; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } } else { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); } } do { // Request a write IO slot. if (_SslState.CheckEnqueueWrite(asyncRequest)) { // Operation is async and has been queued, return. return; } int chunkBytes = Math.Min(count, _SslState.MaxDataSize); int encryptedBytes; Interop.SecurityStatus errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (errorCode != Interop.SecurityStatus.OK) { ProtocolToken message = new ProtocolToken(null, errorCode); throw new IOException(SR.net_io_encrypt, message.GetException()); } if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } if (asyncRequest != null) { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); IAsyncResult ar = _SslState.InnerStreamAPM.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _SslState.InnerStreamAPM.EndWrite(ar); } else { _SslState.InnerStream.Write(outBuffer, 0, encryptedBytes); } offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _SslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } if (buffer == _PinnableOutputBufferInUse) { _PinnableOutputBufferInUse = null; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback); } // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. if (count >= 0) { byte[] outBuffer = null; if (_pinnableOutputBufferInUse == null) { if (_pinnableOutputBuffer == null) { _pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); } _pinnableOutputBufferInUse = buffer; outBuffer = _pinnableOutputBuffer; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } } else { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); } } do { if (count == 0 && !SslStreamPal.CanEncryptEmptyMessage) { // If it's an empty message and the PAL doesn't support that, // we're done. break; } // Request a write IO slot. if (_sslState.CheckEnqueueWrite(asyncRequest)) { // Operation is async and has been queued, return. return; } int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { // Re-handshake status is not supported. ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.net_io_encrypt, message.GetException()); } if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } if (asyncRequest != null) { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes); if (t.IsCompleted) { t.GetAwaiter().GetResult(); } else { IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } TaskToApm.End(ar); } } else { _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); } offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _sslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } if (buffer == _pinnableOutputBufferInUse) { _pinnableOutputBufferInUse = null; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } }