RamStorage.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace SvdCli.Storage
  4. {
  5. public class UnmanagedGigabyteRamDisk : IStorage
  6. {
  7. private readonly IntPtr[] _blocks;
  8. private bool _isInit;
  9. public string ProductId { get; } = "Svd RamDisk";
  10. public string ProductVersion { get; } = "1.0";
  11. public string TypeDescription { get; } = "RamDisk";
  12. public uint BlockSize { get; } = 512;
  13. public ulong BlockCount { get; }
  14. public uint MaxTransferLength { get; } = 64 * CapacityUnits.KiloByte;
  15. public bool SupportTrim { get; } = false;
  16. public bool WriteProtect { get; set; } = false;
  17. public void Init()
  18. {
  19. if (_isInit) return;
  20. try
  21. {
  22. for (var i = 0; i < _blocks.Length; i++)
  23. {
  24. _blocks[i] = Marshal.AllocHGlobal(CapacityUnits.Gigabyte);
  25. }
  26. _isInit = true;
  27. }
  28. catch (OutOfMemoryException)
  29. {
  30. Exit();
  31. throw;
  32. }
  33. }
  34. public void Exit()
  35. {
  36. foreach (var block in _blocks)
  37. {
  38. if (block != IntPtr.Zero) Marshal.FreeHGlobal(block);
  39. }
  40. GC.Collect();
  41. GC.WaitForPendingFinalizers();
  42. _isInit = false;
  43. }
  44. public UnmanagedGigabyteRamDisk(int sizeInGigabyte)
  45. {
  46. _blocks = new IntPtr[sizeInGigabyte];
  47. var size = (ulong)sizeInGigabyte * CapacityUnits.Gigabyte;
  48. BlockCount = size / BlockSize;
  49. }
  50. private void ReadInternal(byte[] buffer, int offset, int count, int gigabyteIndex, int gigabyteOffset)
  51. {
  52. Marshal.Copy(_blocks[gigabyteIndex] + gigabyteOffset, buffer, offset, count);
  53. }
  54. private void WriteInternal(byte[] buffer, int offset, int count, int gigabyteIndex, int gigabyteOffset)
  55. {
  56. Marshal.Copy(buffer, offset, _blocks[gigabyteIndex] + gigabyteOffset, count);
  57. }
  58. public void Read(byte[] buffer, ulong blockIndex, uint blockCount)
  59. {
  60. var rawOffset = blockIndex * BlockSize;
  61. var rawSize = blockCount * BlockSize;
  62. for (var i = 0; i < rawSize;)
  63. {
  64. var gigabyteIndex = (int)(rawOffset / CapacityUnits.Gigabyte);
  65. var gigabyteOffset = (int)(rawOffset % CapacityUnits.Gigabyte);
  66. var bytesToRead = CapacityUnits.Gigabyte - gigabyteOffset;
  67. if (i + bytesToRead > rawSize)
  68. {
  69. bytesToRead = (int)(rawSize - i);
  70. }
  71. ReadInternal(buffer, i, bytesToRead, gigabyteIndex, gigabyteOffset);
  72. i += bytesToRead;
  73. rawOffset += (ulong)bytesToRead;
  74. }
  75. }
  76. public void Write(byte[] buffer, ulong blockIndex, uint blockCount)
  77. {
  78. var rawOffset = blockIndex * BlockSize;
  79. for (var i = 0; i < buffer.Length;)
  80. {
  81. var gigabyteIndex = (int)(rawOffset / CapacityUnits.Gigabyte);
  82. var gigabyteOffset = (int)(rawOffset % CapacityUnits.Gigabyte);
  83. var bytesToWrite = CapacityUnits.Gigabyte - gigabyteOffset;
  84. if (i + bytesToWrite > buffer.Length)
  85. {
  86. bytesToWrite = buffer.Length - i;
  87. }
  88. WriteInternal(buffer, i, bytesToWrite, gigabyteIndex, gigabyteOffset);
  89. i += bytesToWrite;
  90. rawOffset += (ulong)bytesToWrite;
  91. }
  92. }
  93. public void Flush()
  94. {
  95. }
  96. public void Trim(params TrimDescriptor[] descriptors)
  97. {
  98. }
  99. }
  100. }