PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs

https://github.com/gimlism/mono
C# | 393 lines | 278 code | 67 blank | 48 comment | 52 complexity | 7d3f6b3f6b1012961df218bbe458e761 MD5 | raw file
  1. //
  2. // MemoryMappedFile.cs
  3. //
  4. // Authors:
  5. // Zoltan Varga (vargaz@gmail.com)
  6. //
  7. // Copyright (C) 2009, Novell, Inc (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if NET_4_0
  29. using System;
  30. using System.IO;
  31. using System.Collections.Generic;
  32. using Microsoft.Win32.SafeHandles;
  33. using Mono.Unix.Native;
  34. using Mono.Unix;
  35. using System.Runtime.InteropServices;
  36. namespace System.IO.MemoryMappedFiles
  37. {
  38. public class MemoryMappedFile : IDisposable {
  39. MemoryMappedFileAccess fileAccess;
  40. string name;
  41. long fileCapacity;
  42. //
  43. // We allow the use of either the FileStream/keepOpen combo
  44. // or a Unix file descriptor. This way we avoid the dependency on
  45. // Mono's io-layer having the Unix file descriptors mapped to
  46. // the same io-layer handle
  47. //
  48. FileStream stream;
  49. bool keepOpen;
  50. int unix_fd;
  51. public static MemoryMappedFile CreateFromFile (string path)
  52. {
  53. return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
  54. }
  55. public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
  56. {
  57. return CreateFromFile (path, mode, null, 0, MemoryMappedFileAccess.ReadWrite);
  58. }
  59. public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
  60. {
  61. return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
  62. }
  63. public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
  64. {
  65. return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
  66. }
  67. //
  68. // Turns the FileMode into the first half of open(2) flags
  69. //
  70. static OpenFlags ToUnixMode (FileMode mode)
  71. {
  72. switch (mode){
  73. case FileMode.CreateNew:
  74. return OpenFlags.O_CREAT | OpenFlags.O_EXCL;
  75. case FileMode.Create:
  76. return OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
  77. case FileMode.OpenOrCreate:
  78. return OpenFlags.O_CREAT;
  79. case FileMode.Truncate:
  80. return OpenFlags.O_TRUNC;
  81. case FileMode.Append:
  82. return OpenFlags.O_APPEND;
  83. default:
  84. case FileMode.Open:
  85. return 0;
  86. }
  87. }
  88. //
  89. // Turns the MemoryMappedFileAccess into the second half of open(2) flags
  90. //
  91. static OpenFlags ToUnixMode (MemoryMappedFileAccess access)
  92. {
  93. switch (access){
  94. case MemoryMappedFileAccess.CopyOnWrite:
  95. case MemoryMappedFileAccess.ReadWriteExecute:
  96. case MemoryMappedFileAccess.ReadWrite:
  97. return OpenFlags.O_RDWR;
  98. case MemoryMappedFileAccess.Write:
  99. return OpenFlags.O_WRONLY;
  100. case MemoryMappedFileAccess.ReadExecute:
  101. case MemoryMappedFileAccess.Read:
  102. default:
  103. return OpenFlags.O_RDONLY;
  104. }
  105. }
  106. public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
  107. {
  108. if (path == null)
  109. throw new ArgumentNullException ("path");
  110. if (path.Length == 0)
  111. throw new ArgumentException ("path");
  112. if (mapName != null && mapName.Length == 0)
  113. throw new ArgumentException ("mapName");
  114. int fd;
  115. if (MonoUtil.IsUnix){
  116. Stat buf;
  117. if (Syscall.stat (path, out buf) == -1)
  118. UnixMarshal.ThrowExceptionForLastError ();
  119. if ((capacity == 0 && buf.st_size == 0) || (capacity > buf.st_size))
  120. throw new ArgumentException ("capacity");
  121. fd = Syscall.open (path, ToUnixMode (mode) | ToUnixMode (access), FilePermissions.DEFFILEMODE);
  122. if (fd == -1)
  123. UnixMarshal.ThrowExceptionForLastError ();
  124. } else
  125. throw new NotImplementedException ();
  126. return new MemoryMappedFile () {
  127. unix_fd = fd,
  128. fileAccess = access,
  129. name = mapName,
  130. fileCapacity = capacity
  131. };
  132. }
  133. static void ConfigureUnixFD (IntPtr handle, HandleInheritability h)
  134. {
  135. // TODO: Mono.Posix is lacking O_CLOEXEC definitions for fcntl.
  136. }
  137. [DllImport("kernel32.dll", SetLastError = true)]
  138. static extern bool SetHandleInformation (IntPtr hObject, int dwMask, int dwFlags);
  139. static void ConfigureWindowsFD (IntPtr handle, HandleInheritability h)
  140. {
  141. SetHandleInformation (handle, 1 /* FLAG_INHERIT */, h == HandleInheritability.None ? 0 : 1);
  142. }
  143. [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
  144. public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
  145. MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
  146. bool leaveOpen)
  147. {
  148. if (fileStream == null)
  149. throw new ArgumentNullException ("fileStream");
  150. if (mapName != null && mapName.Length == 0)
  151. throw new ArgumentException ("mapName");
  152. if ((capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
  153. throw new ArgumentException ("capacity");
  154. if (MonoUtil.IsUnix)
  155. ConfigureUnixFD (fileStream.Handle, inheritability);
  156. else
  157. ConfigureWindowsFD (fileStream.Handle, inheritability);
  158. return new MemoryMappedFile () {
  159. stream = fileStream,
  160. fileAccess = access,
  161. name = mapName,
  162. fileCapacity = capacity,
  163. keepOpen = leaveOpen
  164. };
  165. }
  166. [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
  167. public static MemoryMappedFile CreateNew (string mapName, long capacity)
  168. {
  169. return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
  170. }
  171. [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
  172. public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access)
  173. {
  174. return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
  175. }
  176. [MonoLimitation ("CreateNew requires that mapName be a file name on Unix; options and memoryMappedFileSecurity are ignored")]
  177. public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
  178. MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
  179. HandleInheritability handleInheritability)
  180. {
  181. return CreateFromFile (mapName, FileMode.CreateNew, mapName, capacity, access);
  182. }
  183. [MonoLimitation ("CreateOrOpen requires that mapName be a file name on Unix")]
  184. public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
  185. {
  186. return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
  187. }
  188. [MonoLimitation ("CreateOrOpen requires that mapName be a file name on Unix")]
  189. public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
  190. {
  191. return CreateFromFile (mapName, FileMode.OpenOrCreate, mapName, capacity, access);
  192. }
  193. [MonoTODO]
  194. public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability handleInheritability)
  195. {
  196. throw new NotImplementedException ();
  197. }
  198. [MonoTODO]
  199. public static MemoryMappedFile OpenExisting (string mapName)
  200. {
  201. throw new NotImplementedException ();
  202. }
  203. [MonoTODO]
  204. public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
  205. {
  206. throw new NotImplementedException ();
  207. }
  208. [MonoTODO]
  209. public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
  210. {
  211. throw new NotImplementedException ();
  212. }
  213. public MemoryMappedViewStream CreateViewStream ()
  214. {
  215. return CreateViewStream (0, 0);
  216. }
  217. public MemoryMappedViewStream CreateViewStream (long offset, long size)
  218. {
  219. return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
  220. }
  221. public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
  222. {
  223. return new MemoryMappedViewStream (stream != null ? (int)stream.Handle : unix_fd, offset, size, access);
  224. }
  225. public MemoryMappedViewAccessor CreateViewAccessor ()
  226. {
  227. return CreateViewAccessor (0, 0);
  228. }
  229. public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
  230. {
  231. return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
  232. }
  233. public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
  234. {
  235. int file_handle = stream != null ? (int) stream.Handle : unix_fd;
  236. return new MemoryMappedViewAccessor (file_handle, offset, size, access);
  237. }
  238. MemoryMappedFile ()
  239. {
  240. }
  241. public void Dispose ()
  242. {
  243. Dispose (true);
  244. }
  245. protected virtual void Dispose (bool disposing)
  246. {
  247. if (disposing){
  248. if (stream != null){
  249. if (keepOpen == false)
  250. stream.Close ();
  251. unix_fd = -1;
  252. }
  253. if (unix_fd != -1)
  254. Syscall.close (unix_fd);
  255. unix_fd = -1;
  256. stream = null;
  257. }
  258. }
  259. [MonoTODO]
  260. public MemoryMappedFileSecurity GetAccessControl ()
  261. {
  262. throw new NotImplementedException ();
  263. }
  264. [MonoTODO]
  265. public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
  266. {
  267. throw new NotImplementedException ();
  268. }
  269. [MonoTODO]
  270. public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
  271. get {
  272. throw new NotImplementedException ();
  273. }
  274. }
  275. static int pagesize;
  276. static MmapProts ToUnixProts (MemoryMappedFileAccess access)
  277. {
  278. switch (access){
  279. case MemoryMappedFileAccess.ReadWrite:
  280. return MmapProts.PROT_WRITE | MmapProts.PROT_READ;
  281. case MemoryMappedFileAccess.Write:
  282. return MmapProts.PROT_WRITE;
  283. case MemoryMappedFileAccess.CopyOnWrite:
  284. return MmapProts.PROT_WRITE | MmapProts.PROT_READ;
  285. case MemoryMappedFileAccess.ReadExecute:
  286. return MmapProts.PROT_EXEC;
  287. case MemoryMappedFileAccess.ReadWriteExecute:
  288. return MmapProts.PROT_WRITE | MmapProts.PROT_READ | MmapProts.PROT_EXEC;
  289. case MemoryMappedFileAccess.Read:
  290. default:
  291. return MmapProts.PROT_READ;
  292. }
  293. }
  294. internal static unsafe void MapPosix (int file_handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr map_addr, out int offset_diff)
  295. {
  296. if (pagesize == 0)
  297. pagesize = Syscall.getpagesize ();
  298. Stat buf;
  299. Syscall.fstat (file_handle, out buf);
  300. long fsize = buf.st_size;
  301. if (size == 0 || size > fsize)
  302. size = fsize;
  303. // Align offset
  304. long real_offset = offset & ~(pagesize - 1);
  305. offset_diff = (int)(offset - real_offset);
  306. // FIXME: Need to determine the unix fd for the file, Handle is only
  307. // equal to it by accident
  308. //
  309. // The new API no longer uses FileStream everywhere, but exposes instead
  310. // the filename (with one exception), we could move this API to use
  311. // file descriptors instead of the FileStream plus its Handle.
  312. //
  313. map_addr = Syscall.mmap (IntPtr.Zero, (ulong) size,
  314. ToUnixProts (access),
  315. access == MemoryMappedFileAccess.CopyOnWrite ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED,
  316. file_handle, real_offset);
  317. if (map_addr == (IntPtr)(-1))
  318. throw new IOException ("mmap failed for fd#" + file_handle + "(" + offset + ", " + size + ")");
  319. }
  320. internal static bool UnmapPosix (IntPtr map_addr, ulong map_size)
  321. {
  322. return Syscall.munmap (map_addr, map_size) == 0;
  323. }
  324. }
  325. }
  326. #endif