The Labs \ Source Viewer \ SSCLI \ System.IO \ ByteBufferPool

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. //==========================================================================
  16. // File: ByteBufferPool.cs
  17. //
  18. // Summary: Stream used for reading from a socket by remoting channels.
  19. //
  20. //==========================================================================
  21. using System;
  22. using System.Threading;
  23. namespace System.IO
  24. {
  25.    
  26.     internal interface IByteBufferPool
  27.     {
  28.         byte[] GetBuffer();
  29.         void ReturnBuffer(byte[] buffer);
  30.     }
  31.    
  32.    
  33.     // This isn't actually a buffer pool. It always creates a new byte buffer.
  34.     internal class ByteBufferAllocator : IByteBufferPool
  35.     {
  36.         private int _bufferSize;
  37.        
  38.         public ByteBufferAllocator(int bufferSize)
  39.         {
  40.             _bufferSize = bufferSize;
  41.         }
  42.        
  43.         public byte[] GetBuffer()
  44.         {
  45.             return new byte[_bufferSize];
  46.         }
  47.        
  48.         public void ReturnBuffer(byte[] buffer)
  49.         {
  50.         }
  51.        
  52.     }
  53.     // ByteBufferAllocator
  54.    
  55.     internal class ByteBufferPool : IByteBufferPool
  56.     {
  57.         private byte[][] _bufferPool = null;
  58.        
  59.         private int _current;
  60.         // -1 for none
  61.         private int _last;
  62.         private int _max;
  63.         // maximum number of buffers to pool
  64.         private int _bufferSize;
  65.        
  66.         private object _controlCookie = "cookie object";
  67.        
  68.        
  69.         public ByteBufferPool(int maxBuffers, int bufferSize)
  70.         {
  71.             _max = maxBuffers;
  72.             _bufferPool = new byte[_max][];
  73.             _bufferSize = bufferSize;
  74.            
  75.             _current = -1;
  76.             _last = -1;
  77.         }
  78.         // ByteBufferPool
  79.        
  80.         public byte[] GetBuffer()
  81.         {
  82.             object cookie = null;
  83.            
  84.             try {
  85.                 // If a ThreadAbortException gets thrown after the exchange,
  86.                 // but before the result is assigned to cookie, then the
  87.                 // control cookie is lost forever. However, the buffer pool
  88.                 // will still function normally and return everybody a new
  89.                 // buffer each time (that isn't very likely to happen,
  90.                 // so we don't really care).
  91.                 cookie = Interlocked.Exchange(ref _controlCookie, null);
  92.                
  93.                 if (cookie != null) {
  94.                     // we have the control cookie, so take a buffer
  95.                    
  96.                     if (_current == -1) {
  97.                         _controlCookie = cookie;
  98.                         // no pooled buffers available
  99.                         return new byte[_bufferSize];
  100.                     }
  101.                     else {
  102.                         // grab next available buffer
  103.                         byte[] buffer = _bufferPool[_current];
  104.                         _bufferPool[_current] = null;
  105.                        
  106.                         // update "current" index
  107.                         if (_current == _last) {
  108.                             // this is the last free buffer
  109.                             _current = -1;
  110.                         }
  111.                         else {
  112.                             _current = (_current + 1) % _max;
  113.                         }
  114.                        
  115.                         _controlCookie = cookie;
  116.                         return buffer;
  117.                     }
  118.                 }
  119.                 else {
  120.                     // we don't have the control cookie, so just create a new buffer since
  121.                     // there will probably be a lot of contention anyway.
  122.                     return new byte[_bufferSize];
  123.                 }
  124.             }
  125.             catch (ThreadAbortException) {
  126.                 if (cookie != null) {
  127.                     // This should be rare, so just reset
  128.                     // everything to the initial state.
  129.                     _current = -1;
  130.                     _last = -1;
  131.                    
  132.                     // restore cookie
  133.                     _controlCookie = cookie;
  134.                 }
  135.                
  136.                 throw;
  137.             }
  138.         }
  139.         // GetBuffer
  140.        
  141.         public void ReturnBuffer(byte[] buffer)
  142.         {
  143.             if (buffer == null)
  144.                 throw new ArgumentNullException("buffer");
  145.            
  146.            
  147.             // The purpose of the buffer pool is to try to reduce the
  148.             // amount of garbage generated, so it doesn't matter if
  149.             // the buffer gets tossed out. Since we don't want to
  150.             // take the perf hit of taking a lock, we only return
  151.             // the buffer if we can grab the control cookie.
  152.            
  153.             object cookie = null;
  154.            
  155.             try {
  156.                 // If a ThreadAbortException gets thrown after the exchange,
  157.                 // but before the result is assigned to cookie, then the
  158.                 // control cookie is lost forever. However, the buffer pool
  159.                 // will still function normally and return everybody a new
  160.                 // buffer each time (that isn't very likely to happen,
  161.                 // so we don't really care).
  162.                 cookie = Interlocked.Exchange(ref _controlCookie, null);
  163.                
  164.                 if (cookie != null) {
  165.                     if (_current == -1) {
  166.                         _bufferPool[0] = buffer;
  167.                         _current = 0;
  168.                         _last = 0;
  169.                     }
  170.                     else {
  171.                         int newLast = (_last + 1) % _max;
  172.                         if (newLast != _current) {
  173.                             // the pool isn't full so store this buffer
  174.                             _last = newLast;
  175.                             _bufferPool[_last] = buffer;
  176.                         }
  177.                     }
  178.                    
  179.                     _controlCookie = cookie;
  180.                 }
  181.             }
  182.             catch (ThreadAbortException) {
  183.                 if (cookie != null) {
  184.                     // This should be rare, so just reset
  185.                     // everything to the initial state.
  186.                     _current = -1;
  187.                     _last = -1;
  188.                    
  189.                     // restore cookie
  190.                     _controlCookie = cookie;
  191.                 }
  192.                
  193.                 throw;
  194.             }
  195.         }
  196.         // ReturnBuffer
  197.        
  198.        
  199.     }
  200.     // ByteBufferPool
  201.    
  202. }
  203. // namespace System.IO

Developer Fusion