diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index 02f9cda754d..1b48b48e097 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -62,6 +62,8 @@ #define REF_MD_LOCKED(s) ref_md_locked((s)) #endif +typedef void (*destroy_user_data_func)(void *user_data); + typedef struct internal_string { /* must be byte compatible with grpc_mdstr */ gpr_slice slice; @@ -88,8 +90,8 @@ typedef struct internal_metadata { /* private only data */ gpr_mu mu_user_data; - void *user_data; - void (*destroy_user_data)(void *user_data); + gpr_atm destroy_user_data; + gpr_atm user_data; grpc_mdctx *context; struct internal_metadata *bucket_next; @@ -201,12 +203,14 @@ static void discard_metadata(grpc_mdctx *ctx) { for (i = 0; i < ctx->mdtab_capacity; i++) { cur = ctx->mdtab[i]; while (cur) { + void *user_data = (void *)gpr_atm_no_barrier_load(&cur->user_data); GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0); next = cur->bucket_next; INTERNAL_STRING_UNREF(cur->key); INTERNAL_STRING_UNREF(cur->value); - if (cur->user_data) { - cur->destroy_user_data(cur->user_data); + if (user_data != NULL) { + ((destroy_user_data_func)gpr_atm_no_barrier_load( + &cur->destroy_user_data))(user_data); } gpr_mu_destroy(&cur->mu_user_data); gpr_free(cur); @@ -392,12 +396,14 @@ static void gc_mdtab(grpc_mdctx *ctx) { for (i = 0; i < ctx->mdtab_capacity; i++) { prev_next = &ctx->mdtab[i]; for (md = ctx->mdtab[i]; md; md = next) { + void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data); next = md->bucket_next; if (gpr_atm_acq_load(&md->refcnt) == 0) { INTERNAL_STRING_UNREF(md->key); INTERNAL_STRING_UNREF(md->value); if (md->user_data) { - md->destroy_user_data(md->user_data); + ((destroy_user_data_func)gpr_atm_no_barrier_load( + &md->destroy_user_data))(user_data); } gpr_free(md); *prev_next = next; @@ -473,8 +479,8 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, md->context = ctx; md->key = key; md->value = value; - md->user_data = NULL; - md->destroy_user_data = NULL; + md->user_data = 0; + md->destroy_user_data = 0; md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity]; gpr_mu_init(&md->mu_user_data); #ifdef GRPC_METADATA_REFCOUNT_DEBUG @@ -588,13 +594,14 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) { return ctx->mdtab_free; } -void *grpc_mdelem_get_user_data(grpc_mdelem *md, - void (*if_destroy_func)(void *)) { +void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) { internal_metadata *im = (internal_metadata *)md; void *result; - gpr_mu_lock(&im->mu_user_data); - result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL; - gpr_mu_unlock(&im->mu_user_data); + if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } else { + return NULL; + } return result; } @@ -603,7 +610,7 @@ void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), internal_metadata *im = (internal_metadata *)md; GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); gpr_mu_lock(&im->mu_user_data); - if (im->destroy_user_data) { + if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { /* user data can only be set once */ gpr_mu_unlock(&im->mu_user_data); if (destroy_func != NULL) { @@ -611,8 +618,8 @@ void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), } return; } - im->destroy_user_data = destroy_func; - im->user_data = user_data; + gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); + gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); gpr_mu_unlock(&im->mu_user_data); }