Call prof_gctx_create() without owing bt2gctx_mtx.
This reduces the probability of allocating (and thereby indirectly
making a system call) while owning bt2gctx_mtx. Unfortunately it is an
incomplete solution, because ckh insertion/deletion can also
allocate/deallocate, which requires more extensive changes to address.
diff --git a/src/prof.c b/src/prof.c
index 28d30f2..5aeefb2 100644
--- a/src/prof.c
+++ b/src/prof.c
@@ -708,7 +708,7 @@
union {
prof_gctx_t *p;
void *v;
- } gctx;
+ } gctx, tgctx;
union {
prof_bt_t *p;
void *v;
@@ -718,21 +718,32 @@
prof_enter(tsd, tdata);
if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
/* bt has never been seen before. Insert it. */
- gctx.p = prof_gctx_create(tsd_tsdn(tsd), bt);
- if (gctx.v == NULL) {
- prof_leave(tsd, tdata);
+ prof_leave(tsd, tdata);
+ tgctx.p = prof_gctx_create(tsd_tsdn(tsd), bt);
+ if (tgctx.v == NULL) {
return true;
}
- btkey.p = &gctx.p->bt;
- if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) {
- /* OOM. */
- prof_leave(tsd, tdata);
- idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx.v),
- gctx.v, NULL, true, true);
- return true;
+ prof_enter(tsd, tdata);
+ if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
+ gctx.p = tgctx.p;
+ btkey.p = &gctx.p->bt;
+ if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) {
+ /* OOM. */
+ prof_leave(tsd, tdata);
+ idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd),
+ gctx.v), gctx.v, NULL, true, true);
+ return true;
+ }
+ new_gctx = true;
+ } else {
+ new_gctx = false;
}
- new_gctx = true;
} else {
+ tgctx.v = NULL;
+ new_gctx = false;
+ }
+
+ if (!new_gctx) {
/*
* Increment nlimbo, in order to avoid a race condition with
* prof_tctx_destroy()/prof_gctx_try_destroy().
@@ -741,6 +752,12 @@
gctx.p->nlimbo++;
malloc_mutex_unlock(tsd_tsdn(tsd), gctx.p->lock);
new_gctx = false;
+
+ if (tgctx.v != NULL) {
+ /* Lost race to insert. */
+ idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd),
+ tgctx.v), tgctx.v, NULL, true, true);
+ }
}
prof_leave(tsd, tdata);