quarantine.c revision 234370
1#include "jemalloc/internal/jemalloc_internal.h"
2
3/******************************************************************************/
4/* Data. */
5
6typedef struct quarantine_s quarantine_t;
7
8struct quarantine_s {
9	size_t	curbytes;
10	size_t	curobjs;
11	size_t	first;
12#define	LG_MAXOBJS_INIT 10
13	size_t	lg_maxobjs;
14	void	*objs[1]; /* Dynamically sized ring buffer. */
15};
16
17static void	quarantine_cleanup(void *arg);
18
19malloc_tsd_data(static, quarantine, quarantine_t *, NULL)
20malloc_tsd_funcs(JEMALLOC_INLINE, quarantine, quarantine_t *, NULL,
21    quarantine_cleanup)
22
23/******************************************************************************/
24/* Function prototypes for non-inline static functions. */
25
26static quarantine_t	*quarantine_init(size_t lg_maxobjs);
27static quarantine_t	*quarantine_grow(quarantine_t *quarantine);
28static void	quarantine_drain(quarantine_t *quarantine, size_t upper_bound);
29
30/******************************************************************************/
31
32static quarantine_t *
33quarantine_init(size_t lg_maxobjs)
34{
35	quarantine_t *quarantine;
36
37	quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) +
38	    ((ZU(1) << lg_maxobjs) * sizeof(void *)));
39	if (quarantine == NULL)
40		return (NULL);
41	quarantine->curbytes = 0;
42	quarantine->curobjs = 0;
43	quarantine->first = 0;
44	quarantine->lg_maxobjs = lg_maxobjs;
45
46	quarantine_tsd_set(&quarantine);
47
48	return (quarantine);
49}
50
51static quarantine_t *
52quarantine_grow(quarantine_t *quarantine)
53{
54	quarantine_t *ret;
55
56	ret = quarantine_init(quarantine->lg_maxobjs + 1);
57	if (ret == NULL)
58		return (quarantine);
59
60	ret->curbytes = quarantine->curbytes;
61	if (quarantine->first + quarantine->curobjs < (ZU(1) <<
62	    quarantine->lg_maxobjs)) {
63		/* objs ring buffer data are contiguous. */
64		memcpy(ret->objs, &quarantine->objs[quarantine->first],
65		    quarantine->curobjs * sizeof(void *));
66		ret->curobjs = quarantine->curobjs;
67	} else {
68		/* objs ring buffer data wrap around. */
69		size_t ncopy = (ZU(1) << quarantine->lg_maxobjs) -
70		    quarantine->first;
71		memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy *
72		    sizeof(void *));
73		ret->curobjs = ncopy;
74		if (quarantine->curobjs != 0) {
75			memcpy(&ret->objs[ret->curobjs], quarantine->objs,
76			    quarantine->curobjs - ncopy);
77		}
78	}
79
80	return (ret);
81}
82
83static void
84quarantine_drain(quarantine_t *quarantine, size_t upper_bound)
85{
86
87	while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) {
88		void *ptr = quarantine->objs[quarantine->first];
89		size_t usize = isalloc(ptr, config_prof);
90		idalloc(ptr);
91		quarantine->curbytes -= usize;
92		quarantine->curobjs--;
93		quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
94		    quarantine->lg_maxobjs) - 1);
95	}
96}
97
98void
99quarantine(void *ptr)
100{
101	quarantine_t *quarantine;
102	size_t usize = isalloc(ptr, config_prof);
103
104	assert(config_fill);
105	assert(opt_quarantine);
106
107	quarantine = *quarantine_tsd_get();
108	if (quarantine == NULL && (quarantine =
109	    quarantine_init(LG_MAXOBJS_INIT)) == NULL) {
110		idalloc(ptr);
111		return;
112	}
113	/*
114	 * Drain one or more objects if the quarantine size limit would be
115	 * exceeded by appending ptr.
116	 */
117	if (quarantine->curbytes + usize > opt_quarantine) {
118		size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine
119		    - usize : 0;
120		quarantine_drain(quarantine, upper_bound);
121	}
122	/* Grow the quarantine ring buffer if it's full. */
123	if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs))
124		quarantine = quarantine_grow(quarantine);
125	/* quarantine_grow() must free a slot if it fails to grow. */
126	assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs));
127	/* Append ptr if its size doesn't exceed the quarantine size. */
128	if (quarantine->curbytes + usize <= opt_quarantine) {
129		size_t offset = (quarantine->first + quarantine->curobjs) &
130		    ((ZU(1) << quarantine->lg_maxobjs) - 1);
131		quarantine->objs[offset] = ptr;
132		quarantine->curbytes += usize;
133		quarantine->curobjs++;
134		if (opt_junk)
135			memset(ptr, 0x5a, usize);
136	} else {
137		assert(quarantine->curbytes == 0);
138		idalloc(ptr);
139	}
140}
141
142static void
143quarantine_cleanup(void *arg)
144{
145	quarantine_t *quarantine = *(quarantine_t **)arg;
146
147	if (quarantine != NULL) {
148		quarantine_drain(quarantine, 0);
149		idalloc(quarantine);
150	}
151}
152
153bool
154quarantine_boot(void)
155{
156
157	assert(config_fill);
158
159	if (quarantine_tsd_boot())
160		return (true);
161
162	return (false);
163}
164