diff options
author | Joshua Haberman <joshua@reverberate.org> | 2009-12-06 17:12:39 -0800 |
---|---|---|
committer | Joshua Haberman <joshua@reverberate.org> | 2009-12-06 17:12:39 -0800 |
commit | dc4246db788fc54a633189047bb696c5a33b884c (patch) | |
tree | 3fedc7140fec64f046a6c774102fecbbb7da9245 /src/upb_def.c | |
parent | 2a8ba6f3a26177e98a255ac129568feb6c1440aa (diff) |
Refined interface of upb_symtab.
Diffstat (limited to 'src/upb_def.c')
-rw-r--r-- | src/upb_def.c | 76 |
1 files changed, 52 insertions, 24 deletions
diff --git a/src/upb_def.c b/src/upb_def.c index e48e825..1983be4 100644 --- a/src/upb_def.c +++ b/src/upb_def.c @@ -147,8 +147,8 @@ void _upb_def_cyclic_ref(struct upb_def *def) { cycle_ref_or_unref(upb_downcast_msgdef(def), NULL, open_defs, 0, true); } -void upb_def_init(struct upb_def *def, enum upb_def_type type, - struct upb_string *fqname) { +static void upb_def_init(struct upb_def *def, enum upb_def_type type, + struct upb_string *fqname) { def->type = type; def->is_cyclic = 0; // We detect this later, after resolving refs. def->search_depth = 0; @@ -157,7 +157,7 @@ void upb_def_init(struct upb_def *def, enum upb_def_type type, upb_atomic_refcount_init(&def->refcount, 1); } -void upb_def_uninit(struct upb_def *def) { +static void upb_def_uninit(struct upb_def *def) { upb_string_unref(def->fqname); } @@ -732,20 +732,26 @@ void _upb_symtab_free(struct upb_symtab *s) free(s); } -struct upb_def **upb_symtab_getandref_defs(struct upb_symtab *s, int *count) +struct upb_def **upb_symtab_getdefs(struct upb_symtab *s, int *count, + upb_def_type_t type) { - upb_rwlock_wrlock(&s->lock); - *count = upb_strtable_count(&s->symtab); - struct upb_def **defs = malloc(sizeof(*defs) * (*count)); + upb_rwlock_rdlock(&s->lock); + int total = upb_strtable_count(&s->symtab); + // We may only use part of this, depending on how many symbols are of the + // correct type. + struct upb_def **defs = malloc(sizeof(*defs) * total); struct symtab_ent *e = upb_strtable_begin(&s->symtab); int i = 0; - for(; e; e = upb_strtable_next(&s->symtab, &e->e), i++) { - assert(e->def); - defs[i] = e->def; - upb_def_ref(defs[i]); + for(; e; e = upb_strtable_next(&s->symtab, &e->e)) { + struct upb_def *def = e->def; + assert(def); + if(type == UPB_DEF_ANY || def->type == type) + defs[i++] = def; } - assert(*count == i); upb_rwlock_unlock(&s->lock); + *count = i; + for(i = 0; i < *count; i++) + upb_def_ref(defs[i]); return defs; } @@ -769,8 +775,13 @@ struct upb_def *upb_symtab_resolve(struct upb_symtab *s, struct upb_string *symbol) { upb_rwlock_rdlock(&s->lock); struct symtab_ent *e = resolve(&s->symtab, base, symbol); + struct upb_def *ret = NULL; + if(e) { + ret = e->def; + upb_def_ref(ret); + } upb_rwlock_unlock(&s->lock); - return e ? e->def : NULL; + return ret; } void upb_symtab_addfds(struct upb_symtab *s, @@ -782,23 +793,40 @@ void upb_symtab_addfds(struct upb_symtab *s, // the descriptor is valid. struct upb_strtable tmp; upb_strtable_init(&tmp, 0, sizeof(struct symtab_ent)); - upb_rwlock_rdlock(&s->lock); - for(uint32_t i = 0; i < fds->file->len; i++) { - addfd(&tmp, &s->symtab, fds->file->elements[i], true, status); - if(!upb_ok(status)) { - free_symtab(&tmp); - upb_rwlock_unlock(&s->lock); - return; + + { // Read lock scope + upb_rwlock_rdlock(&s->lock); + for(uint32_t i = 0; i < fds->file->len; i++) { + addfd(&tmp, &s->symtab, fds->file->elements[i], true, status); + if(!upb_ok(status)) { + free_symtab(&tmp); + upb_rwlock_unlock(&s->lock); + return; + } } + upb_rwlock_unlock(&s->lock); } - upb_rwlock_unlock(&s->lock); // Everything was successfully added, copy from the tmp symtable. - struct symtab_ent *e; - { + { // Write lock scope upb_rwlock_wrlock(&s->lock); - for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) + struct symtab_ent *e; + for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) { + // We checked for duplicates when we had only the read lock, but it is + // theoretically possible that a duplicate symbol when we dropped the + // read lock to acquire a write lock. + if(upb_strtable_lookup(&s->symtab, e->e.key)) { + upb_seterr(status, UPB_STATUS_ERROR, "Attempted to insert duplicate " + "symbol: " UPB_STRFMT, UPB_STRARG(e->e.key)); + // To truly handle this situation we would need to remove any symbols + // from tmp that were successfully inserted into s->symtab. Because + // this case is exceedingly unlikely, and because our hashtable + // doesn't support deletions right now, we leave them in there, which + // means we must not call free_symtab(&s->symtab), so we will leak it. + break; + } upb_strtable_insert(&s->symtab, &e->e); + } upb_rwlock_unlock(&s->lock); } upb_strtable_free(&tmp); |