2013-01-31 07:03:11 +08:00
|
|
|
#define JEMALLOC_QUARANTINE_C_
|
2012-04-06 15:35:09 +08:00
|
|
|
#include "jemalloc/internal/jemalloc_internal.h"
|
|
|
|
|
2012-04-24 12:14:26 +08:00
|
|
|
/*
|
2014-12-09 06:40:14 +08:00
|
|
|
* Quarantine pointers close to NULL are used to encode state information that
|
2012-04-24 12:14:26 +08:00
|
|
|
* is used for cleaning up during thread shutdown.
|
|
|
|
*/
|
|
|
|
#define QUARANTINE_STATE_REINCARNATED ((quarantine_t *)(uintptr_t)1)
|
|
|
|
#define QUARANTINE_STATE_PURGATORY ((quarantine_t *)(uintptr_t)2)
|
|
|
|
#define QUARANTINE_STATE_MAX QUARANTINE_STATE_PURGATORY
|
|
|
|
|
2012-04-06 15:35:09 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
/* Function prototypes for non-inline static functions. */
|
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
static quarantine_t *quarantine_grow(tsd_t *tsd, quarantine_t *quarantine);
|
|
|
|
static void quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine);
|
|
|
|
static void quarantine_drain(tsd_t *tsd, quarantine_t *quarantine,
|
|
|
|
size_t upper_bound);
|
2012-04-06 15:35:09 +08:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-08 06:50:38 +08:00
|
|
|
static quarantine_t *
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_init(tsd_t *tsd, size_t lg_maxobjs)
|
2012-04-06 15:35:09 +08:00
|
|
|
{
|
|
|
|
quarantine_t *quarantine;
|
|
|
|
|
2014-11-05 10:03:11 +08:00
|
|
|
assert(tsd_nominal(tsd));
|
|
|
|
|
2014-11-28 03:22:36 +08:00
|
|
|
quarantine = (quarantine_t *)iallocztm(tsd, offsetof(quarantine_t, objs)
|
|
|
|
+ ((ZU(1) << lg_maxobjs) * sizeof(quarantine_obj_t)), false, true,
|
|
|
|
true, NULL);
|
2012-04-06 15:35:09 +08:00
|
|
|
if (quarantine == NULL)
|
|
|
|
return (NULL);
|
|
|
|
quarantine->curbytes = 0;
|
|
|
|
quarantine->curobjs = 0;
|
|
|
|
quarantine->first = 0;
|
|
|
|
quarantine->lg_maxobjs = lg_maxobjs;
|
|
|
|
|
|
|
|
return (quarantine);
|
|
|
|
}
|
|
|
|
|
2014-11-05 10:03:11 +08:00
|
|
|
void
|
|
|
|
quarantine_alloc_hook_work(tsd_t *tsd)
|
|
|
|
{
|
|
|
|
quarantine_t *quarantine;
|
|
|
|
|
|
|
|
if (!tsd_nominal(tsd))
|
|
|
|
return;
|
|
|
|
|
|
|
|
quarantine = quarantine_init(tsd, LG_MAXOBJS_INIT);
|
|
|
|
/*
|
|
|
|
* Check again whether quarantine has been initialized, because
|
2014-12-09 06:40:14 +08:00
|
|
|
* quarantine_init() may have triggered recursive initialization.
|
2014-11-05 10:03:11 +08:00
|
|
|
*/
|
|
|
|
if (tsd_quarantine_get(tsd) == NULL)
|
|
|
|
tsd_quarantine_set(tsd, quarantine);
|
|
|
|
else
|
2014-11-28 03:22:36 +08:00
|
|
|
idalloctm(tsd, quarantine, true, true);
|
2014-11-05 10:03:11 +08:00
|
|
|
}
|
|
|
|
|
2012-04-06 15:35:09 +08:00
|
|
|
static quarantine_t *
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_grow(tsd_t *tsd, quarantine_t *quarantine)
|
2012-04-06 15:35:09 +08:00
|
|
|
{
|
|
|
|
quarantine_t *ret;
|
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
ret = quarantine_init(tsd, quarantine->lg_maxobjs + 1);
|
2013-02-01 06:42:41 +08:00
|
|
|
if (ret == NULL) {
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_drain_one(tsd, quarantine);
|
2012-04-06 15:35:09 +08:00
|
|
|
return (quarantine);
|
2013-02-01 06:42:41 +08:00
|
|
|
}
|
2012-04-06 15:35:09 +08:00
|
|
|
|
|
|
|
ret->curbytes = quarantine->curbytes;
|
2012-04-24 13:07:30 +08:00
|
|
|
ret->curobjs = quarantine->curobjs;
|
|
|
|
if (quarantine->first + quarantine->curobjs <= (ZU(1) <<
|
2012-04-06 15:35:09 +08:00
|
|
|
quarantine->lg_maxobjs)) {
|
|
|
|
/* objs ring buffer data are contiguous. */
|
|
|
|
memcpy(ret->objs, &quarantine->objs[quarantine->first],
|
2012-04-24 12:43:18 +08:00
|
|
|
quarantine->curobjs * sizeof(quarantine_obj_t));
|
2012-04-06 15:35:09 +08:00
|
|
|
} else {
|
|
|
|
/* objs ring buffer data wrap around. */
|
2012-04-24 13:07:30 +08:00
|
|
|
size_t ncopy_a = (ZU(1) << quarantine->lg_maxobjs) -
|
2012-04-06 15:35:09 +08:00
|
|
|
quarantine->first;
|
2012-04-24 13:07:30 +08:00
|
|
|
size_t ncopy_b = quarantine->curobjs - ncopy_a;
|
|
|
|
|
|
|
|
memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy_a
|
|
|
|
* sizeof(quarantine_obj_t));
|
|
|
|
memcpy(&ret->objs[ncopy_a], quarantine->objs, ncopy_b *
|
2012-04-24 12:43:18 +08:00
|
|
|
sizeof(quarantine_obj_t));
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|
2014-11-28 03:22:36 +08:00
|
|
|
idalloctm(tsd, quarantine, true, true);
|
2012-04-06 15:35:09 +08:00
|
|
|
|
2014-11-05 10:03:11 +08:00
|
|
|
tsd_quarantine_set(tsd, ret);
|
2012-04-06 15:35:09 +08:00
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2013-02-01 06:42:41 +08:00
|
|
|
static void
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine)
|
2013-02-01 06:42:41 +08:00
|
|
|
{
|
|
|
|
quarantine_obj_t *obj = &quarantine->objs[quarantine->first];
|
|
|
|
assert(obj->usize == isalloc(obj->ptr, config_prof));
|
2014-09-23 12:09:23 +08:00
|
|
|
idalloc(tsd, obj->ptr);
|
2013-02-01 06:42:41 +08:00
|
|
|
quarantine->curbytes -= obj->usize;
|
|
|
|
quarantine->curobjs--;
|
|
|
|
quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
|
|
|
|
quarantine->lg_maxobjs) - 1);
|
|
|
|
}
|
|
|
|
|
2012-04-06 15:35:09 +08:00
|
|
|
static void
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_drain(tsd_t *tsd, quarantine_t *quarantine, size_t upper_bound)
|
2012-04-06 15:35:09 +08:00
|
|
|
{
|
|
|
|
|
2013-02-01 06:42:41 +08:00
|
|
|
while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0)
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_drain_one(tsd, quarantine);
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine(tsd_t *tsd, void *ptr)
|
2012-04-06 15:35:09 +08:00
|
|
|
{
|
|
|
|
quarantine_t *quarantine;
|
|
|
|
size_t usize = isalloc(ptr, config_prof);
|
|
|
|
|
2012-04-19 04:38:40 +08:00
|
|
|
cassert(config_fill);
|
2012-04-06 15:35:09 +08:00
|
|
|
assert(opt_quarantine);
|
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
if ((quarantine = tsd_quarantine_get(tsd)) == NULL) {
|
|
|
|
idalloc(tsd, ptr);
|
2013-01-31 07:03:11 +08:00
|
|
|
return;
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Drain one or more objects if the quarantine size limit would be
|
|
|
|
* exceeded by appending ptr.
|
|
|
|
*/
|
|
|
|
if (quarantine->curbytes + usize > opt_quarantine) {
|
|
|
|
size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine
|
|
|
|
- usize : 0;
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_drain(tsd, quarantine, upper_bound);
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|
|
|
|
/* Grow the quarantine ring buffer if it's full. */
|
|
|
|
if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs))
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine = quarantine_grow(tsd, quarantine);
|
2012-04-06 15:35:09 +08:00
|
|
|
/* quarantine_grow() must free a slot if it fails to grow. */
|
|
|
|
assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs));
|
|
|
|
/* Append ptr if its size doesn't exceed the quarantine size. */
|
|
|
|
if (quarantine->curbytes + usize <= opt_quarantine) {
|
|
|
|
size_t offset = (quarantine->first + quarantine->curobjs) &
|
|
|
|
((ZU(1) << quarantine->lg_maxobjs) - 1);
|
2012-04-24 12:43:18 +08:00
|
|
|
quarantine_obj_t *obj = &quarantine->objs[offset];
|
|
|
|
obj->ptr = ptr;
|
|
|
|
obj->usize = usize;
|
2012-04-06 15:35:09 +08:00
|
|
|
quarantine->curbytes += usize;
|
|
|
|
quarantine->curobjs++;
|
2014-12-09 05:12:41 +08:00
|
|
|
if (config_fill && unlikely(opt_junk_free)) {
|
2013-12-18 07:14:36 +08:00
|
|
|
/*
|
|
|
|
* Only do redzone validation if Valgrind isn't in
|
|
|
|
* operation.
|
|
|
|
*/
|
2014-09-12 07:20:44 +08:00
|
|
|
if ((!config_valgrind || likely(!in_valgrind))
|
2013-12-18 07:14:36 +08:00
|
|
|
&& usize <= SMALL_MAXCLASS)
|
|
|
|
arena_quarantine_junk_small(ptr, usize);
|
|
|
|
else
|
|
|
|
memset(ptr, 0x5a, usize);
|
|
|
|
}
|
2012-04-06 15:35:09 +08:00
|
|
|
} else {
|
|
|
|
assert(quarantine->curbytes == 0);
|
2014-09-23 12:09:23 +08:00
|
|
|
idalloc(tsd, ptr);
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-31 07:03:11 +08:00
|
|
|
void
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_cleanup(tsd_t *tsd)
|
2012-04-06 15:35:09 +08:00
|
|
|
{
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine_t *quarantine;
|
2012-04-06 15:35:09 +08:00
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
if (!config_fill)
|
|
|
|
return;
|
2012-04-06 15:35:09 +08:00
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
quarantine = tsd_quarantine_get(tsd);
|
|
|
|
if (quarantine != NULL) {
|
|
|
|
quarantine_drain(tsd, quarantine, 0);
|
2014-11-28 03:22:36 +08:00
|
|
|
idalloctm(tsd, quarantine, true, true);
|
2014-09-23 12:09:23 +08:00
|
|
|
tsd_quarantine_set(tsd, NULL);
|
|
|
|
}
|
2012-04-06 15:35:09 +08:00
|
|
|
}
|