1 /**
2 * ae.sys.datamm
3 *
4 * License:
5 * This Source Code Form is subject to the terms of
6 * the Mozilla Public License, v. 2.0. If a copy of
7 * the MPL was not distributed with this file, You
8 * can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * Authors:
11 * Vladimir Panteleev <ae@cy.md>
12 */
13
14 module ae.sys.datamm;
15
16 import core.stdc.errno;
17
18 import std.exception;
19 import std.mmfile;
20 import std.typecons;
21
22 debug(DATA_REFCOUNT) import std.stdio, core.stdc.stdio;
23
24 import ae.sys.data;
25
26 alias MmMode = MmFile.Mode; /// Convenience alias.
27
28 // ************************************************************************
29
30 /// `Memory` implementation encapsulating a memory-mapped file.
31 /// When the last reference is released, the file is unmapped.
32 class MappedMemory : Memory
33 {
34 typeof(scoped!MmFile(null)) mmFile; /// The `MmFile` object.
35 ubyte[] mappedData; /// View of the mapped file data.
36
37 this(string name, MmMode mode, size_t from, size_t to)
38 {
39 mmFile = retryInterrupted({
40 return scoped!MmFile(name, mode, 0, null);
41 });
42 mappedData = cast(ubyte[])(
43 (from || to)
44 ? mmFile.Scoped_payload[from..(to ? to : mmFile.length)]
45 : mmFile.Scoped_payload[]
46 );
47
48 debug(DATA_REFCOUNT) writefln("? -> %s [%s..%s]: Created MappedMemory", cast(void*)this, contents.ptr, contents.ptr + contents.length);
49 } ///
50
51 debug(DATA_REFCOUNT)
52 ~this() @nogc
53 {
54 printf("? -> %p: Deleted MappedMemory\n", cast(void*)this);
55 }
56
57 override @property inout(ubyte)[] contents() inout { return mappedData; } ///
58 override @property size_t size() const { return mappedData.length; } ///
59 override void setSize(size_t newSize) { assert(false, "Can't resize MappedMemory"); } ///
60 override @property size_t capacity() const { return mappedData.length; } ///
61 }
62
63 /// Returns a `Data` viewing a mapped file.
64 Data mapFile(string name, MmMode mode, size_t from = 0, size_t to = 0)
65 {
66 auto memory = unmanagedNew!MappedMemory(name, mode, from, to);
67 return Data(memory);
68 }
69
70 private T retryInterrupted(T)(scope T delegate() dg)
71 {
72 version (Posix)
73 {
74 while (true)
75 {
76 try
77 {
78 return dg();
79 }
80 catch (ErrnoException e)
81 {
82 if (e.errno == EINTR)
83 continue;
84 throw e;
85 }
86 }
87 }
88 else
89 return dg();
90 }