private static unsafe SafeMemoryMappedFileHandle CreateCore( FileStream fileStream, string mapName, HandleInheritability inheritability, MemoryMappedFileAccess access, MemoryMappedFileOptions options, long capacity) { if (mapName != null) { // Named maps are not supported in our Unix implementation. We could support named maps on Linux using // shared memory segments (shmget/shmat/shmdt/shmctl/etc.), but that doesn't work on OSX by default due // to very low default limits on OSX for the size of such objects; it also doesn't support behaviors // like copy-on-write or the ability to control handle inheritability, and reliably cleaning them up // relies on some non-conforming behaviors around shared memory IDs remaining valid even after they've // been marked for deletion (IPC_RMID). We could also support named maps using the current implementation // by not unlinking after creating the backing store, but then the backing stores would remain around // and accessible even after process exit, with no good way to appropriately clean them up. // (File-backed maps may still be used for cross-process communication.) throw CreateNamedMapsNotSupportedException(); } bool ownsFileStream = false; if (fileStream != null) { // This map is backed by a file. Make sure the file's size is increased to be // at least as big as the requested capacity of the map. if (fileStream.Length < capacity) { fileStream.SetLength(capacity); } } else { // This map is backed by memory-only. With files, multiple views over the same map // will end up being able to share data through the same file-based backing store; // for anonymous maps, we need a similar backing store, or else multiple views would logically // each be their own map and wouldn't share any data. To achieve this, we create a backing object // (either memory or on disk, depending on the system) and use its file descriptor as the file handle. // However, we only do this when the permission is more than read-only. We can't change the size // of an object that has read-only permissions, but we also don't need to worry about sharing // views over a read-only, anonymous, memory-backed map, because the data will never change, so all views // will always see zero and can't change that. In that case, we just use the built-in anonymous support of // the map by leaving fileStream as null. Interop.libc.MemoryMappedProtections protections = MemoryMappedView.GetProtections(access, forVerification: false); if ((protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0 && capacity > 0) { ownsFileStream = true; fileStream = CreateSharedBackingObject(protections, capacity); } } return(new SafeMemoryMappedFileHandle(fileStream, ownsFileStream, inheritability, access, options, capacity)); }
private static unsafe SafeMemoryMappedFileHandle CreateCore( FileStream fileStream, string mapName, HandleInheritability inheritability, MemoryMappedFileAccess access, MemoryMappedFileOptions options, long capacity) { if (mapName != null) { // TODO: We currently do not support named maps. We could possibly support // named maps in the future by using shm_open / shm_unlink, as we do for // giving internal names to anonymous maps. Issues to work through will include // dealing with permissions, passing information from the creator of the // map to another opener of it, etc. throw CreateNamedMapsNotSupportedException(); } SafeFileHandle fileHandle = null; if (fileStream != null) { // This map is backed by a file. Make sure the file's size is increased to be // at least as big as the requested capacity of the map. fileHandle = fileStream.SafeFileHandle; if (fileStream.Length < capacity) { fileStream.SetLength(capacity); } } else { // This map is backed by memory-only. With files, multiple views over the same map // will end up being able to share data through the same file-based backing store; // for anonymous maps, we need a similar backing store, or else multiple views would logically // each be their own map and wouldn't share any data. To achieve this, we create a POSIX shared // memory object and use its file descriptor as the file handle. However, we only do this when the // permission is more than read-only. We can't ftruncate to increase the size of a shared memory // object that has read-only permissions, but we also don't need to worry about sharing // views over a read-only, anonymous, memory-backed map, because the data will never change, so all views // will always see zero and can't change that. In that case, we just use the built-in anonymous support of // the map by leaving fileHandle as null. Interop.libc.MemoryMappedProtections protections = MemoryMappedView.GetProtections(access, forVerification: false); if ((protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0 && capacity > 0) { mapName = "/AnonCoreFxMemMap_" + Guid.NewGuid().ToString("N"); // unique name must start with "/" and be < NAME_MAX length fileHandle = CreateNewSharedMemoryObject(mapName, protections, capacity); } } return(new SafeMemoryMappedFileHandle(mapName, fileHandle, inheritability, access, options, capacity)); }