quarantine.c revision 234543
1234370Sjasone#include "jemalloc/internal/jemalloc_internal.h"
2234370Sjasone
3234370Sjasone/******************************************************************************/
4234370Sjasone/* Data. */
5234370Sjasone
6234370Sjasonetypedef struct quarantine_s quarantine_t;
7234370Sjasone
8234370Sjasonestruct quarantine_s {
9234370Sjasone	size_t	curbytes;
10234370Sjasone	size_t	curobjs;
11234370Sjasone	size_t	first;
12234370Sjasone#define	LG_MAXOBJS_INIT 10
13234370Sjasone	size_t	lg_maxobjs;
14234370Sjasone	void	*objs[1]; /* Dynamically sized ring buffer. */
15234370Sjasone};
16234370Sjasone
17234370Sjasonestatic void	quarantine_cleanup(void *arg);
18234370Sjasone
19234370Sjasonemalloc_tsd_data(static, quarantine, quarantine_t *, NULL)
20234370Sjasonemalloc_tsd_funcs(JEMALLOC_INLINE, quarantine, quarantine_t *, NULL,
21234370Sjasone    quarantine_cleanup)
22234370Sjasone
23234370Sjasone/******************************************************************************/
24234370Sjasone/* Function prototypes for non-inline static functions. */
25234370Sjasone
26234370Sjasonestatic quarantine_t	*quarantine_init(size_t lg_maxobjs);
27234370Sjasonestatic quarantine_t	*quarantine_grow(quarantine_t *quarantine);
28234370Sjasonestatic void	quarantine_drain(quarantine_t *quarantine, size_t upper_bound);
29234370Sjasone
30234370Sjasone/******************************************************************************/
31234370Sjasone
32234370Sjasonestatic quarantine_t *
33234370Sjasonequarantine_init(size_t lg_maxobjs)
34234370Sjasone{
35234370Sjasone	quarantine_t *quarantine;
36234370Sjasone
37234370Sjasone	quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) +
38234370Sjasone	    ((ZU(1) << lg_maxobjs) * sizeof(void *)));
39234370Sjasone	if (quarantine == NULL)
40234370Sjasone		return (NULL);
41234370Sjasone	quarantine->curbytes = 0;
42234370Sjasone	quarantine->curobjs = 0;
43234370Sjasone	quarantine->first = 0;
44234370Sjasone	quarantine->lg_maxobjs = lg_maxobjs;
45234370Sjasone
46234370Sjasone	quarantine_tsd_set(&quarantine);
47234370Sjasone
48234370Sjasone	return (quarantine);
49234370Sjasone}
50234370Sjasone
51234370Sjasonestatic quarantine_t *
52234370Sjasonequarantine_grow(quarantine_t *quarantine)
53234370Sjasone{
54234370Sjasone	quarantine_t *ret;
55234370Sjasone
56234370Sjasone	ret = quarantine_init(quarantine->lg_maxobjs + 1);
57234370Sjasone	if (ret == NULL)
58234370Sjasone		return (quarantine);
59234370Sjasone
60234370Sjasone	ret->curbytes = quarantine->curbytes;
61234370Sjasone	if (quarantine->first + quarantine->curobjs < (ZU(1) <<
62234370Sjasone	    quarantine->lg_maxobjs)) {
63234370Sjasone		/* objs ring buffer data are contiguous. */
64234370Sjasone		memcpy(ret->objs, &quarantine->objs[quarantine->first],
65234370Sjasone		    quarantine->curobjs * sizeof(void *));
66234370Sjasone		ret->curobjs = quarantine->curobjs;
67234370Sjasone	} else {
68234370Sjasone		/* objs ring buffer data wrap around. */
69234370Sjasone		size_t ncopy = (ZU(1) << quarantine->lg_maxobjs) -
70234370Sjasone		    quarantine->first;
71234370Sjasone		memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy *
72234370Sjasone		    sizeof(void *));
73234370Sjasone		ret->curobjs = ncopy;
74234370Sjasone		if (quarantine->curobjs != 0) {
75234370Sjasone			memcpy(&ret->objs[ret->curobjs], quarantine->objs,
76234370Sjasone			    quarantine->curobjs - ncopy);
77234370Sjasone		}
78234370Sjasone	}
79234370Sjasone
80234370Sjasone	return (ret);
81234370Sjasone}
82234370Sjasone
83234370Sjasonestatic void
84234370Sjasonequarantine_drain(quarantine_t *quarantine, size_t upper_bound)
85234370Sjasone{
86234370Sjasone
87234370Sjasone	while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) {
88234370Sjasone		void *ptr = quarantine->objs[quarantine->first];
89234370Sjasone		size_t usize = isalloc(ptr, config_prof);
90234370Sjasone		idalloc(ptr);
91234370Sjasone		quarantine->curbytes -= usize;
92234370Sjasone		quarantine->curobjs--;
93234370Sjasone		quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
94234370Sjasone		    quarantine->lg_maxobjs) - 1);
95234370Sjasone	}
96234370Sjasone}
97234370Sjasone
98234370Sjasonevoid
99234370Sjasonequarantine(void *ptr)
100234370Sjasone{
101234370Sjasone	quarantine_t *quarantine;
102234370Sjasone	size_t usize = isalloc(ptr, config_prof);
103234370Sjasone
104234543Sjasone	cassert(config_fill);
105234370Sjasone	assert(opt_quarantine);
106234370Sjasone
107234370Sjasone	quarantine = *quarantine_tsd_get();
108234370Sjasone	if (quarantine == NULL && (quarantine =
109234370Sjasone	    quarantine_init(LG_MAXOBJS_INIT)) == NULL) {
110234370Sjasone		idalloc(ptr);
111234370Sjasone		return;
112234370Sjasone	}
113234370Sjasone	/*
114234370Sjasone	 * Drain one or more objects if the quarantine size limit would be
115234370Sjasone	 * exceeded by appending ptr.
116234370Sjasone	 */
117234370Sjasone	if (quarantine->curbytes + usize > opt_quarantine) {
118234370Sjasone		size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine
119234370Sjasone		    - usize : 0;
120234370Sjasone		quarantine_drain(quarantine, upper_bound);
121234370Sjasone	}
122234370Sjasone	/* Grow the quarantine ring buffer if it's full. */
123234370Sjasone	if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs))
124234370Sjasone		quarantine = quarantine_grow(quarantine);
125234370Sjasone	/* quarantine_grow() must free a slot if it fails to grow. */
126234370Sjasone	assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs));
127234370Sjasone	/* Append ptr if its size doesn't exceed the quarantine size. */
128234370Sjasone	if (quarantine->curbytes + usize <= opt_quarantine) {
129234370Sjasone		size_t offset = (quarantine->first + quarantine->curobjs) &
130234370Sjasone		    ((ZU(1) << quarantine->lg_maxobjs) - 1);
131234370Sjasone		quarantine->objs[offset] = ptr;
132234370Sjasone		quarantine->curbytes += usize;
133234370Sjasone		quarantine->curobjs++;
134234370Sjasone		if (opt_junk)
135234370Sjasone			memset(ptr, 0x5a, usize);
136234370Sjasone	} else {
137234370Sjasone		assert(quarantine->curbytes == 0);
138234370Sjasone		idalloc(ptr);
139234370Sjasone	}
140234370Sjasone}
141234370Sjasone
142234370Sjasonestatic void
143234370Sjasonequarantine_cleanup(void *arg)
144234370Sjasone{
145234370Sjasone	quarantine_t *quarantine = *(quarantine_t **)arg;
146234370Sjasone
147234370Sjasone	if (quarantine != NULL) {
148234370Sjasone		quarantine_drain(quarantine, 0);
149234370Sjasone		idalloc(quarantine);
150234370Sjasone	}
151234370Sjasone}
152234370Sjasone
153234370Sjasonebool
154234370Sjasonequarantine_boot(void)
155234370Sjasone{
156234370Sjasone
157234543Sjasone	cassert(config_fill);
158234370Sjasone
159234370Sjasone	if (quarantine_tsd_boot())
160234370Sjasone		return (true);
161234370Sjasone
162234370Sjasone	return (false);
163234370Sjasone}
164