]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/jemalloc/src/pages.c
Merge from head
[FreeBSD/FreeBSD.git] / contrib / jemalloc / src / pages.c
1 #define JEMALLOC_PAGES_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
3
4 /******************************************************************************/
5
6 void *
7 pages_map(void *addr, size_t size)
8 {
9         void *ret;
10
11         assert(size != 0);
12
13 #ifdef _WIN32
14         /*
15          * If VirtualAlloc can't allocate at the given address when one is
16          * given, it fails and returns NULL.
17          */
18         ret = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE,
19             PAGE_READWRITE);
20 #else
21         /*
22          * We don't use MAP_FIXED here, because it can cause the *replacement*
23          * of existing mappings, and we only want to create new mappings.
24          */
25         ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
26             -1, 0);
27         assert(ret != NULL);
28
29         if (ret == MAP_FAILED)
30                 ret = NULL;
31         else if (addr != NULL && ret != addr) {
32                 /*
33                  * We succeeded in mapping memory, but not in the right place.
34                  */
35                 pages_unmap(ret, size);
36                 ret = NULL;
37         }
38 #endif
39         assert(ret == NULL || (addr == NULL && ret != addr)
40             || (addr != NULL && ret == addr));
41         return (ret);
42 }
43
44 void
45 pages_unmap(void *addr, size_t size)
46 {
47
48 #ifdef _WIN32
49         if (VirtualFree(addr, 0, MEM_RELEASE) == 0)
50 #else
51         if (munmap(addr, size) == -1)
52 #endif
53         {
54                 char buf[BUFERROR_BUF];
55
56                 buferror(get_errno(), buf, sizeof(buf));
57                 malloc_printf("<jemalloc>: Error in "
58 #ifdef _WIN32
59                               "VirtualFree"
60 #else
61                               "munmap"
62 #endif
63                               "(): %s\n", buf);
64                 if (opt_abort)
65                         abort();
66         }
67 }
68
69 void *
70 pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size)
71 {
72         void *ret = (void *)((uintptr_t)addr + leadsize);
73
74         assert(alloc_size >= leadsize + size);
75 #ifdef _WIN32
76         {
77                 void *new_addr;
78
79                 pages_unmap(addr, alloc_size);
80                 new_addr = pages_map(ret, size);
81                 if (new_addr == ret)
82                         return (ret);
83                 if (new_addr)
84                         pages_unmap(new_addr, size);
85                 return (NULL);
86         }
87 #else
88         {
89                 size_t trailsize = alloc_size - leadsize - size;
90
91                 if (leadsize != 0)
92                         pages_unmap(addr, leadsize);
93                 if (trailsize != 0)
94                         pages_unmap((void *)((uintptr_t)ret + size), trailsize);
95                 return (ret);
96         }
97 #endif
98 }
99
100 static bool
101 pages_commit_impl(void *addr, size_t size, bool commit)
102 {
103
104 #ifndef _WIN32
105         /*
106          * The following decommit/commit implementation is functional, but
107          * always disabled because it doesn't add value beyong improved
108          * debugging (at the cost of extra system calls) on systems that
109          * overcommit.
110          */
111         if (false) {
112                 int prot = commit ? (PROT_READ | PROT_WRITE) : PROT_NONE;
113                 void *result = mmap(addr, size, prot, MAP_PRIVATE | MAP_ANON |
114                     MAP_FIXED, -1, 0);
115                 if (result == MAP_FAILED)
116                         return (true);
117                 if (result != addr) {
118                         /*
119                          * We succeeded in mapping memory, but not in the right
120                          * place.
121                          */
122                         pages_unmap(result, size);
123                         return (true);
124                 }
125                 return (false);
126         }
127 #endif
128         return (true);
129 }
130
131 bool
132 pages_commit(void *addr, size_t size)
133 {
134
135         return (pages_commit_impl(addr, size, true));
136 }
137
138 bool
139 pages_decommit(void *addr, size_t size)
140 {
141
142         return (pages_commit_impl(addr, size, false));
143 }
144
145 bool
146 pages_purge(void *addr, size_t size)
147 {
148         bool unzeroed;
149
150 #ifdef _WIN32
151         VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
152         unzeroed = true;
153 #elif defined(JEMALLOC_HAVE_MADVISE)
154 #  ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
155 #    define JEMALLOC_MADV_PURGE MADV_DONTNEED
156 #    define JEMALLOC_MADV_ZEROS true
157 #  elif defined(JEMALLOC_PURGE_MADVISE_FREE)
158 #    define JEMALLOC_MADV_PURGE MADV_FREE
159 #    define JEMALLOC_MADV_ZEROS false
160 #  else
161 #    error "No madvise(2) flag defined for purging unused dirty pages."
162 #  endif
163         int err = madvise(addr, size, JEMALLOC_MADV_PURGE);
164         unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
165 #  undef JEMALLOC_MADV_PURGE
166 #  undef JEMALLOC_MADV_ZEROS
167 #else
168         /* Last resort no-op. */
169         unzeroed = true;
170 #endif
171         return (unzeroed);
172 }
173