blob: c5fa566bcf6e7e73331410b99f7ae312b19ce35e [file] [log] [blame]
Jason Evansbbe29d32013-01-30 15:03:11 -08001#define JEMALLOC_QUARANTINE_C_
Jason Evans122449b2012-04-06 00:35:09 -07002#include "jemalloc/internal/jemalloc_internal.h"
3
Jason Evans577dd842012-04-23 21:14:26 -07004/*
Jason Evanse12eaf92014-12-08 14:40:14 -08005 * Quarantine pointers close to NULL are used to encode state information that
Jason Evans577dd842012-04-23 21:14:26 -07006 * is used for cleaning up during thread shutdown.
7 */
8#define QUARANTINE_STATE_REINCARNATED ((quarantine_t *)(uintptr_t)1)
9#define QUARANTINE_STATE_PURGATORY ((quarantine_t *)(uintptr_t)2)
10#define QUARANTINE_STATE_MAX QUARANTINE_STATE_PURGATORY
11
Jason Evans122449b2012-04-06 00:35:09 -070012/******************************************************************************/
Jason Evans122449b2012-04-06 00:35:09 -070013/* Function prototypes for non-inline static functions. */
14
Jason Evans5460aa62014-09-22 21:09:23 -070015static quarantine_t *quarantine_grow(tsd_t *tsd, quarantine_t *quarantine);
16static void quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine);
17static void quarantine_drain(tsd_t *tsd, quarantine_t *quarantine,
18 size_t upper_bound);
Jason Evans122449b2012-04-06 00:35:09 -070019
20/******************************************************************************/
21
Jason Evans9cf2be02014-11-07 14:50:38 -080022static quarantine_t *
Jason Evans5460aa62014-09-22 21:09:23 -070023quarantine_init(tsd_t *tsd, size_t lg_maxobjs)
Jason Evans122449b2012-04-06 00:35:09 -070024{
25 quarantine_t *quarantine;
26
Jason Evansc002a5c2014-11-04 18:03:11 -080027 assert(tsd_nominal(tsd));
28
Jason Evans5460aa62014-09-22 21:09:23 -070029 quarantine = (quarantine_t *)imalloc(tsd, offsetof(quarantine_t, objs) +
Jason Evans9cd351d2012-04-23 21:43:18 -070030 ((ZU(1) << lg_maxobjs) * sizeof(quarantine_obj_t)));
Jason Evans122449b2012-04-06 00:35:09 -070031 if (quarantine == NULL)
32 return (NULL);
33 quarantine->curbytes = 0;
34 quarantine->curobjs = 0;
35 quarantine->first = 0;
36 quarantine->lg_maxobjs = lg_maxobjs;
37
Jason Evans122449b2012-04-06 00:35:09 -070038 return (quarantine);
39}
40
Jason Evansc002a5c2014-11-04 18:03:11 -080041void
42quarantine_alloc_hook_work(tsd_t *tsd)
43{
44 quarantine_t *quarantine;
45
46 if (!tsd_nominal(tsd))
47 return;
48
49 quarantine = quarantine_init(tsd, LG_MAXOBJS_INIT);
50 /*
51 * Check again whether quarantine has been initialized, because
Jason Evanse12eaf92014-12-08 14:40:14 -080052 * quarantine_init() may have triggered recursive initialization.
Jason Evansc002a5c2014-11-04 18:03:11 -080053 */
54 if (tsd_quarantine_get(tsd) == NULL)
55 tsd_quarantine_set(tsd, quarantine);
56 else
57 idalloc(tsd, quarantine);
58}
59
Jason Evans122449b2012-04-06 00:35:09 -070060static quarantine_t *
Jason Evans5460aa62014-09-22 21:09:23 -070061quarantine_grow(tsd_t *tsd, quarantine_t *quarantine)
Jason Evans122449b2012-04-06 00:35:09 -070062{
63 quarantine_t *ret;
64
Jason Evans5460aa62014-09-22 21:09:23 -070065 ret = quarantine_init(tsd, quarantine->lg_maxobjs + 1);
Jason Evansd0e942e2013-01-31 14:42:41 -080066 if (ret == NULL) {
Jason Evans5460aa62014-09-22 21:09:23 -070067 quarantine_drain_one(tsd, quarantine);
Jason Evans122449b2012-04-06 00:35:09 -070068 return (quarantine);
Jason Evansd0e942e2013-01-31 14:42:41 -080069 }
Jason Evans122449b2012-04-06 00:35:09 -070070
71 ret->curbytes = quarantine->curbytes;
Jason Evans7e060392012-04-23 22:07:30 -070072 ret->curobjs = quarantine->curobjs;
73 if (quarantine->first + quarantine->curobjs <= (ZU(1) <<
Jason Evans122449b2012-04-06 00:35:09 -070074 quarantine->lg_maxobjs)) {
75 /* objs ring buffer data are contiguous. */
76 memcpy(ret->objs, &quarantine->objs[quarantine->first],
Jason Evans9cd351d2012-04-23 21:43:18 -070077 quarantine->curobjs * sizeof(quarantine_obj_t));
Jason Evans122449b2012-04-06 00:35:09 -070078 } else {
79 /* objs ring buffer data wrap around. */
Jason Evans7e060392012-04-23 22:07:30 -070080 size_t ncopy_a = (ZU(1) << quarantine->lg_maxobjs) -
Jason Evans122449b2012-04-06 00:35:09 -070081 quarantine->first;
Jason Evans7e060392012-04-23 22:07:30 -070082 size_t ncopy_b = quarantine->curobjs - ncopy_a;
83
84 memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy_a
85 * sizeof(quarantine_obj_t));
86 memcpy(&ret->objs[ncopy_a], quarantine->objs, ncopy_b *
Jason Evans9cd351d2012-04-23 21:43:18 -070087 sizeof(quarantine_obj_t));
Jason Evans122449b2012-04-06 00:35:09 -070088 }
Jason Evans5460aa62014-09-22 21:09:23 -070089 idalloc(tsd, quarantine);
Jason Evans122449b2012-04-06 00:35:09 -070090
Jason Evansc002a5c2014-11-04 18:03:11 -080091 tsd_quarantine_set(tsd, ret);
Jason Evans122449b2012-04-06 00:35:09 -070092 return (ret);
93}
94
95static void
Jason Evans5460aa62014-09-22 21:09:23 -070096quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine)
Jason Evansd0e942e2013-01-31 14:42:41 -080097{
98 quarantine_obj_t *obj = &quarantine->objs[quarantine->first];
99 assert(obj->usize == isalloc(obj->ptr, config_prof));
Jason Evans5460aa62014-09-22 21:09:23 -0700100 idalloc(tsd, obj->ptr);
Jason Evansd0e942e2013-01-31 14:42:41 -0800101 quarantine->curbytes -= obj->usize;
102 quarantine->curobjs--;
103 quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
104 quarantine->lg_maxobjs) - 1);
105}
106
107static void
Jason Evans5460aa62014-09-22 21:09:23 -0700108quarantine_drain(tsd_t *tsd, quarantine_t *quarantine, size_t upper_bound)
Jason Evans122449b2012-04-06 00:35:09 -0700109{
110
Jason Evansd0e942e2013-01-31 14:42:41 -0800111 while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0)
Jason Evans5460aa62014-09-22 21:09:23 -0700112 quarantine_drain_one(tsd, quarantine);
Jason Evans122449b2012-04-06 00:35:09 -0700113}
114
115void
Jason Evans5460aa62014-09-22 21:09:23 -0700116quarantine(tsd_t *tsd, void *ptr)
Jason Evans122449b2012-04-06 00:35:09 -0700117{
118 quarantine_t *quarantine;
119 size_t usize = isalloc(ptr, config_prof);
120
Jason Evans78f73522012-04-18 13:38:40 -0700121 cassert(config_fill);
Jason Evans122449b2012-04-06 00:35:09 -0700122 assert(opt_quarantine);
123
Jason Evans5460aa62014-09-22 21:09:23 -0700124 if ((quarantine = tsd_quarantine_get(tsd)) == NULL) {
125 idalloc(tsd, ptr);
Jason Evansbbe29d32013-01-30 15:03:11 -0800126 return;
Jason Evans122449b2012-04-06 00:35:09 -0700127 }
128 /*
129 * Drain one or more objects if the quarantine size limit would be
130 * exceeded by appending ptr.
131 */
132 if (quarantine->curbytes + usize > opt_quarantine) {
133 size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine
134 - usize : 0;
Jason Evans5460aa62014-09-22 21:09:23 -0700135 quarantine_drain(tsd, quarantine, upper_bound);
Jason Evans122449b2012-04-06 00:35:09 -0700136 }
137 /* Grow the quarantine ring buffer if it's full. */
138 if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs))
Jason Evans5460aa62014-09-22 21:09:23 -0700139 quarantine = quarantine_grow(tsd, quarantine);
Jason Evans122449b2012-04-06 00:35:09 -0700140 /* quarantine_grow() must free a slot if it fails to grow. */
141 assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs));
142 /* Append ptr if its size doesn't exceed the quarantine size. */
143 if (quarantine->curbytes + usize <= opt_quarantine) {
144 size_t offset = (quarantine->first + quarantine->curobjs) &
145 ((ZU(1) << quarantine->lg_maxobjs) - 1);
Jason Evans9cd351d2012-04-23 21:43:18 -0700146 quarantine_obj_t *obj = &quarantine->objs[offset];
147 obj->ptr = ptr;
148 obj->usize = usize;
Jason Evans122449b2012-04-06 00:35:09 -0700149 quarantine->curbytes += usize;
150 quarantine->curobjs++;
Jason Evans9c640bf2014-09-11 16:20:44 -0700151 if (config_fill && unlikely(opt_junk)) {
Jason Evans0d6c5d82013-12-17 15:14:36 -0800152 /*
153 * Only do redzone validation if Valgrind isn't in
154 * operation.
155 */
Jason Evans9c640bf2014-09-11 16:20:44 -0700156 if ((!config_valgrind || likely(!in_valgrind))
Jason Evans0d6c5d82013-12-17 15:14:36 -0800157 && usize <= SMALL_MAXCLASS)
158 arena_quarantine_junk_small(ptr, usize);
159 else
160 memset(ptr, 0x5a, usize);
161 }
Jason Evans122449b2012-04-06 00:35:09 -0700162 } else {
163 assert(quarantine->curbytes == 0);
Jason Evans5460aa62014-09-22 21:09:23 -0700164 idalloc(tsd, ptr);
Jason Evans122449b2012-04-06 00:35:09 -0700165 }
166}
167
Jason Evansbbe29d32013-01-30 15:03:11 -0800168void
Jason Evans5460aa62014-09-22 21:09:23 -0700169quarantine_cleanup(tsd_t *tsd)
Jason Evans122449b2012-04-06 00:35:09 -0700170{
Jason Evans5460aa62014-09-22 21:09:23 -0700171 quarantine_t *quarantine;
Jason Evans122449b2012-04-06 00:35:09 -0700172
Jason Evans5460aa62014-09-22 21:09:23 -0700173 if (!config_fill)
174 return;
175
176 quarantine = tsd_quarantine_get(tsd);
177 if (quarantine != NULL) {
178 quarantine_drain(tsd, quarantine, 0);
179 idalloc(tsd, quarantine);
180 tsd_quarantine_set(tsd, NULL);
Jason Evans122449b2012-04-06 00:35:09 -0700181 }
182}