Skip to content

Commit 99d9942

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 c913a63 commit 99d9942

2 files changed

Lines changed: 139 additions & 10 deletions

File tree

id_table.c

Lines changed: 130 additions & 10 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

@@ -373,8 +373,8 @@ rb_managed_id_table_new(size_t capa)
373373
static enum rb_id_table_iterator_result
374374
managed_id_table_dup_i(ID id, VALUE val, void *data)
375375
{
376-
struct rb_id_table *new_tbl = (struct rb_id_table *)data;
377-
rb_id_table_insert(new_tbl, id, val);
376+
VALUE new_table = (VALUE)data;
377+
rb_managed_id_table_insert(new_table, id, val);
378378
return ID_TABLE_CONTINUE;
379379
}
380380

@@ -384,12 +384,9 @@ rb_managed_id_table_dup(VALUE old_table)
384384
RUBY_ASSERT(RB_TYPE_P(old_table, T_DATA));
385385
RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(old_table), &managed_id_table_type));
386386

387-
struct rb_id_table *new_tbl;
388-
VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, &managed_id_table_type, new_tbl);
389-
struct rb_id_table *old_tbl = RTYPEDDATA_GET_DATA(old_table);
390-
rb_id_table_init(new_tbl, old_tbl->num + 1);
391-
rb_id_table_foreach(old_tbl, managed_id_table_dup_i, new_tbl);
392-
return obj;
387+
VALUE new_table = rb_managed_id_table_new(rb_managed_id_table_size(old_table) + 1);
388+
rb_managed_id_table_foreach(old_table, managed_id_table_dup_i, (void *)new_table);
389+
return new_table;
393390
}
394391

395392
int
@@ -427,3 +424,126 @@ rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void
427424

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

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)