2009-12-14 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Mon, 14 Dec 2009 05:24:34 +0000 (05:24 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Mon, 14 Dec 2009 05:24:34 +0000 (05:24 -0000)
        * MemoryMappedFile.cs: Make this by default use the native
        interface (Mono.Unix.Native.Syscall) to map files and only support
        the FileStream.Handle when the user explicitly uses this API.

        The reason is that currently the code depends on the io-layer
        keeping parity between our handles and Unix file descriptors, this
        removes this dependency for most cases.

svn path=/trunk/mcs/; revision=148366

mcs/class/System.Core/System.IO.MemoryMappedFiles/ChangeLog
mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs
mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedViewAccessor.cs
mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedViewStream.cs

index eba4295bc207d72b016cd811a7526c4b4241a7dd..1466f2eb6cc416841092a6110878900f534888a4 100644 (file)
@@ -1,3 +1,13 @@
+2009-12-14  Miguel de Icaza  <miguel@novell.com>
+
+       * MemoryMappedFile.cs: Make this by default use the native
+       interface (Mono.Unix.Native.Syscall) to map files and only support
+       the FileStream.Handle when the user explicitly uses this API.
+
+       The reason is that currently the code depends on the io-layer
+       keeping parity between our handles and Unix file descriptors, this
+       removes this dependency for most cases. 
+
 2009-12-13  Miguel de Icaza  <miguel@novell.com>
 
        * MemoryMappedViewAccessor.cs: Derive from
index 63a859c41203791a7d3e849ca372aab02b7b8548..7376bc5ae0628a357bac38f7b663867715b8ecd2 100644 (file)
@@ -33,6 +33,7 @@ using System.IO;
 using System.Collections.Generic;
 using Microsoft.Win32.SafeHandles;
 using Mono.Unix.Native;
+using Mono.Unix;
 using System.Runtime.InteropServices;
 
 namespace System.IO.MemoryMappedFiles
@@ -40,11 +41,20 @@ namespace System.IO.MemoryMappedFiles
        public class MemoryMappedFile : IDisposable {
                MemoryMappedFileAccess fileAccess;
                string name;
-               FileStream stream;
                long fileCapacity;
+
+               //
+               // We allow the use of either the FileStream/keepOpen combo
+               // or a Unix file descriptor.  This way we avoid the dependency on
+               // Mono's io-layer having the Unix file descriptors mapped to
+               // the same io-layer handle
+               //
+               FileStream stream;
                bool keepOpen;
+               int unix_fd;
                
-               public static MemoryMappedFile CreateFromFile (FileStream fileStream) {
+               public static MemoryMappedFile CreateFromFile (FileStream fileStream)
+               {
                        if (fileStream == null)
                                throw new ArgumentNullException ("fileStream");
 
@@ -75,6 +85,53 @@ namespace System.IO.MemoryMappedFiles
                        return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
                }
 
+               //
+               // Turns the FileMode into the first half of open(2) flags
+               //
+               static OpenFlags ToUnixMode (FileMode mode)
+               {
+                       switch (mode){
+                       case FileMode.CreateNew:
+                               return OpenFlags.O_CREAT | OpenFlags.O_EXCL;
+                               
+                       case FileMode.Create:
+                               return OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
+                               
+                       case FileMode.OpenOrCreate:
+                               return OpenFlags.O_CREAT;
+                               
+                       case FileMode.Truncate:
+                               return OpenFlags.O_TRUNC;
+                               
+                       case FileMode.Append:
+                               return OpenFlags.O_APPEND;
+                       default:
+                       case FileMode.Open:
+                               return 0;
+                       }
+               }
+
+               //
+               // Turns the MemoryMappedFileAccess into the second half of open(2) flags
+               //
+               static OpenFlags ToUnixMode (MemoryMappedFileAccess access)
+               {
+                       switch (access){
+                       case MemoryMappedFileAccess.CopyOnWrite:
+                       case MemoryMappedFileAccess.ReadWriteExecute:
+                       case MemoryMappedFileAccess.ReadWrite:
+                               return OpenFlags.O_RDWR;
+                               
+                       case MemoryMappedFileAccess.Write:
+                               return OpenFlags.O_WRONLY;
+
+                       case MemoryMappedFileAccess.ReadExecute:
+                       case MemoryMappedFileAccess.Read:
+                       default:
+                               return OpenFlags.O_RDONLY;
+                       }
+               }
+
                public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
                {
                        if (path == null)
@@ -83,18 +140,29 @@ namespace System.IO.MemoryMappedFiles
                                throw new ArgumentException ("path");
                        if (mapName != null && mapName.Length == 0)
                                throw new ArgumentException ("mapName");
-                       var fileStream = File.Open (path, mode);
 
-                       if ((capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length)){
-                               fileStream.Close ();
-                               throw new ArgumentException ("capacity");
-                       }
+                       int fd;
+                       if (MonoUtil.IsUnix){
+                               Stat buf;
+                               if (Syscall.stat (path, out buf) == -1)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               if ((capacity == 0 && buf.st_size == 0) || (capacity > buf.st_size))
+                                       throw new ArgumentException ("capacity");
+                               
+                               fd = Syscall.open (path, ToUnixMode (mode) | ToUnixMode (access), FilePermissions.DEFFILEMODE);
+
+                               if (fd == -1)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                       } else
+                               throw new NotImplementedException ();
+                       
                        return new MemoryMappedFile () {
-                               stream = fileStream,
+                               unix_fd = fd,
                                fileAccess = access,
                                name = mapName,
                                fileCapacity = capacity
-                                       };
+                       };
                }
 
                public static void ConfigureUnixFD (IntPtr handle, HandleInheritability h)
@@ -136,25 +204,25 @@ namespace System.IO.MemoryMappedFiles
                        };
                }
 
-
-               [MonoTODO]
+               [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
                public static MemoryMappedFile CreateNew (string mapName, long capacity)
                {
-                       throw new NotImplementedException ();
+                       return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
                }
 
-               [MonoTODO]
+               [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
                public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access) 
                {
-                       throw new NotImplementedException ();
+                       return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
                }
 
-               /*
-               [MonoTODO]
-                       public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability handleInheritability) {
-                       throw new NotImplementedException ();
+               [MonoLimitation ("CreateNew requires that mapName be a file name on Unix; options and memoryMappedFileSecurity are ignored")]
+               public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
+                                                         MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
+                                                         HandleInheritability handleInheritability)
+               {
+                       return CreateFromFile (mapName, FileMode.CreateNew, mapName, capacity, access);
                }
-               */
 
                [MonoTODO]
                        public static MemoryMappedFile CreateOrOpen (string mapName, long capacity) {
@@ -183,10 +251,9 @@ namespace System.IO.MemoryMappedFiles
                        return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
                }
 
-               [MonoTODO]
                public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
                {
-                       return new MemoryMappedViewStream (stream, offset, size, access);
+                       return new MemoryMappedViewStream (stream != null ? (int)stream.Handle : unix_fd, offset, size, access);
                }
 
                public MemoryMappedViewAccessor CreateViewAccessor ()
@@ -199,10 +266,11 @@ namespace System.IO.MemoryMappedFiles
                        return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
                }
 
-               [MonoTODO]
                public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
                {
-                       return new MemoryMappedViewAccessor (stream, offset, size, access);
+                       int file_handle = stream != null ? (int) stream.Handle : unix_fd;
+                       
+                       return new MemoryMappedViewAccessor (file_handle, offset, size, access);
                }
 
                MemoryMappedFile ()
@@ -217,8 +285,14 @@ namespace System.IO.MemoryMappedFiles
                protected virtual void Dispose (bool disposing)
                {
                        if (disposing){
-                               if (stream != null && keepOpen == false)
-                                       stream.Close ();
+                               if (stream != null){
+                                       if (keepOpen == false)
+                                               stream.Close ();
+                                       unix_fd = -1;
+                               }
+                               if (unix_fd != -1)
+                                       Syscall.close (unix_fd);
+                               unix_fd = -1;
                                stream = null;
                        }
                }
@@ -257,15 +331,16 @@ namespace System.IO.MemoryMappedFiles
                        default:
                                return MmapProts.PROT_READ;
                        }
-                       
                }
 
-               internal static unsafe void MapPosix (FileStream file, long offset, long size, MemoryMappedFileAccess access, out IntPtr map_addr, out int offset_diff)
+               internal static unsafe void MapPosix (int file_handle, long offset, long size, MemoryMappedFileAccess access, out IntPtr map_addr, out int offset_diff)
                {
                        if (pagesize == 0)
                                pagesize = Syscall.getpagesize ();
 
-                       long fsize = file.Length;
+                       Stat buf;
+                       Syscall.fstat (file_handle, out buf);
+                       long fsize = buf.st_size;
 
                        if (size == 0 || size > fsize)
                                size = fsize;
@@ -285,17 +360,12 @@ namespace System.IO.MemoryMappedFiles
                        map_addr = Syscall.mmap (IntPtr.Zero, (ulong) size,
                                                 ToUnixProts (access),
                                                 access == MemoryMappedFileAccess.CopyOnWrite ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED,
-                                                (int)file.Handle, real_offset);
-                       
+                                                file_handle, real_offset);
+
                        if (map_addr == (IntPtr)(-1))
-                               throw new IOException ("mmap failed for " + file + "(" + offset + ", " + size + ")");
+                               throw new IOException ("mmap failed for fd#" + file_handle + "(" + offset + ", " + size + ")");
                }
 
-               internal static void FlushPosix (FileStream file)
-               {
-                       Syscall.fsync ((int) file.Handle);
-               }
-               
                internal static bool UnmapPosix (IntPtr map_addr, ulong map_size)
                {
                        return Syscall.munmap (map_addr, map_size) == 0;
index bb2a49529de96967727f2e2e20dbaec2f7cdfb49..e1fc156c2a36f133dafe22c7e30c2afdd9c4e823 100644 (file)
@@ -32,17 +32,18 @@ using System;
 using System.IO;
 using System.Collections.Generic;
 using Microsoft.Win32.SafeHandles;
+using Mono.Unix.Native;
 
 namespace System.IO.MemoryMappedFiles
 {
        public class MemoryMappedViewAccessor : UnmanagedMemoryAccessor {
-               FileStream file;
+               int file_handle;
                IntPtr mmap_addr;
                SafeMemoryMappedViewHandle handle;
 
-               internal MemoryMappedViewAccessor (FileStream file, long offset, long size, MemoryMappedFileAccess access)
+               internal MemoryMappedViewAccessor (int file_handle, long offset, long size, MemoryMappedFileAccess access)
                {
-                       this.file = file;
+                       this.file_handle = file_handle;
                        if (MonoUtil.IsUnix)
                                CreatePosix (offset, size, access);
                        else
@@ -68,15 +69,11 @@ namespace System.IO.MemoryMappedFiles
                        }
                }
                
-               unsafe void CreatePosix (long offset, long size, MemoryMappedFileAccess access) {
-                       long fsize = file.Length;
-
-                       if (size == 0 || size > fsize)
-                               size = fsize;
-
+               unsafe void CreatePosix (long offset, long size, MemoryMappedFileAccess access)
+               {
                        int offset_diff;
 
-                       MemoryMappedFile.MapPosix (file, offset, size, access, out mmap_addr, out offset_diff);
+                       MemoryMappedFile.MapPosix (file_handle, offset, size, access, out mmap_addr, out offset_diff);
 
                        handle = new SafeMemoryMappedViewHandle ((IntPtr)((long)mmap_addr + offset_diff), size);
                        Initialize (handle, 0, size, ToFileAccess (access));
@@ -95,7 +92,7 @@ namespace System.IO.MemoryMappedFiles
                public void Flush ()
                {
                        if (MonoUtil.IsUnix)
-                               MemoryMappedFile.FlushPosix (file);
+                               Syscall.fsync (file_handle);
                        else
                                throw new NotImplementedException ("Not implemented on Windows");
                }
index c3c434b7490b1132fa1d82e86064f1072890a58a..2bf2f8a0084fde6f1d5c9ff8daf2f7fad7b39d97 100644 (file)
 
 using System;
 using System.IO;
+using Mono.Unix.Native;
 
 namespace System.IO.MemoryMappedFiles
 {
        public sealed class MemoryMappedViewStream : UnmanagedMemoryStream {
-
                IntPtr mmap_addr;
                ulong mmap_size;
                object monitor;
-
-               internal MemoryMappedViewStream (FileStream file, long offset, long size, MemoryMappedFileAccess access) {
+               int fd;
+               
+               internal MemoryMappedViewStream (int fd, long offset, long size, MemoryMappedFileAccess access) {
+                       this.fd = fd;
                        monitor = new Object ();
                        if (MonoUtil.IsUnix)
-                               CreateStreamPosix (file, offset, size, access);
+                               CreateStreamPosix (fd, offset, size, access);
                        else
                                throw new NotImplementedException ("Not implemented on windows.");
                }
 
-               unsafe void CreateStreamPosix (FileStream file, long offset, long size, MemoryMappedFileAccess access) {
-                       long fsize = file.Length;
-
-                       if (size == 0 || size > fsize)
-                               size = fsize;
-
+               unsafe void CreateStreamPosix (int fd, long offset, long size, MemoryMappedFileAccess access)
+               {
                        int offset_diff;
                        mmap_size = (ulong) size;
-                       MemoryMappedFile.MapPosix (file, offset, size, access, out mmap_addr, out offset_diff);
+                       MemoryMappedFile.MapPosix (fd, offset, size, access, out mmap_addr, out offset_diff);
                        
                        FileAccess faccess;
 
@@ -86,6 +84,13 @@ namespace System.IO.MemoryMappedFiles
                        }
                }
 
+               public override void Flush ()
+               {
+                       if (MonoUtil.IsUnix)
+                               Syscall.fsync (fd);
+                       else
+                               throw new NotImplementedException ("Not implemented on Windows");
+               }
        }
 }