| 909 | } |
| 910 | |
| 911 | static void |
| 912 | prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { |
| 913 | prof_tdata_t *tdata = tctx->tdata; |
| 914 | prof_gctx_t *gctx = tctx->gctx; |
| 915 | bool destroy_tdata, destroy_tctx, destroy_gctx; |
| 916 | |
| 917 | malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock); |
| 918 | |
| 919 | assert(tctx->cnts.curobjs == 0); |
| 920 | assert(tctx->cnts.curbytes == 0); |
| 921 | assert(!opt_prof_accum); |
| 922 | assert(tctx->cnts.accumobjs == 0); |
| 923 | assert(tctx->cnts.accumbytes == 0); |
| 924 | |
| 925 | ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL); |
| 926 | destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false); |
| 927 | malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); |
| 928 | |
| 929 | malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); |
| 930 | switch (tctx->state) { |
| 931 | case prof_tctx_state_nominal: |
| 932 | tctx_tree_remove(&gctx->tctxs, tctx); |
| 933 | destroy_tctx = true; |
| 934 | if (prof_gctx_should_destroy(gctx)) { |
| 935 | /* |
| 936 | * Increment gctx->nlimbo in order to keep another |
| 937 | * thread from winning the race to destroy gctx while |
| 938 | * this one has gctx->lock dropped. Without this, it |
| 939 | * would be possible for another thread to: |
| 940 | * |
| 941 | * 1) Sample an allocation associated with gctx. |
| 942 | * 2) Deallocate the sampled object. |
| 943 | * 3) Successfully prof_gctx_try_destroy(gctx). |
| 944 | * |
| 945 | * The result would be that gctx no longer exists by the |
| 946 | * time this thread accesses it in |
| 947 | * prof_gctx_try_destroy(). |
| 948 | */ |
| 949 | gctx->nlimbo++; |
| 950 | destroy_gctx = true; |
| 951 | } else { |
| 952 | destroy_gctx = false; |
| 953 | } |
| 954 | break; |
| 955 | case prof_tctx_state_dumping: |
| 956 | /* |
| 957 | * A dumping thread needs tctx to remain valid until dumping |
| 958 | * has finished. Change state such that the dumping thread will |
| 959 | * complete destruction during a late dump iteration phase. |
| 960 | */ |
| 961 | tctx->state = prof_tctx_state_purgatory; |
| 962 | destroy_tctx = false; |
| 963 | destroy_gctx = false; |
| 964 | break; |
| 965 | default: |
| 966 | not_reached(); |
| 967 | destroy_tctx = false; |
| 968 | destroy_gctx = false; |
no test coverage detected