PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_ctypes/MemoryHolder.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 299 lines | 198 code | 39 blank | 62 comment | 10 complexity | a2b9dd62966f6a4158a63370a2d445cf MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Runtime.CompilerServices;
  17. using System.Runtime.ConstrainedExecution;
  18. using System.Runtime.InteropServices;
  19. using System.Text;
  20. using System.Threading;
  21. using IronPython.Runtime;
  22. #if !SILVERLIGHT
  23. namespace IronPython.Modules {
  24. /// <summary>
  25. /// A wrapper around allocated memory to ensure it gets released and isn't accessed
  26. /// when it could be finalized.
  27. /// </summary>
  28. internal sealed class MemoryHolder : CriticalFinalizerObject {
  29. private readonly IntPtr _data;
  30. private readonly bool _ownsData;
  31. private readonly MemoryHolder _parent;
  32. private readonly int _size;
  33. private PythonDictionary _objects;
  34. /// <summary>
  35. /// Creates a new MemoryHolder and allocates a buffer of the specified size.
  36. /// </summary>
  37. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  38. public MemoryHolder(int size) {
  39. RuntimeHelpers.PrepareConstrainedRegions();
  40. try {
  41. } finally {
  42. _size = size;
  43. _data = NativeFunctions.Calloc(new IntPtr(size));
  44. if (_data == IntPtr.Zero) {
  45. GC.SuppressFinalize(this);
  46. throw new OutOfMemoryException();
  47. }
  48. _ownsData = true;
  49. }
  50. }
  51. /// <summary>
  52. /// Creates a new MemoryHolder at the specified address which is not tracked
  53. /// by us and we will never free.
  54. /// </summary>
  55. public MemoryHolder(IntPtr data, int size) {
  56. GC.SuppressFinalize(this);
  57. _data = data;
  58. _size = size;
  59. }
  60. /// <summary>
  61. /// Creates a new MemoryHolder at the specified address which will keep alive the
  62. /// parent memory holder.
  63. /// </summary>
  64. public MemoryHolder(IntPtr data, int size, MemoryHolder parent) {
  65. GC.SuppressFinalize(this);
  66. _data = data;
  67. _parent = parent;
  68. _objects = parent._objects;
  69. _size = size;
  70. }
  71. /// <summary>
  72. /// Gets the address of the held memory. The caller should ensure the MemoryHolder
  73. /// is always alive as long as the address will continue to be accessed.
  74. /// </summary>
  75. public IntPtr UnsafeAddress {
  76. get {
  77. return _data;
  78. }
  79. }
  80. public int Size {
  81. get {
  82. return _size;
  83. }
  84. }
  85. /// <summary>
  86. /// Gets a list of objects which need to be kept alive for this MemoryHolder to be
  87. /// remain valid.
  88. /// </summary>
  89. public PythonDictionary Objects {
  90. get {
  91. return _objects;
  92. }
  93. set {
  94. _objects = value;
  95. }
  96. }
  97. internal PythonDictionary EnsureObjects() {
  98. if (_objects == null) {
  99. Interlocked.CompareExchange(ref _objects, new PythonDictionary(), null);
  100. }
  101. return _objects;
  102. }
  103. /// <summary>
  104. /// Used to track the lifetime of objects when one memory region depends upon
  105. /// another memory region. For example if you have an array of objects that
  106. /// each have an element which has it's own lifetime the array needs to keep
  107. /// the individual elements alive.
  108. ///
  109. /// The keys used here match CPython's keys as tested by CPython's test_ctypes.
  110. /// Typically they are a string which is the array index, "ffffffff" when
  111. /// from_buffer is used, or when it's a simple type there's just a string
  112. /// instead of the full dictionary - we store that under the key "str".
  113. /// </summary>
  114. internal void AddObject(object key, object value) {
  115. EnsureObjects()[key] = value;
  116. }
  117. public byte ReadByte(int offset) {
  118. byte res = Marshal.ReadByte(_data, offset);
  119. GC.KeepAlive(this);
  120. return res;
  121. }
  122. public short ReadInt16(int offset) {
  123. short res = Marshal.ReadInt16(_data, offset);
  124. GC.KeepAlive(this);
  125. return res;
  126. }
  127. public int ReadInt32(int offset) {
  128. int res = Marshal.ReadInt32(_data, offset);
  129. GC.KeepAlive(this);
  130. return res;
  131. }
  132. public long ReadInt64(int offset) {
  133. long res = Marshal.ReadInt64(_data, offset);
  134. GC.KeepAlive(this);
  135. return res;
  136. }
  137. public IntPtr ReadIntPtr(int offset) {
  138. IntPtr res = Marshal.ReadIntPtr(_data, offset);
  139. GC.KeepAlive(this);
  140. return res;
  141. }
  142. public MemoryHolder ReadMemoryHolder(int offset) {
  143. IntPtr res = Marshal.ReadIntPtr(_data, offset);
  144. return new MemoryHolder(res, IntPtr.Size, this);
  145. }
  146. internal string ReadAnsiString(int offset) {
  147. try {
  148. return Marshal.PtrToStringAnsi(_data.Add(offset));
  149. } finally {
  150. GC.KeepAlive(this);
  151. }
  152. }
  153. internal string ReadUnicodeString(int offset) {
  154. try {
  155. return Marshal.PtrToStringUni(_data.Add(offset));
  156. } finally {
  157. GC.KeepAlive(this);
  158. }
  159. }
  160. internal string ReadAnsiString(int offset, int length) {
  161. try {
  162. return ReadAnsiString(_data, offset, length);
  163. } finally {
  164. GC.KeepAlive(this);
  165. }
  166. }
  167. internal static string ReadAnsiString(IntPtr addr, int offset, int length) {
  168. // instead of Marshal.PtrToStringAnsi we do this because
  169. // ptrToStringAnsi gives special treatment to values >= 128.
  170. StringBuilder res = new StringBuilder();
  171. if (checked(offset + length) < Int32.MaxValue) {
  172. for (int i = 0; i < length; i++) {
  173. res.Append((char)Marshal.ReadByte(addr, offset + i));
  174. }
  175. }
  176. return res.ToString();
  177. }
  178. internal static string ReadAnsiString(IntPtr addr, int offset) {
  179. // instead of Marshal.PtrToStringAnsi we do this because
  180. // ptrToStringAnsi gives special treatment to values >= 128.
  181. StringBuilder res = new StringBuilder();
  182. byte b;
  183. while((b = Marshal.ReadByte(addr, offset++)) != 0) {
  184. res.Append((char)b);
  185. }
  186. return res.ToString();
  187. }
  188. internal string ReadUnicodeString(int offset, int length) {
  189. try {
  190. return Marshal.PtrToStringUni(_data.Add(offset), length);
  191. } finally {
  192. GC.KeepAlive(this);
  193. }
  194. }
  195. public void WriteByte(int offset, byte value) {
  196. Marshal.WriteByte(_data, offset, value);
  197. GC.KeepAlive(this);
  198. }
  199. public void WriteInt16(int offset, short value) {
  200. Marshal.WriteInt16(_data, offset, value);
  201. GC.KeepAlive(this);
  202. }
  203. public void WriteInt32(int offset, int value) {
  204. Marshal.WriteInt32(_data, offset, value);
  205. GC.KeepAlive(this);
  206. }
  207. public void WriteInt64(int offset, long value) {
  208. Marshal.WriteInt64(_data, offset, value);
  209. GC.KeepAlive(this);
  210. }
  211. public void WriteIntPtr(int offset, IntPtr value) {
  212. Marshal.WriteIntPtr(_data, offset, value);
  213. GC.KeepAlive(this);
  214. }
  215. public void WriteIntPtr(int offset, MemoryHolder address) {
  216. Marshal.WriteIntPtr(_data, offset, address.UnsafeAddress);
  217. GC.KeepAlive(this);
  218. GC.KeepAlive(address);
  219. }
  220. /// <summary>
  221. /// Copies the data in data into this MemoryHolder.
  222. /// </summary>
  223. public void CopyFrom(IntPtr source, IntPtr size) {
  224. NativeFunctions.CopyMemory(_data, source, size);
  225. GC.KeepAlive(this);
  226. }
  227. internal void WriteUnicodeString(int offset, string value) {
  228. // TODO: There's gotta be a better way to do this
  229. for (int i = 0; i < value.Length; i++) {
  230. WriteInt16(checked(offset + i * 2), (short)value[i]);
  231. }
  232. }
  233. internal void WriteAnsiString(int offset, string value) {
  234. // TODO: There's gotta be a better way to do this
  235. for (int i = 0; i < value.Length; i++) {
  236. WriteByte(checked(offset + i), (byte)value[i]);
  237. }
  238. }
  239. public MemoryHolder GetSubBlock(int offset) {
  240. // No GC.KeepAlive here because the new MemoryHolder holds onto the previous one.
  241. return new MemoryHolder(_data.Add(offset), _size - offset, this);
  242. }
  243. /// <summary>
  244. /// Copies memory from one location to another keeping the associated memory holders alive during the
  245. /// operation.
  246. /// </summary>
  247. public void CopyTo(MemoryHolder/*!*/ destAddress, int writeOffset, int size) {
  248. NativeFunctions.CopyMemory(destAddress._data.Add(writeOffset), _data, new IntPtr(size));
  249. GC.KeepAlive(destAddress);
  250. GC.KeepAlive(this);
  251. }
  252. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  253. ~MemoryHolder() {
  254. if (_ownsData) {
  255. Marshal.FreeHGlobal(_data);
  256. }
  257. }
  258. }
  259. }
  260. #endif