diff options
author | c-blake <c-blake@users.noreply.github.com> | 2018-12-14 05:44:11 -0500 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-12-14 11:44:11 +0100 |
commit | a54e3f46026e641ab8653d06c12eb04aa57d4274 (patch) | |
tree | 102d541e6f7632d7e6374e770ff1f91f90809016 | |
parent | 3ba8f158fb59372b492b353d60abeae343fdeef5 (diff) | |
download | Nim-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.nim | 26 |
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 |