Handle prof_tdata resurrection.
Handle prof_tdata resurrection during thread shutdown, similarly to how tcache and quarantine handle resurrection.
This commit is contained in:
parent
95ff6aadca
commit
0050a0f7e6
@ -37,6 +37,14 @@ typedef struct prof_tdata_s prof_tdata_t;
|
|||||||
*/
|
*/
|
||||||
#define PROF_NCTX_LOCKS 1024
|
#define PROF_NCTX_LOCKS 1024
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prof_tdata pointers close to NULL are used to encode state information that
|
||||||
|
* is used for cleaning up during thread shutdown.
|
||||||
|
*/
|
||||||
|
#define PROF_TDATA_STATE_REINCARNATED ((prof_tdata_t *)(uintptr_t)1)
|
||||||
|
#define PROF_TDATA_STATE_PURGATORY ((prof_tdata_t *)(uintptr_t)2)
|
||||||
|
#define PROF_TDATA_STATE_MAX PROF_TDATA_STATE_PURGATORY
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_TYPES */
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_STRUCTS
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
@ -297,8 +305,12 @@ prof_tdata_get(void)
|
|||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
prof_tdata = *prof_tdata_tsd_get();
|
prof_tdata = *prof_tdata_tsd_get();
|
||||||
|
if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) {
|
||||||
if (prof_tdata == NULL)
|
if (prof_tdata == NULL)
|
||||||
prof_tdata = prof_tdata_init();
|
prof_tdata = prof_tdata_init();
|
||||||
|
else
|
||||||
|
prof_tdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return (prof_tdata);
|
return (prof_tdata);
|
||||||
}
|
}
|
||||||
@ -382,7 +394,7 @@ prof_sample_accum_update(size_t size)
|
|||||||
assert(opt_lg_prof_sample != 0);
|
assert(opt_lg_prof_sample != 0);
|
||||||
|
|
||||||
prof_tdata = *prof_tdata_tsd_get();
|
prof_tdata = *prof_tdata_tsd_get();
|
||||||
assert(prof_tdata != NULL);
|
assert((uintptr_t)prof_tdata > (uintptr_t)PROF_TDATA_STATE_MAX);
|
||||||
|
|
||||||
/* Take care to avoid integer overflow. */
|
/* Take care to avoid integer overflow. */
|
||||||
if (size >= prof_tdata->threshold - prof_tdata->accum) {
|
if (size >= prof_tdata->threshold - prof_tdata->accum) {
|
||||||
|
36
src/prof.c
36
src/prof.c
@ -686,7 +686,7 @@ prof_ctx_destroy(prof_ctx_t *ctx)
|
|||||||
* into this function.
|
* into this function.
|
||||||
*/
|
*/
|
||||||
prof_tdata = *prof_tdata_tsd_get();
|
prof_tdata = *prof_tdata_tsd_get();
|
||||||
assert(prof_tdata != NULL);
|
assert((uintptr_t)prof_tdata > (uintptr_t)PROF_TDATA_STATE_MAX);
|
||||||
prof_enter(prof_tdata);
|
prof_enter(prof_tdata);
|
||||||
malloc_mutex_lock(ctx->lock);
|
malloc_mutex_lock(ctx->lock);
|
||||||
if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 0 &&
|
if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 0 &&
|
||||||
@ -972,7 +972,7 @@ prof_idump(void)
|
|||||||
* allocation.
|
* allocation.
|
||||||
*/
|
*/
|
||||||
prof_tdata = *prof_tdata_tsd_get();
|
prof_tdata = *prof_tdata_tsd_get();
|
||||||
if (prof_tdata == NULL)
|
if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)
|
||||||
return;
|
return;
|
||||||
if (prof_tdata->enq) {
|
if (prof_tdata->enq) {
|
||||||
prof_tdata->enq_idump = true;
|
prof_tdata->enq_idump = true;
|
||||||
@ -1026,7 +1026,7 @@ prof_gdump(void)
|
|||||||
* allocation.
|
* allocation.
|
||||||
*/
|
*/
|
||||||
prof_tdata = *prof_tdata_tsd_get();
|
prof_tdata = *prof_tdata_tsd_get();
|
||||||
if (prof_tdata == NULL)
|
if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)
|
||||||
return;
|
return;
|
||||||
if (prof_tdata->enq) {
|
if (prof_tdata->enq) {
|
||||||
prof_tdata->enq_gdump = true;
|
prof_tdata->enq_gdump = true;
|
||||||
@ -1141,21 +1141,41 @@ prof_tdata_cleanup(void *arg)
|
|||||||
|
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
|
if (prof_tdata == PROF_TDATA_STATE_REINCARNATED) {
|
||||||
/*
|
/*
|
||||||
* Delete the hash table. All of its contents can still be iterated
|
* Another destructor deallocated memory after this destructor
|
||||||
* over via the LRU.
|
* was called. Reset prof_tdata to PROF_TDATA_STATE_PURGATORY
|
||||||
|
* in order to receive another callback.
|
||||||
|
*/
|
||||||
|
prof_tdata = PROF_TDATA_STATE_PURGATORY;
|
||||||
|
prof_tdata_tsd_set(&prof_tdata);
|
||||||
|
} else if (prof_tdata == PROF_TDATA_STATE_PURGATORY) {
|
||||||
|
/*
|
||||||
|
* The previous time this destructor was called, we set the key
|
||||||
|
* to PROF_TDATA_STATE_PURGATORY so that other destructors
|
||||||
|
* wouldn't cause re-creation of the prof_tdata. This time, do
|
||||||
|
* nothing, so that the destructor will not be called again.
|
||||||
|
*/
|
||||||
|
} else if (prof_tdata != NULL) {
|
||||||
|
/*
|
||||||
|
* Delete the hash table. All of its contents can still be
|
||||||
|
* iterated over via the LRU.
|
||||||
*/
|
*/
|
||||||
ckh_delete(&prof_tdata->bt2cnt);
|
ckh_delete(&prof_tdata->bt2cnt);
|
||||||
|
/*
|
||||||
/* Iteratively merge cnt's into the global stats and delete them. */
|
* Iteratively merge cnt's into the global stats and delete
|
||||||
|
* them.
|
||||||
|
*/
|
||||||
while ((cnt = ql_last(&prof_tdata->lru_ql, lru_link)) != NULL) {
|
while ((cnt = ql_last(&prof_tdata->lru_ql, lru_link)) != NULL) {
|
||||||
ql_remove(&prof_tdata->lru_ql, cnt, lru_link);
|
ql_remove(&prof_tdata->lru_ql, cnt, lru_link);
|
||||||
prof_ctx_merge(cnt->ctx, cnt);
|
prof_ctx_merge(cnt->ctx, cnt);
|
||||||
idalloc(cnt);
|
idalloc(cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
idalloc(prof_tdata->vec);
|
idalloc(prof_tdata->vec);
|
||||||
idalloc(prof_tdata);
|
idalloc(prof_tdata);
|
||||||
|
prof_tdata = PROF_TDATA_STATE_PURGATORY;
|
||||||
|
prof_tdata_tsd_set(&prof_tdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user