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