Make getting metadata user data a lock free operation

pull/3794/head
Craig Tiller 9 years ago
parent 63bda56884
commit 8344daa1df
  1. 37
      src/core/transport/metadata.c

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

Loading…
Cancel
Save