Skip to content

Commit e73c842

Browse files
committed
Implement marked_id_table
Similar to `managed_id_table`, but the values are marked. This can be used to implement RCU pattern on id tables that contain marked objects (e.g. `class->const_tbl`).
1 parent 0bb44f2 commit e73c842

2 files changed

Lines changed: 150 additions & 2 deletions

File tree

id_table.c

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ rb_id_table_init(struct rb_id_table *tbl, size_t s_capa)
8787
MEMZERO(tbl, struct rb_id_table, 1);
8888
if (capa > 0) {
8989
capa = round_capa(capa);
90-
tbl->capa = (int)capa;
9190
tbl->items = ZALLOC_N(item_t, capa);
91+
tbl->capa = (int)capa;
9292
}
9393
return tbl;
9494
}
@@ -341,7 +341,7 @@ managed_id_table_free(void *data)
341341
static size_t
342342
managed_id_table_memsize(const void *data)
343343
{
344-
const struct rb_id_table *tbl = (const struct rb_id_table *)data;
344+
const struct rb_id_table *tbl = (struct rb_id_table *)data;
345345
return rb_id_table_memsize(tbl) - sizeof(struct rb_id_table);
346346
}
347347

@@ -427,3 +427,142 @@ rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void
427427

428428
rb_id_table_foreach(RTYPEDDATA_GET_DATA(table), func, data);
429429
}
430+
431+
static enum rb_id_table_iterator_result
432+
marked_id_table_mark_i(ID key, VALUE value, void *ref)
433+
{
434+
rb_gc_mark_movable(value);
435+
return ID_TABLE_CONTINUE;
436+
}
437+
438+
static void
439+
marked_id_table_mark(void *data)
440+
{
441+
struct rb_id_table *tbl = (struct rb_id_table *)data;
442+
rb_id_table_foreach(tbl, marked_id_table_mark_i, NULL);
443+
}
444+
445+
static enum rb_id_table_iterator_result
446+
marked_id_table_compact_check_i(VALUE value, void *data)
447+
{
448+
if (rb_gc_location(value) != value) {
449+
return ID_TABLE_REPLACE;
450+
}
451+
return ID_TABLE_CONTINUE;
452+
}
453+
454+
static enum rb_id_table_iterator_result
455+
marked_id_table_compact_replace_i(VALUE *value, void *data, int existing)
456+
{
457+
*value = rb_gc_location(*value);
458+
return ID_TABLE_CONTINUE;
459+
}
460+
461+
static void
462+
marked_id_table_compact(void *data)
463+
{
464+
struct rb_id_table *tbl = (struct rb_id_table *)data;
465+
rb_id_table_foreach_values_with_replace(tbl, marked_id_table_compact_check_i, marked_id_table_compact_replace_i, NULL);
466+
}
467+
468+
static const rb_data_type_t marked_id_table_type = {
469+
.wrap_struct_name = "VM/marked_id_table",
470+
.function = {
471+
.dmark = marked_id_table_mark,
472+
.dfree = (RUBY_DATA_FUNC)managed_id_table_free,
473+
.dsize = managed_id_table_memsize,
474+
.dcompact = marked_id_table_compact,
475+
},
476+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
477+
};
478+
479+
VALUE
480+
rb_marked_id_table_new(size_t capa)
481+
{
482+
struct rb_id_table *tbl;
483+
VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, &marked_id_table_type, tbl);
484+
rb_id_table_init(tbl, capa);
485+
return obj;
486+
}
487+
488+
struct marked_id_table_dup_args {
489+
struct rb_id_table *tbl;
490+
VALUE owner;
491+
};
492+
493+
static enum rb_id_table_iterator_result
494+
marked_id_table_dup_i(ID id, VALUE val, void *data)
495+
{
496+
struct marked_id_table_dup_args *args = (struct marked_id_table_dup_args *)data;
497+
498+
rb_id_table_insert(args->tbl, id, val);
499+
RB_OBJ_WRITTEN(args->owner, Qundef, val);
500+
return ID_TABLE_CONTINUE;
501+
}
502+
503+
size_t
504+
rb_marked_id_table_size(VALUE table)
505+
{
506+
RUBY_ASSERT(RB_TYPE_P(table, T_DATA));
507+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(table), &marked_id_table_type));
508+
509+
return rb_id_table_size(RTYPEDDATA_GET_DATA(table));
510+
}
511+
512+
VALUE
513+
rb_marked_id_table_dup(VALUE old_table)
514+
{
515+
RUBY_ASSERT(RB_TYPE_P(old_table, T_DATA));
516+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(old_table), &marked_id_table_type));
517+
518+
struct rb_id_table *new_tbl;
519+
VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, &marked_id_table_type, new_tbl);
520+
struct rb_id_table *old_tbl = RTYPEDDATA_GET_DATA(old_table);
521+
522+
struct marked_id_table_dup_args args = {
523+
.tbl = new_tbl,
524+
.owner = obj,
525+
};
526+
527+
rb_id_table_init(new_tbl, old_tbl->num + 1);
528+
rb_id_table_foreach(old_tbl, marked_id_table_dup_i, (void *)&args);
529+
return obj;
530+
}
531+
532+
int
533+
rb_marked_id_table_lookup(VALUE table, ID id, VALUE *valp)
534+
{
535+
RUBY_ASSERT(RB_TYPE_P(table, T_DATA));
536+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(table), &marked_id_table_type));
537+
538+
return rb_id_table_lookup(RTYPEDDATA_GET_DATA(table), id, valp);
539+
}
540+
541+
int
542+
rb_marked_id_table_insert(VALUE table, ID id, VALUE val)
543+
{
544+
RUBY_ASSERT(RB_TYPE_P(table, T_DATA));
545+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(table), &marked_id_table_type));
546+
547+
int retval = rb_id_table_insert(RTYPEDDATA_GET_DATA(table), id, val);
548+
RB_OBJ_WRITTEN(table, Qundef, val);
549+
return retval;
550+
}
551+
552+
int
553+
rb_marked_id_table_delete(VALUE table, ID id)
554+
{
555+
RUBY_ASSERT(RB_TYPE_P(table, T_DATA));
556+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(table), &marked_id_table_type));
557+
558+
return rb_id_table_delete(RTYPEDDATA_GET_DATA(table), id);
559+
}
560+
561+
void
562+
rb_marked_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data)
563+
{
564+
RUBY_ASSERT(RB_TYPE_P(table, T_DATA));
565+
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(table), &marked_id_table_type));
566+
567+
rb_id_table_foreach(RTYPEDDATA_GET_DATA(table), func, data);
568+
}

id_table.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ int rb_managed_id_table_lookup(VALUE table, ID id, VALUE *valp);
4242
size_t rb_managed_id_table_size(VALUE table);
4343
void rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data);
4444

45+
VALUE rb_marked_id_table_new(size_t capa);
46+
VALUE rb_marked_id_table_dup(VALUE table);
47+
int rb_marked_id_table_insert(VALUE table, ID id, VALUE val);
48+
int rb_marked_id_table_lookup(VALUE table, ID id, VALUE *valp);
49+
int rb_marked_id_table_delete(VALUE table, ID id);
50+
51+
size_t rb_marked_id_table_size(VALUE table);
52+
void rb_marked_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data);
53+
4554
RUBY_SYMBOL_EXPORT_BEGIN
4655
size_t rb_id_table_size(const struct rb_id_table *tbl);
4756
RUBY_SYMBOL_EXPORT_END

0 commit comments

Comments
 (0)