]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/jemalloc/src/chunk_dss.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / jemalloc / src / chunk_dss.c
1 #define JEMALLOC_CHUNK_DSS_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
3 /******************************************************************************/
4 /* Data. */
5
6 const char      *dss_prec_names[] = {
7         "disabled",
8         "primary",
9         "secondary",
10         "N/A"
11 };
12
13 /* Current dss precedence default, used when creating new arenas. */
14 static dss_prec_t       dss_prec_default = DSS_PREC_DEFAULT;
15
16 /*
17  * Protects sbrk() calls.  This avoids malloc races among threads, though it
18  * does not protect against races with threads that call sbrk() directly.
19  */
20 static malloc_mutex_t   dss_mtx;
21
22 /* Base address of the DSS. */
23 static void             *dss_base;
24 /* Current end of the DSS, or ((void *)-1) if the DSS is exhausted. */
25 static void             *dss_prev;
26 /* Current upper limit on DSS addresses. */
27 static void             *dss_max;
28
29 /******************************************************************************/
30
31 #ifndef JEMALLOC_HAVE_SBRK
32 static void *
33 sbrk(intptr_t increment)
34 {
35
36         not_implemented();
37
38         return (NULL);
39 }
40 #endif
41
42 dss_prec_t
43 chunk_dss_prec_get(void)
44 {
45         dss_prec_t ret;
46
47         if (config_dss == false)
48                 return (dss_prec_disabled);
49         malloc_mutex_lock(&dss_mtx);
50         ret = dss_prec_default;
51         malloc_mutex_unlock(&dss_mtx);
52         return (ret);
53 }
54
55 bool
56 chunk_dss_prec_set(dss_prec_t dss_prec)
57 {
58
59         if (config_dss == false)
60                 return (true);
61         malloc_mutex_lock(&dss_mtx);
62         dss_prec_default = dss_prec;
63         malloc_mutex_unlock(&dss_mtx);
64         return (false);
65 }
66
67 void *
68 chunk_alloc_dss(size_t size, size_t alignment, bool *zero)
69 {
70         void *ret;
71
72         cassert(config_dss);
73         assert(size > 0 && (size & chunksize_mask) == 0);
74         assert(alignment > 0 && (alignment & chunksize_mask) == 0);
75
76         /*
77          * sbrk() uses a signed increment argument, so take care not to
78          * interpret a huge allocation request as a negative increment.
79          */
80         if ((intptr_t)size < 0)
81                 return (NULL);
82
83         malloc_mutex_lock(&dss_mtx);
84         if (dss_prev != (void *)-1) {
85                 size_t gap_size, cpad_size;
86                 void *cpad, *dss_next;
87                 intptr_t incr;
88
89                 /*
90                  * The loop is necessary to recover from races with other
91                  * threads that are using the DSS for something other than
92                  * malloc.
93                  */
94                 do {
95                         /* Get the current end of the DSS. */
96                         dss_max = sbrk(0);
97                         /*
98                          * Calculate how much padding is necessary to
99                          * chunk-align the end of the DSS.
100                          */
101                         gap_size = (chunksize - CHUNK_ADDR2OFFSET(dss_max)) &
102                             chunksize_mask;
103                         /*
104                          * Compute how much chunk-aligned pad space (if any) is
105                          * necessary to satisfy alignment.  This space can be
106                          * recycled for later use.
107                          */
108                         cpad = (void *)((uintptr_t)dss_max + gap_size);
109                         ret = (void *)ALIGNMENT_CEILING((uintptr_t)dss_max,
110                             alignment);
111                         cpad_size = (uintptr_t)ret - (uintptr_t)cpad;
112                         dss_next = (void *)((uintptr_t)ret + size);
113                         if ((uintptr_t)ret < (uintptr_t)dss_max ||
114                             (uintptr_t)dss_next < (uintptr_t)dss_max) {
115                                 /* Wrap-around. */
116                                 malloc_mutex_unlock(&dss_mtx);
117                                 return (NULL);
118                         }
119                         incr = gap_size + cpad_size + size;
120                         dss_prev = sbrk(incr);
121                         if (dss_prev == dss_max) {
122                                 /* Success. */
123                                 dss_max = dss_next;
124                                 malloc_mutex_unlock(&dss_mtx);
125                                 if (cpad_size != 0)
126                                         chunk_unmap(cpad, cpad_size);
127                                 if (*zero) {
128                                         VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
129                                         memset(ret, 0, size);
130                                 }
131                                 return (ret);
132                         }
133                 } while (dss_prev != (void *)-1);
134         }
135         malloc_mutex_unlock(&dss_mtx);
136
137         return (NULL);
138 }
139
140 bool
141 chunk_in_dss(void *chunk)
142 {
143         bool ret;
144
145         cassert(config_dss);
146
147         malloc_mutex_lock(&dss_mtx);
148         if ((uintptr_t)chunk >= (uintptr_t)dss_base
149             && (uintptr_t)chunk < (uintptr_t)dss_max)
150                 ret = true;
151         else
152                 ret = false;
153         malloc_mutex_unlock(&dss_mtx);
154
155         return (ret);
156 }
157
158 bool
159 chunk_dss_boot(void)
160 {
161
162         cassert(config_dss);
163
164         if (malloc_mutex_init(&dss_mtx))
165                 return (true);
166         dss_base = sbrk(0);
167         dss_prev = dss_base;
168         dss_max = dss_base;
169
170         return (false);
171 }
172
173 void
174 chunk_dss_prefork(void)
175 {
176
177         if (config_dss)
178                 malloc_mutex_prefork(&dss_mtx);
179 }
180
181 void
182 chunk_dss_postfork_parent(void)
183 {
184
185         if (config_dss)
186                 malloc_mutex_postfork_parent(&dss_mtx);
187 }
188
189 void
190 chunk_dss_postfork_child(void)
191 {
192
193         if (config_dss)
194                 malloc_mutex_postfork_child(&dss_mtx);
195 }
196
197 /******************************************************************************/