1. // Copyright (C) 2010 OfficeSIP Communications
  2. // This source is subject to the GNU General Public License.
  3. // Please see Notice.txt for details.
  4.  
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Threading;
  9.  
  10. namespace SocketServers
  11. {
  12. static class ByteArraySegmentHelpers
  13. {
  14. public static bool IsValid(this ArraySegment<byte> segment)
  15. {
  16. return segment.Array != null && segment.Offset >= 0 && segment.Count > 0;
  17. }
  18.  
  19. public static bool IsInvalid(this ArraySegment<byte> segment)
  20. {
  21. return segment.Array == null || segment.Offset < 0 || segment.Count <= 0;
  22. }
  23. }
  24.  
  25. public class BufferManager1
  26. {
  27. private InternalBufferManager[] buffers;
  28. private SafeDictionary<byte[], int> buffersIndexes;
  29. private int maxIndex;
  30. private int currentIndex;
  31. private const int segments = 128;
  32. private const int segmentSize = 8192;
  33.  
  34. public BufferManager1()
  35. {
  36. buffers = new InternalBufferManager[2000];
  37. buffersIndexes = new SafeDictionary<byte[], int>();
  38. buffers[0] = new InternalBufferManager(segments, segmentSize);
  39. currentIndex = 0;
  40. maxIndex = 0;
  41. }
  42.  
  43. public void Allocate(IList<ArraySegment<byte>> list, int size)
  44. {
  45. int index = currentIndex;
  46.  
  47. for (; ; )
  48. {
  49. do
  50. {
  51. int segmentsCount = (size + segmentSize - 1) / segmentSize;
  52.  
  53. if (buffers[index].FreeCount > segmentsCount)
  54. {
  55. var segment = buffers[index].Allocate(size);
  56. if (segment.IsValid())
  57. {
  58. list.Add(segment);
  59. size -= segment.Count;
  60. }
  61.  
  62. if (currentIndex != index &&
  63. buffers[index].FreeCount > buffers[currentIndex].FreeCount)
  64. {
  65. Interlocked.Exchange(ref currentIndex, index);
  66. }
  67.  
  68. if (size == 0)
  69. return;
  70. }
  71.  
  72. index = (index < maxIndex) ? index + 1 : 0;
  73. }
  74. while (index != currentIndex);
  75.  
  76. index = AddInternalBuffer();
  77. }
  78. }
  79.  
  80. public void Free(IList<ArraySegment<byte>> list)
  81. {
  82. int length = list.Count;
  83. for (int i = 0; i < length; i++)
  84. Free(list[i]);
  85. }
  86.  
  87. public void Free(ArraySegment<byte> segment)
  88. {
  89. buffers[buffersIndexes.GetValue(segment.Array)].Free(segment);
  90. }
  91.  
  92. public void AddRef(ArraySegment<byte> segment)
  93. {
  94. buffers[buffersIndexes.GetValue(segment.Array)].AddRef(segment);
  95. }
  96.  
  97. public int SegmentSize
  98. {
  99. get { return segmentSize; }
  100. }
  101.  
  102. private int AddInternalBuffer()
  103. {
  104. var buffer = new InternalBufferManager(segments, segmentSize);
  105.  
  106. for (; ; )
  107. {
  108. int index = maxIndex + 1;
  109. if (Interlocked.CompareExchange(ref buffers[index], buffer, null) == null)
  110. {
  111. buffersIndexes.Add(buffer.Buffer, index);
  112. return Interlocked.Increment(ref maxIndex);
  113. }
  114. }
  115. }
  116.  
  117. class InternalBufferManager
  118. {
  119. private byte[] _buffer;
  120. private int[] _lockCounters;
  121. private int _freeCount;
  122. private int _segmentSize;
  123. private int _segments;
  124.  
  125. public InternalBufferManager(int segments, int segmentSize)
  126. {
  127. _segmentSize = segmentSize;
  128. _buffer = new byte[segments * segmentSize];
  129. _lockCounters = new int[segments];
  130. _freeCount = segments;
  131. _segments = segments;
  132. }
  133.  
  134. public ArraySegment<byte> Allocate(int size)
  135. {
  136. int startIndex = 0;
  137.  
  138. while (_freeCount > 0)
  139. {
  140. if (Interlocked.CompareExchange(ref _lockCounters[startIndex], 1, 0) == 0)
  141. {
  142. Interlocked.Decrement(ref _freeCount);
  143.  
  144. int allocatedSize = 0;
  145. int endIndex = startIndex + 1;
  146.  
  147. while (size > allocatedSize && _freeCount > 0 && endIndex < _segments)
  148. {
  149. if (Interlocked.CompareExchange(ref _lockCounters[endIndex], 1, 0) != 0)
  150. break;
  151.  
  152. Interlocked.Decrement(ref _freeCount);
  153. endIndex += 1;
  154. allocatedSize += _segmentSize;
  155. }
  156.  
  157. return new ArraySegment<byte>(_buffer, (endIndex - startIndex) * _segmentSize,
  158. (size < allocatedSize) ? size : allocatedSize);
  159. }
  160.  
  161. startIndex = (startIndex + 1) % _segments;
  162. }
  163.  
  164. return new ArraySegment<byte>();
  165. }
  166.  
  167. public void Free(ArraySegment<byte> segment)
  168. {
  169. int startIndex = GetSegmentIndex(segment.Offset);
  170. int endIndex = GetSegmentIndex(segment.Offset + segment.Count - 1);
  171.  
  172. for (; startIndex < endIndex; startIndex++)
  173. {
  174. switch (Interlocked.Decrement(ref _lockCounters[startIndex]))
  175. {
  176. case 0:
  177. Interlocked.Increment(ref _freeCount);
  178. break;
  179. #if DEBUG
  180. case -1:
  181. throw new InvalidOperationException("Buffer segment was freed before.");
  182. #endif
  183. }
  184. }
  185. }
  186.  
  187. public void AddRef(ArraySegment<byte> segment)
  188. {
  189. int startIndex = GetSegmentIndex(segment.Offset);
  190. int endIndex = GetSegmentIndex(segment.Offset + segment.Count - 1);
  191.  
  192. for (; startIndex < endIndex; startIndex++)
  193. {
  194. #if DEBUG
  195. if (_lockCounters[startIndex] == 0)
  196. throw new InvalidOperationException("Buffer segment was not allocated yet.");
  197. #endif
  198. Interlocked.Increment(ref _lockCounters[startIndex]);
  199. }
  200. }
  201.  
  202. public int FreeCount
  203. {
  204. get { return _freeCount; }
  205. }
  206.  
  207. public byte[] Buffer
  208. {
  209. get { return _buffer; }
  210. }
  211.  
  212. private int GetSegmentIndex(int offset)
  213. {
  214. return offset / _segmentSize;
  215. }
  216. }
  217. }
  218.  
  219. #region List1
  220.  
  221. class List1<T>
  222. : IList<T>
  223. {
  224. private T item;
  225. private Enumerator1 enumerator;
  226.  
  227. public List1(T item)
  228. {
  229. this.item = item;
  230. }
  231.  
  232. void ICollection<T>.Add(T item)
  233. {
  234. }
  235.  
  236. void ICollection<T>.Clear()
  237. {
  238. }
  239.  
  240. bool ICollection<T>.Contains(T item)
  241. {
  242. return false;
  243. }
  244.  
  245. void ICollection<T>.CopyTo(T[] array, int arrayIndex)
  246. {
  247. array[arrayIndex] = item;
  248. }
  249.  
  250. bool ICollection<T>.Remove(T item)
  251. {
  252. return false;
  253. }
  254.  
  255. int ICollection<T>.Count
  256. {
  257. get { return 1; }
  258. }
  259.  
  260. bool ICollection<T>.IsReadOnly
  261. {
  262. get { return true; }
  263. }
  264.  
  265. int IList<T>.IndexOf(T item)
  266. {
  267. return -1;
  268. }
  269.  
  270. void IList<T>.Insert(int index, T item)
  271. {
  272. }
  273.  
  274. void IList<T>.RemoveAt(int index)
  275. {
  276. }
  277.  
  278. T IList<T>.this[int index]
  279. {
  280. get { return item; }
  281. set { }
  282. }
  283.  
  284. IEnumerator IEnumerable.GetEnumerator()
  285. {
  286. if (enumerator == null)
  287. enumerator = new Enumerator1(this);
  288. return enumerator;
  289. }
  290.  
  291. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  292. {
  293. if (enumerator == null)
  294. enumerator = new Enumerator1(this);
  295. return enumerator;
  296. }
  297.  
  298.  
  299. class Enumerator1
  300. : IEnumerator<T>
  301. {
  302. List1<T> list1;
  303.  
  304. public Enumerator1(List1<T> list1)
  305. {
  306. this.list1 = list1;
  307. }
  308.  
  309. public void Reset()
  310. {
  311. }
  312.  
  313. public bool MoveNext()
  314. {
  315. return false;
  316. }
  317.  
  318. public Object Current
  319. {
  320. get { return list1.item; }
  321. }
  322.  
  323. T IEnumerator<T>.Current
  324. {
  325. get { return list1.item; }
  326. }
  327.  
  328. void IDisposable.Dispose()
  329. {
  330. }
  331. }
  332. }
  333.  
  334. #endregion
  335. }
  336.