summaryrefslogtreecommitdiffstats
path: root/contrib/jemalloc/src/quarantine.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/jemalloc/src/quarantine.c')
-rw-r--r--contrib/jemalloc/src/quarantine.c101
1 files changed, 74 insertions, 27 deletions
diff --git a/contrib/jemalloc/src/quarantine.c b/contrib/jemalloc/src/quarantine.c
index 5fb6c39..9005ab3 100644
--- a/contrib/jemalloc/src/quarantine.c
+++ b/contrib/jemalloc/src/quarantine.c
@@ -1,17 +1,31 @@
#include "jemalloc/internal/jemalloc_internal.h"
+/*
+ * quarantine pointers close to NULL are used to encode state information that
+ * 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
+
/******************************************************************************/
/* Data. */
+typedef struct quarantine_obj_s quarantine_obj_t;
typedef struct quarantine_s quarantine_t;
+struct quarantine_obj_s {
+ void *ptr;
+ size_t usize;
+};
+
struct quarantine_s {
- size_t curbytes;
- size_t curobjs;
- size_t first;
+ size_t curbytes;
+ size_t curobjs;
+ size_t first;
#define LG_MAXOBJS_INIT 10
- size_t lg_maxobjs;
- void *objs[1]; /* Dynamically sized ring buffer. */
+ size_t lg_maxobjs;
+ quarantine_obj_t objs[1]; /* Dynamically sized ring buffer. */
};
static void quarantine_cleanup(void *arg);
@@ -35,7 +49,7 @@ quarantine_init(size_t lg_maxobjs)
quarantine_t *quarantine;
quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) +
- ((ZU(1) << lg_maxobjs) * sizeof(void *)));
+ ((ZU(1) << lg_maxobjs) * sizeof(quarantine_obj_t)));
if (quarantine == NULL)
return (NULL);
quarantine->curbytes = 0;
@@ -58,23 +72,22 @@ quarantine_grow(quarantine_t *quarantine)
return (quarantine);
ret->curbytes = quarantine->curbytes;
- if (quarantine->first + quarantine->curobjs < (ZU(1) <<
+ ret->curobjs = quarantine->curobjs;
+ if (quarantine->first + quarantine->curobjs <= (ZU(1) <<
quarantine->lg_maxobjs)) {
/* objs ring buffer data are contiguous. */
memcpy(ret->objs, &quarantine->objs[quarantine->first],
- quarantine->curobjs * sizeof(void *));
- ret->curobjs = quarantine->curobjs;
+ quarantine->curobjs * sizeof(quarantine_obj_t));
} else {
/* objs ring buffer data wrap around. */
- size_t ncopy = (ZU(1) << quarantine->lg_maxobjs) -
+ size_t ncopy_a = (ZU(1) << quarantine->lg_maxobjs) -
quarantine->first;
- memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy *
- sizeof(void *));
- ret->curobjs = ncopy;
- if (quarantine->curobjs != 0) {
- memcpy(&ret->objs[ret->curobjs], quarantine->objs,
- quarantine->curobjs - ncopy);
- }
+ 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 *
+ sizeof(quarantine_obj_t));
}
return (ret);
@@ -85,10 +98,10 @@ quarantine_drain(quarantine_t *quarantine, size_t upper_bound)
{
while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) {
- void *ptr = quarantine->objs[quarantine->first];
- size_t usize = isalloc(ptr, config_prof);
- idalloc(ptr);
- quarantine->curbytes -= usize;
+ quarantine_obj_t *obj = &quarantine->objs[quarantine->first];
+ assert(obj->usize == isalloc(obj->ptr, config_prof));
+ idalloc(obj->ptr);
+ quarantine->curbytes -= obj->usize;
quarantine->curobjs--;
quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
quarantine->lg_maxobjs) - 1);
@@ -105,10 +118,25 @@ quarantine(void *ptr)
assert(opt_quarantine);
quarantine = *quarantine_tsd_get();
- if (quarantine == NULL && (quarantine =
- quarantine_init(LG_MAXOBJS_INIT)) == NULL) {
- idalloc(ptr);
- return;
+ if ((uintptr_t)quarantine <= (uintptr_t)QUARANTINE_STATE_MAX) {
+ if (quarantine == NULL) {
+ if ((quarantine = quarantine_init(LG_MAXOBJS_INIT)) ==
+ NULL) {
+ idalloc(ptr);
+ return;
+ }
+ } else {
+ if (quarantine == QUARANTINE_STATE_PURGATORY) {
+ /*
+ * Make a note that quarantine() was called
+ * after quarantine_cleanup() was called.
+ */
+ quarantine = QUARANTINE_STATE_REINCARNATED;
+ quarantine_tsd_set(&quarantine);
+ }
+ idalloc(ptr);
+ return;
+ }
}
/*
* Drain one or more objects if the quarantine size limit would be
@@ -128,7 +156,9 @@ quarantine(void *ptr)
if (quarantine->curbytes + usize <= opt_quarantine) {
size_t offset = (quarantine->first + quarantine->curobjs) &
((ZU(1) << quarantine->lg_maxobjs) - 1);
- quarantine->objs[offset] = ptr;
+ quarantine_obj_t *obj = &quarantine->objs[offset];
+ obj->ptr = ptr;
+ obj->usize = usize;
quarantine->curbytes += usize;
quarantine->curobjs++;
if (opt_junk)
@@ -144,9 +174,26 @@ quarantine_cleanup(void *arg)
{
quarantine_t *quarantine = *(quarantine_t **)arg;
- if (quarantine != NULL) {
+ if (quarantine == QUARANTINE_STATE_REINCARNATED) {
+ /*
+ * Another destructor deallocated memory after this destructor
+ * was called. Reset quarantine to QUARANTINE_STATE_PURGATORY
+ * in order to receive another callback.
+ */
+ quarantine = QUARANTINE_STATE_PURGATORY;
+ quarantine_tsd_set(&quarantine);
+ } else if (quarantine == QUARANTINE_STATE_PURGATORY) {
+ /*
+ * The previous time this destructor was called, we set the key
+ * to QUARANTINE_STATE_PURGATORY so that other destructors
+ * wouldn't cause re-creation of the quarantine. This time, do
+ * nothing, so that the destructor will not be called again.
+ */
+ } else if (quarantine != NULL) {
quarantine_drain(quarantine, 0);
idalloc(quarantine);
+ quarantine = QUARANTINE_STATE_PURGATORY;
+ quarantine_tsd_set(&quarantine);
}
}
OpenPOWER on IntegriCloud