1 ///
2 module std.experimental.allocator.mmap_allocator;
3 
4 // MmapAllocator
5 /**
6 
7 Allocator (currently defined only for Posix and Windows) using
8 $(D $(LINK2 https://en.wikipedia.org/wiki/Mmap, mmap))
9 and $(D $(LUCKY munmap)) directly (or their Windows equivalents). There is no
10 additional structure: each call to $(D allocate(s)) issues a call to
11 $(D mmap(null, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)),
12 and each call to $(D deallocate(b)) issues $(D munmap(b.ptr, b.length)).
13 So $(D MmapAllocator) is usually intended for allocating large chunks to be
14 managed by fine-granular allocators.
15 
16 */
17 struct MmapAllocator
18 {
19     /// The one shared instance.
20     static shared MmapAllocator instance;
21 
22     /**
23     Alignment is page-size and hardcoded to 4096 (even though on certain systems
24     it could be larger).
25     */
26     enum size_t alignment = 4096;
27 
versionMmapAllocator28     version (Posix)
29     {
30         /// Allocator API.
31         void[] allocate(size_t bytes) shared
32         {
33             import core.sys.posix.sys.mman : mmap, MAP_ANON, PROT_READ,
34                 PROT_WRITE, MAP_PRIVATE, MAP_FAILED;
35             if (!bytes) return null;
36             auto p = mmap(null, bytes, PROT_READ | PROT_WRITE,
37                 MAP_PRIVATE | MAP_ANON, -1, 0);
38             if (p is MAP_FAILED) return null;
39             return p[0 .. bytes];
40         }
41 
42         /// Ditto
43         bool deallocate(void[] b) shared
44         {
45             import core.sys.posix.sys.mman : munmap;
46             if (b.ptr) munmap(b.ptr, b.length) == 0 || assert(0);
47             return true;
48         }
49 
50         // Anonymous mmap might be zero-filled on all Posix systems but
51         // not all commit to this in the documentation.
52         version (linux)
53             // http://man7.org/linux/man-pages/man2/mmap.2.html
54             package alias allocateZeroed = allocate;
55         else version (NetBSD)
56             // http://netbsd.gw.com/cgi-bin/man-cgi?mmap+2+NetBSD-current
57             package alias allocateZeroed = allocate;
58         else version (Solaris)
59             // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html
60             package alias allocateZeroed = allocate;
61         else version (AIX)
62             // https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.basetrf1/mmap.htm
63             package alias allocateZeroed = allocate;
64     }
versionMmapAllocator65     else version (Windows)
66     {
67         import core.sys.windows.windows : VirtualAlloc, VirtualFree, MEM_COMMIT,
68             PAGE_READWRITE, MEM_RELEASE;
69 
70         /// Allocator API.
71         void[] allocate(size_t bytes) shared
72         {
73             if (!bytes) return null;
74             auto p = VirtualAlloc(null, bytes, MEM_COMMIT, PAGE_READWRITE);
75             if (p == null)
76                 return null;
77             return p[0 .. bytes];
78         }
79 
80         /// Ditto
81         bool deallocate(void[] b) shared
82         {
83             return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0;
84         }
85 
86         package alias allocateZeroed = allocate;
87     }
88 }
89 
90 @system unittest
91 {
92     alias alloc = MmapAllocator.instance;
93     auto p = alloc.allocate(100);
94     assert(p.length == 100);
95     alloc.deallocate(p);
96 }
97