| 641 | } |
| 642 | |
| 643 | static void |
| 644 | prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { |
| 645 | prof_tdata_t *tdata = tctx->tdata; |
| 646 | prof_gctx_t *gctx = tctx->gctx; |
| 647 | bool destroy_tdata, destroy_tctx, destroy_gctx; |
| 648 | |
| 649 | malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock); |
| 650 | |
| 651 | assert(tctx->cnts.curobjs == 0); |
| 652 | assert(tctx->cnts.curbytes == 0); |
| 653 | assert(!opt_prof_accum); |
| 654 | assert(tctx->cnts.accumobjs == 0); |
| 655 | assert(tctx->cnts.accumbytes == 0); |
| 656 | |
| 657 | ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL); |
| 658 | destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false); |
| 659 | malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); |
| 660 | |
| 661 | malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); |
| 662 | switch (tctx->state) { |
| 663 | case prof_tctx_state_nominal: |
| 664 | tctx_tree_remove(&gctx->tctxs, tctx); |
| 665 | destroy_tctx = true; |
| 666 | if (prof_gctx_should_destroy(gctx)) { |
| 667 | /* |
| 668 | * Increment gctx->nlimbo in order to keep another |
| 669 | * thread from winning the race to destroy gctx while |
| 670 | * this one has gctx->lock dropped. Without this, it |
| 671 | * would be possible for another thread to: |
| 672 | * |
| 673 | * 1) Sample an allocation associated with gctx. |
| 674 | * 2) Deallocate the sampled object. |
| 675 | * 3) Successfully prof_gctx_try_destroy(gctx). |
| 676 | * |
| 677 | * The result would be that gctx no longer exists by the |
| 678 | * time this thread accesses it in |
| 679 | * prof_gctx_try_destroy(). |
| 680 | */ |
| 681 | gctx->nlimbo++; |
| 682 | destroy_gctx = true; |
| 683 | } else { |
| 684 | destroy_gctx = false; |
| 685 | } |
| 686 | break; |
| 687 | case prof_tctx_state_dumping: |
| 688 | /* |
| 689 | * A dumping thread needs tctx to remain valid until dumping |
| 690 | * has finished. Change state such that the dumping thread will |
| 691 | * complete destruction during a late dump iteration phase. |
| 692 | */ |
| 693 | tctx->state = prof_tctx_state_purgatory; |
| 694 | destroy_tctx = false; |
| 695 | destroy_gctx = false; |
| 696 | break; |
| 697 | default: |
| 698 | not_reached(); |
| 699 | destroy_tctx = false; |
| 700 | destroy_gctx = false; |
no test coverage detected