summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorc-blake <c-blake@users.noreply.github.com>2018-12-14 05:44:11 -0500
committerAndreas Rumpf <rumpf_a@web.de>2018-12-14 11:44:11 +0100
commita54e3f46026e641ab8653d06c12eb04aa57d4274 (patch)
tree102d541e6f7632d7e6374e770ff1f91f90809016
parent3ba8f158fb59372b492b353d60abeae343fdeef5 (diff)
downloadNim-a54e3f46026e641ab8653d06c12eb04aa57d4274.tar.gz
Allow an escape hatch for platform specific flags/default override (#9968)
* Allow an escape hatch for platform specific flags (of which there are many,
for example MAP_POPULATE itself is a Linux-only thing, not other Unix).

Continue with same defaults as before in this commit, but that really
should be changed to *not* include MAP_POPULATE.  While pre-faulting
all the pages can be useful sometimes *if* you know you're going to
access all the data, it is highly unlikely to be what users expect the
default to be.  For some things all that up front work is 1000s of
times slower than being lazy/on-demand/only ever faulting parts of the
file.  Even the MAP_POPULATE fan who originally in 2014 committed to
this file defaulted it to off (but turned it always-on as a "temporary"
work around for some long since gone/mutated compiler issue).

Anyway, at least something like this `mapFlags` gives users the ability
to override the poor default choice or activate any other idiosyncratic
platform-specific features.

* Use simple, efficient default flags, but also accept whatever the open/mapMem
caller specifies.  Save flags in MemFile so they can be used in `resize`.

This field should not need exporting like the others -- callers can always
save whatever values they pass -- but we include a cautionary comment in
case anyone ever asks for a `*` there, as well as for documentation.

Also make documentation for ``mapFlags`` in open more likely to inspire care.
-rw-r--r--lib/pure/memfiles.nim26
1 files changed, 21 insertions, 5 deletions
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 810223d72..d1a006eee 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -42,9 +42,10 @@ type
       wasOpened*: bool     ## **Caution**: Windows specific public field.
     else:
       handle*: cint        ## **Caution**: Posix specific public field.
+      flags: cint          ## **Caution**: Platform specific private field.
 
 proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
-             mappedSize = -1, offset = 0): pointer =
+             mappedSize = -1, offset = 0, mapFlags = cint(-1)): pointer =
   ## returns a pointer to a mapped portion of MemFile `m`
   ##
   ## ``mappedSize`` of ``-1`` maps to the whole file, and
@@ -65,11 +66,17 @@ proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
       raiseOSError(osLastError())
   else:
     assert mappedSize > 0
+
+    m.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
+    #Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
+    if int(m.flags and MAP_PRIVATE) == 0:
+      m.flags = m.flags or MAP_SHARED
+
     result = mmap(
       nil,
       mappedSize,
       if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
-      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      m.flags,
       m.handle, offset)
     if result == cast[pointer](MAP_FAILED):
       raiseOSError(osLastError())
@@ -90,7 +97,7 @@ proc unmapMem*(f: var MemFile, p: pointer, size: int) =
 
 proc open*(filename: string, mode: FileMode = fmRead,
            mappedSize = -1, offset = 0, newFileSize = -1,
-           allowRemap = false): MemFile =
+           allowRemap = false, mapFlags = cint(-1)): MemFile =
   ## opens a memory mapped file. If this fails, ``OSError`` is raised.
   ##
   ## ``newFileSize`` can only be set if the file does not exist and is opened
@@ -105,6 +112,10 @@ proc open*(filename: string, mode: FileMode = fmRead,
   ## ``allowRemap`` only needs to be true if you want to call ``mapMem`` on
   ## the resulting MemFile; else file handles are not kept open.
   ##
+  ## ``mapFlags`` allows callers to override default choices for memory mapping
+  ## flags with a bitwise mask of a variety of likely platform-specific flags
+  ## which may be ignored or even cause `open` to fail if misspecified.
+  ##
   ## Example:
   ##
   ## .. code-block:: nim
@@ -245,11 +256,16 @@ proc open*(filename: string, mode: FileMode = fmRead,
       else:
         fail(osLastError(), "error getting file size")
 
+    result.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
+    #Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
+    if int(result.flags and MAP_PRIVATE) == 0:
+      result.flags = result.flags or MAP_SHARED
+
     result.mem = mmap(
       nil,
       result.size,
       if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
-      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      result.flags,
       result.handle,
       offset)
 
@@ -305,7 +321,7 @@ when defined(posix) or defined(nimdoc):
         if munmap(f.mem, f.size) != 0:
           raiseOSError(osLastError())
         let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE,
-                            MAP_SHARED or MAP_POPULATE, f.handle, 0)
+                           f.flags, f.handle, 0)
         if newAddr == cast[pointer](MAP_FAILED):
           raiseOSError(osLastError())
       f.mem = newAddr