farce 0.1.0-arm-linux-gnu → 0.2.0-arm-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -1
  3. data/README.md +72 -16
  4. data/docs/gems/dry-types.md +8 -8
  5. data/docs/modes.md +67 -10
  6. data/ext/farce/atom.c +37 -22
  7. data/ext/farce/bounded_map.c +17 -13
  8. data/ext/farce/containers.h +15 -0
  9. data/ext/farce/counter.c +13 -18
  10. data/ext/farce/exchanger.c +5 -1
  11. data/ext/farce/farce.c +1 -1
  12. data/ext/farce/flag.c +39 -3
  13. data/ext/farce/io.c +3 -3
  14. data/ext/farce/lock.c +17 -23
  15. data/ext/farce/map.c +88 -66
  16. data/ext/farce/priority_queue.c +55 -43
  17. data/ext/farce/queue.c +10 -4
  18. data/ext/farce/reactor.c +52 -25
  19. data/ext/farce/reactor.h +1 -1
  20. data/ext/farce/signal.c +5 -1
  21. data/ext/farce/transaction.c +20 -24
  22. data/ext/farce/tree_map.c +33 -18
  23. data/ext/farce/trie.c +81 -43
  24. data/ext/farce/unshareable.c +168 -19
  25. data/ext/farce/unshared_io_pool.h +21 -12
  26. data/ext/farce/unshared_signal.c +13 -2
  27. data/ext/farce/unshared_wait.h +3 -0
  28. data/ext/farce/vector.c +82 -18
  29. data/ext/farce/weak_map.c +75 -63
  30. data/lib/farce/_yard/macros.rb +18 -3
  31. data/lib/farce/abstract/flag.rb +73 -0
  32. data/lib/farce/abstract/queue.rb +4 -3
  33. data/lib/farce/abstract/scheduler.rb +3 -3
  34. data/lib/farce/abstract/set.rb +17 -5
  35. data/lib/farce/abstract/sorted_set.rb +2 -2
  36. data/lib/farce/abstract/timer_queue.rb +49 -10
  37. data/lib/farce/abstract/vector.rb +510 -28
  38. data/lib/farce/atom.rb +1 -1
  39. data/lib/farce/class_mirror.rb +20 -7
  40. data/lib/farce/config.rb +7 -1
  41. data/lib/farce/engine/jvm/flag.rb +15 -3
  42. data/lib/farce/engine/ruby/3.4/farce.so +0 -0
  43. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  44. data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
  45. data/lib/farce/engine/ruby.rb +7 -0
  46. data/lib/farce/engine/shared/unshared_vector.rb +31 -4
  47. data/lib/farce/engine/shared/vector.rb +8 -0
  48. data/lib/farce/engine/shared/weak_map/index.rb +14 -1
  49. data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
  50. data/lib/farce/envelope.rb +54 -7
  51. data/lib/farce/exchanger.rb +1 -1
  52. data/lib/farce/flag.rb +2 -0
  53. data/lib/farce/integrations/active_support.rb +1 -1
  54. data/lib/farce/integrations/bson.rb +1 -1
  55. data/lib/farce/integrations/cbor.rb +1 -1
  56. data/lib/farce/integrations/concurrent.rb +3 -3
  57. data/lib/farce/integrations/date.rb +8 -0
  58. data/lib/farce/integrations/dry_types.rb +7 -4
  59. data/lib/farce/integrations/json.rb +2 -2
  60. data/lib/farce/integrations/msgpack.rb +1 -1
  61. data/lib/farce/integrations/oj.rb +3 -4
  62. data/lib/farce/integrations/psych.rb +1 -1
  63. data/lib/farce/integrations/ractor_sharing.rb +1 -1
  64. data/lib/farce/integrations/sorted_set.rb +1 -1
  65. data/lib/farce/integrations/weakref.rb +9 -1
  66. data/lib/farce/integrations/yajl.rb +3 -3
  67. data/lib/farce/integrations.rb +33 -23
  68. data/lib/farce/internal/flag_waiting.rb +30 -0
  69. data/lib/farce/internal/freeze.rb +8 -3
  70. data/lib/farce/internal/map_value_modes.rb +1 -1
  71. data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
  72. data/lib/farce/lazy.rb +4 -4
  73. data/lib/farce/lazy_ref.rb +3 -3
  74. data/lib/farce/lfu_map.rb +1 -1
  75. data/lib/farce/local/flag.rb +4 -0
  76. data/lib/farce/local/scoped.rb +1 -1
  77. data/lib/farce/lru_map.rb +1 -1
  78. data/lib/farce/map.rb +2 -2
  79. data/lib/farce/mode_manager/smart_rule.rb +138 -0
  80. data/lib/farce/mode_manager.rb +12 -3
  81. data/lib/farce/molecule.rb +2 -2
  82. data/lib/farce/pool.rb +1 -1
  83. data/lib/farce/port.rb +4 -4
  84. data/lib/farce/priority_queue.rb +1 -1
  85. data/lib/farce/proxy/register.rb +6 -0
  86. data/lib/farce/proxy/supervisor.rb +1 -1
  87. data/lib/farce/proxy.rb +7 -2
  88. data/lib/farce/queue.rb +1 -1
  89. data/lib/farce/scheduler.rb +2 -2
  90. data/lib/farce/set.rb +1 -1
  91. data/lib/farce/sorted_set.rb +1 -1
  92. data/lib/farce/timer_queue.rb +20 -6
  93. data/lib/farce/transaction/vector.rb +43 -9
  94. data/lib/farce/transaction/wrapper.rb +14 -0
  95. data/lib/farce/tree_map.rb +1 -1
  96. data/lib/farce/unsafe/lfu_map.rb +2 -0
  97. data/lib/farce/unsafe/lru_map.rb +2 -0
  98. data/lib/farce/unsafe/tree_map.rb +2 -0
  99. data/lib/farce/unshareable.rb +8 -19
  100. data/lib/farce/unshared/atom.rb +3 -0
  101. data/lib/farce/unshared/lfu_map.rb +2 -0
  102. data/lib/farce/unshared/lru_map.rb +2 -0
  103. data/lib/farce/unshared/map.rb +3 -0
  104. data/lib/farce/unshared/set.rb +1 -0
  105. data/lib/farce/unshared/sorted_set.rb +1 -0
  106. data/lib/farce/unshared/tree_map.rb +5 -1
  107. data/lib/farce/unshared/vector.rb +3 -0
  108. data/lib/farce/unshared/weak_atom.rb +5 -1
  109. data/lib/farce/unshared/weak_key_map.rb +3 -0
  110. data/lib/farce/unshared/weak_map.rb +3 -0
  111. data/lib/farce/unshared/weak_set.rb +1 -0
  112. data/lib/farce/unshared/weak_value_map.rb +3 -0
  113. data/lib/farce/vector.rb +44 -19
  114. data/lib/farce/version.rb +1 -1
  115. data/lib/farce.rb +11 -8
  116. metadata +5 -1
data/ext/farce/atom.c CHANGED
@@ -44,6 +44,14 @@ typedef struct {
44
44
  bool initialized;
45
45
  } atom_t;
46
46
 
47
+ /* Weak edges use the VM's separately registered weak-reference callback. */
48
+ static inline void
49
+ atom_write_value(VALUE self, atom_t *atom, VALUE value)
50
+ {
51
+ if (atom->weak) atom->value = value;
52
+ else RB_OBJ_WRITE(self, &atom->value, value);
53
+ }
54
+
47
55
  typedef struct {
48
56
  bool finite;
49
57
  bool collected;
@@ -158,9 +166,9 @@ static void
158
166
  atom_compact(void *pointer)
159
167
  {
160
168
  atom_t *atom = pointer;
161
- atom->value = rb_gc_location(atom->value);
162
- atom->updating_fiber = rb_gc_location(atom->updating_fiber);
163
- atom->updating_thread = rb_gc_location(atom->updating_thread);
169
+ containers_gc_update(&atom->value);
170
+ containers_gc_update(&atom->updating_fiber);
171
+ containers_gc_update(&atom->updating_thread);
164
172
  }
165
173
 
166
174
  #ifdef RC_HAVE_NATIVE_WEAK_REFERENCES
@@ -203,7 +211,11 @@ static const rb_data_type_t atom_type = {
203
211
  .handle_weak_references = atom_handle_weak_references,
204
212
  #endif
205
213
  },
206
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
214
+ .flags =
215
+ RUBY_TYPED_WB_PROTECTED |
216
+ RUBY_TYPED_FROZEN_SHAREABLE |
217
+ RUBY_TYPED_FREE_IMMEDIATELY |
218
+ FARCE_TYPED_THREAD_SAFE_FREE,
207
219
  };
208
220
 
209
221
  static void
@@ -228,6 +240,7 @@ static const rb_data_type_t unshared_weak_atom_type = {
228
240
  .handle_weak_references = atom_handle_weak_references,
229
241
  },
230
242
  .parent = &atom_type,
243
+ .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
231
244
  };
232
245
  #endif
233
246
 
@@ -296,11 +309,11 @@ atom_check_update_wait_locked(atom_t *atom, const atom_execution_context_t *cont
296
309
  }
297
310
 
298
311
  static void
299
- atom_begin_update_locked(atom_t *atom, const atom_execution_context_t *context)
312
+ atom_begin_update_locked(VALUE self, atom_t *atom, const atom_execution_context_t *context)
300
313
  {
301
314
  atom->updating = true;
302
- atom->updating_fiber = context->fiber;
303
- atom->updating_thread = context->thread;
315
+ RB_OBJ_WRITE(self, &atom->updating_fiber, context->fiber);
316
+ RB_OBJ_WRITE(self, &atom->updating_thread, context->thread);
304
317
  }
305
318
 
306
319
  static void
@@ -491,7 +504,7 @@ atom_initialize(int argc, VALUE *argv, VALUE self)
491
504
  TypedData_Get_Struct(self, atom_t, &atom_type, atom);
492
505
  if (atom->initialized) rb_raise(rb_eRuntimeError, "Atom is already initialized");
493
506
  atom_check_value(atom, value);
494
- atom->value = value;
507
+ atom_write_value(self, atom, value);
495
508
  atom->compare_by_identity = identity == Qundef ? false : containers_strict_bool(identity, "compare_by_identity");
496
509
  #ifdef RC_HAVE_NATIVE_WEAK_REFERENCES
497
510
  if (atom->weak) rb_gc_declare_weak_references(self);
@@ -520,7 +533,7 @@ atom_set_value(VALUE self, VALUE value)
520
533
  atom_check_value(atom, value);
521
534
  atom_execution_context_t execution = atom_current_execution_context();
522
535
  atom_lock_for_update(atom, &execution);
523
- atom->value = value;
536
+ atom_write_value(self, atom, value);
524
537
  atom_changed(atom);
525
538
  pthread_mutex_unlock(&atom->lock);
526
539
  return value;
@@ -560,7 +573,7 @@ atom_store(int argc, VALUE *argv, VALUE self)
560
573
  for (;;) {
561
574
  pthread_mutex_lock(&atom->lock);
562
575
  if (!atom->updating) {
563
- atom->value = value;
576
+ atom_write_value(self, atom, value);
564
577
  atom_changed(atom);
565
578
  pthread_mutex_unlock(&atom->lock);
566
579
  return value;
@@ -586,7 +599,7 @@ atom_swap(int argc, VALUE *argv, VALUE self)
586
599
  pthread_mutex_lock(&atom->lock);
587
600
  if (!atom->updating) {
588
601
  VALUE previous = atom->value;
589
- atom->value = value;
602
+ atom_write_value(self, atom, value);
590
603
  atom_changed(atom);
591
604
  pthread_mutex_unlock(&atom->lock);
592
605
  return previous;
@@ -626,7 +639,7 @@ atom_store_body(VALUE opaque)
626
639
  rb_check_frozen(operation->self);
627
640
  atom_check_value(operation->atom, result);
628
641
  pthread_mutex_lock(&operation->atom->lock);
629
- operation->atom->value = result;
642
+ atom_write_value(operation->self, operation->atom, result);
630
643
  atom_finished_update(operation->atom, true);
631
644
  pthread_mutex_unlock(&operation->atom->lock);
632
645
  operation->complete = true;
@@ -654,7 +667,7 @@ atom_store_if_absent(int argc, VALUE *argv, VALUE self)
654
667
  pthread_mutex_unlock(&atom->lock);
655
668
  return value;
656
669
  }
657
- atom_begin_update_locked(atom, &operation.execution);
670
+ atom_begin_update_locked(self, atom, &operation.execution);
658
671
  pthread_mutex_unlock(&atom->lock);
659
672
  return rb_ensure(atom_store_body, (VALUE)&operation, atom_operation_cleanup, (VALUE)&operation);
660
673
  }
@@ -692,7 +705,9 @@ atom_cas_body(VALUE opaque)
692
705
  rb_check_frozen(operation->self);
693
706
 
694
707
  pthread_mutex_lock(&operation->atom->lock);
695
- if (matches) operation->atom->value = operation->replacement;
708
+ if (matches) {
709
+ atom_write_value(operation->self, operation->atom, operation->replacement);
710
+ }
696
711
  atom_finished_update(operation->atom, matches);
697
712
  pthread_mutex_unlock(&operation->atom->lock);
698
713
  operation->complete = true;
@@ -730,7 +745,7 @@ atom_compare_and_set(int argc, VALUE *argv, VALUE self)
730
745
  operation.replacement = replacement;
731
746
  operation.identity = atom->compare_by_identity;
732
747
  operation.complete = false;
733
- atom_begin_update_locked(atom, &operation.execution);
748
+ atom_begin_update_locked(self, atom, &operation.execution);
734
749
  pthread_mutex_unlock(&atom->lock);
735
750
 
736
751
  return rb_ensure(atom_cas_body, (VALUE)&operation, atom_cas_cleanup, (VALUE)&operation);
@@ -744,7 +759,7 @@ atom_update_body(VALUE opaque)
744
759
  rb_check_frozen(operation->self);
745
760
  atom_check_value(operation->atom, result);
746
761
  pthread_mutex_lock(&operation->atom->lock);
747
- operation->atom->value = result;
762
+ atom_write_value(operation->self, operation->atom, result);
748
763
  atom_finished_update(operation->atom, true);
749
764
  pthread_mutex_unlock(&operation->atom->lock);
750
765
  operation->complete = true;
@@ -768,7 +783,7 @@ atom_update(int argc, VALUE *argv, VALUE self)
768
783
 
769
784
  if (!atom_lock_for_update_with_timeout(atom, &timeout, &operation.execution)) return Qnil;
770
785
  operation.current = atom->value;
771
- atom_begin_update_locked(atom, &operation.execution);
786
+ atom_begin_update_locked(self, atom, &operation.execution);
772
787
  pthread_mutex_unlock(&atom->lock);
773
788
 
774
789
  return rb_ensure(atom_update_body, (VALUE)&operation, atom_operation_cleanup, (VALUE)&operation);
@@ -793,13 +808,13 @@ atom_upsert(int argc, VALUE *argv, VALUE self)
793
808
 
794
809
  if (!atom_lock_for_update_with_timeout(atom, &timeout, &operation.execution)) return Qnil;
795
810
  if (NIL_P(atom->value)) {
796
- atom->value = initial;
811
+ atom_write_value(self, atom, initial);
797
812
  atom_changed(atom);
798
813
  pthread_mutex_unlock(&atom->lock);
799
814
  return initial;
800
815
  }
801
816
  operation.current = atom->value;
802
- atom_begin_update_locked(atom, &operation.execution);
817
+ atom_begin_update_locked(self, atom, &operation.execution);
803
818
  pthread_mutex_unlock(&atom->lock);
804
819
 
805
820
  return rb_ensure(atom_update_body, (VALUE)&operation, atom_operation_cleanup, (VALUE)&operation);
@@ -927,7 +942,7 @@ atom_transaction_apply(farce_transaction_entry_t *entry)
927
942
  {
928
943
  atom_t *atom = entry->source_data;
929
944
  atom_t *working = entry->working_data;
930
- atom->value = working->value;
945
+ RB_OBJ_WRITE(entry->source, &atom->value, working->value);
931
946
  }
932
947
 
933
948
  static void
@@ -941,8 +956,8 @@ atom_transaction_reserve(farce_transaction_entry_t *entry, VALUE fiber, VALUE th
941
956
  {
942
957
  atom_t *atom = entry->source_data;
943
958
  atom->updating = FARCE_TRANSACTION_RESERVED;
944
- atom->updating_fiber = fiber;
945
- atom->updating_thread = thread;
959
+ RB_OBJ_WRITE(entry->source, &atom->updating_fiber, fiber);
960
+ RB_OBJ_WRITE(entry->source, &atom->updating_thread, thread);
946
961
  }
947
962
 
948
963
  static void
@@ -153,17 +153,17 @@ lru_compact(void *opaque)
153
153
  lru_map_t *map = opaque;
154
154
  if (map == NULL) return;
155
155
 
156
- map->lock = rb_gc_location(map->lock);
156
+ containers_gc_update(&map->lock);
157
157
  if (map->lfu_policy) {
158
158
  for (lfu_bucket_t *bucket = map->least_frequency;
159
159
  bucket != NULL;
160
160
  bucket = bucket->following) {
161
- bucket->frequency = rb_gc_location(bucket->frequency);
161
+ containers_gc_update(&bucket->frequency);
162
162
  for (lru_entry_t *entry = bucket->least_recent;
163
163
  entry != NULL;
164
164
  entry = entry->following) {
165
- entry->key = rb_gc_location(entry->key);
166
- entry->value = rb_gc_location(entry->value);
165
+ containers_gc_update(&entry->key);
166
+ containers_gc_update(&entry->value);
167
167
  }
168
168
  }
169
169
  }
@@ -171,8 +171,8 @@ lru_compact(void *opaque)
171
171
  for (lru_entry_t *entry = map->least_recent;
172
172
  entry != NULL;
173
173
  entry = entry->following) {
174
- entry->key = rb_gc_location(entry->key);
175
- entry->value = rb_gc_location(entry->value);
174
+ containers_gc_update(&entry->key);
175
+ containers_gc_update(&entry->value);
176
176
  }
177
177
  }
178
178
  }
@@ -207,7 +207,7 @@ static const rb_data_type_t lru_map_type = {
207
207
  .dsize = lru_memsize,
208
208
  .dcompact = lru_compact,
209
209
  },
210
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
210
+ .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
211
211
  };
212
212
 
213
213
  static const rb_data_type_t lru_shared_map_type = {
@@ -218,7 +218,11 @@ static const rb_data_type_t lru_shared_map_type = {
218
218
  .dsize = lru_memsize,
219
219
  .dcompact = lru_compact,
220
220
  },
221
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
221
+ .flags =
222
+ RUBY_TYPED_WB_PROTECTED |
223
+ RUBY_TYPED_FROZEN_SHAREABLE |
224
+ RUBY_TYPED_FREE_IMMEDIATELY |
225
+ FARCE_TYPED_THREAD_SAFE_FREE,
222
226
  };
223
227
 
224
228
  static VALUE
@@ -1320,8 +1324,8 @@ lru_each(VALUE self)
1320
1324
 
1321
1325
  for (long index = 0; index < length; index += 2) {
1322
1326
  rb_yield(rb_assoc_new(
1323
- RARRAY_AREF(entries, index),
1324
- RARRAY_AREF(entries, index + 1)
1327
+ rb_ary_entry(entries, index),
1328
+ rb_ary_entry(entries, index + 1)
1325
1329
  ));
1326
1330
  }
1327
1331
  RB_GC_GUARD(entries);
@@ -1338,7 +1342,7 @@ lru_each_key(VALUE self)
1338
1342
  long length = RARRAY_LEN(entries);
1339
1343
 
1340
1344
  for (long index = 0; index < length; index += 2) {
1341
- rb_yield(RARRAY_AREF(entries, index));
1345
+ rb_yield(rb_ary_entry(entries, index));
1342
1346
  }
1343
1347
  RB_GC_GUARD(entries);
1344
1348
  return self;
@@ -1354,7 +1358,7 @@ lru_each_value(VALUE self)
1354
1358
  long length = RARRAY_LEN(entries);
1355
1359
 
1356
1360
  for (long index = 1; index < length; index += 2) {
1357
- rb_yield(RARRAY_AREF(entries, index));
1361
+ rb_yield(rb_ary_entry(entries, index));
1358
1362
  }
1359
1363
  RB_GC_GUARD(entries);
1360
1364
  return self;
@@ -1370,7 +1374,7 @@ lru_keys(VALUE self)
1370
1374
  VALUE keys = rb_ary_new_capa(length / 2);
1371
1375
 
1372
1376
  for (long index = 0; index < length; index += 2) {
1373
- rb_ary_push(keys, RARRAY_AREF(entries, index));
1377
+ rb_ary_push(keys, rb_ary_entry(entries, index));
1374
1378
  }
1375
1379
  RB_GC_GUARD(entries);
1376
1380
  rb_obj_freeze(keys);
@@ -12,6 +12,21 @@
12
12
  #include <sys/time.h>
13
13
  #endif
14
14
 
15
+ /* Ruby 4.1 can sweep independently owned native payloads in parallel. */
16
+ #ifdef RUBY_TYPED_THREAD_SAFE_FREE
17
+ # define FARCE_TYPED_THREAD_SAFE_FREE RUBY_TYPED_THREAD_SAFE_FREE
18
+ #else
19
+ # define FARCE_TYPED_THREAD_SAFE_FREE 0
20
+ #endif
21
+
22
+ /* Avoid dirtying a native page when compaction left the reference in place. */
23
+ static inline void
24
+ containers_gc_update(VALUE *reference)
25
+ {
26
+ VALUE relocated = rb_gc_location(*reference);
27
+ if (relocated != *reference) *reference = relocated;
28
+ }
29
+
15
30
  /* Use only after validating self as native TypedData. */
16
31
  static inline void
17
32
  containers_check_typed_frozen(VALUE self)
data/ext/farce/counter.c CHANGED
@@ -49,29 +49,24 @@ counter_memsize(const void *pointer)
49
49
  return pointer ? sizeof(counter_t) : 0;
50
50
  }
51
51
 
52
- static void
53
- counter_mark(void *pointer)
54
- {
55
- counter_t *counter = pointer;
56
- rb_gc_mark_movable(counter->signal);
57
- }
58
-
59
- static void
60
- counter_compact(void *pointer)
61
- {
62
- counter_t *counter = pointer;
63
- counter->signal = rb_gc_location(counter->signal);
64
- }
52
+ RUBY_REFERENCES(counter_references) = {
53
+ RUBY_REF_EDGE(counter_t, signal),
54
+ RUBY_REF_END,
55
+ };
65
56
 
66
57
  static const rb_data_type_t counter_type = {
67
58
  .wrap_struct_name = "Ractor::Containers::Counter",
68
59
  .function = {
69
- .dmark = counter_mark,
70
- .dcompact = counter_compact,
60
+ .dmark = RUBY_REFS_LIST_PTR(counter_references),
71
61
  .dfree = counter_free,
72
62
  .dsize = counter_memsize,
73
63
  },
74
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
64
+ .flags =
65
+ RUBY_TYPED_DECL_MARKING |
66
+ RUBY_TYPED_WB_PROTECTED |
67
+ RUBY_TYPED_FROZEN_SHAREABLE |
68
+ RUBY_TYPED_FREE_IMMEDIATELY |
69
+ FARCE_TYPED_THREAD_SAFE_FREE,
75
70
  };
76
71
 
77
72
  static VALUE
@@ -136,7 +131,7 @@ counter_initialize(int argc, VALUE *argv, VALUE self)
136
131
  #else
137
132
  counter->value = value;
138
133
  #endif
139
- counter->signal = containers_signal_new();
134
+ RB_OBJ_WRITE(self, &counter->signal, containers_signal_new());
140
135
  counter->initial = value;
141
136
  counter->initialized = true;
142
137
  return containers_publish_native_with_references(self, counter_validate_references);
@@ -183,7 +178,7 @@ counter_initialize_copy(VALUE self, VALUE other)
183
178
  #else
184
179
  copy->value = value;
185
180
  #endif
186
- copy->signal = containers_signal_new();
181
+ RB_OBJ_WRITE(self, &copy->signal, containers_signal_new());
187
182
  copy->initial = source->initial;
188
183
  copy->initialized = true;
189
184
  return containers_publish_native_with_references(self, counter_validate_references);
@@ -147,7 +147,11 @@ static const rb_data_type_t exchanger_type = {
147
147
  .dsize = exchanger_memsize,
148
148
  .dcompact = NULL,
149
149
  },
150
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
150
+ .flags =
151
+ RUBY_TYPED_WB_PROTECTED |
152
+ RUBY_TYPED_FROZEN_SHAREABLE |
153
+ RUBY_TYPED_FREE_IMMEDIATELY |
154
+ FARCE_TYPED_THREAD_SAFE_FREE,
151
155
  };
152
156
 
153
157
  static VALUE
data/ext/farce/farce.c CHANGED
@@ -107,7 +107,7 @@ containers_normalize_string_key(VALUE key)
107
107
  long index;
108
108
 
109
109
  for (index = 0; index < RARRAY_LEN(instance_variables); index++) {
110
- ID id = SYM2ID(RARRAY_AREF(instance_variables, index));
110
+ ID id = SYM2ID(rb_ary_entry(instance_variables, index));
111
111
  rb_ivar_set(stored_key, id, rb_ivar_get(key, id));
112
112
  }
113
113
  RB_GC_GUARD(instance_variables);
data/ext/farce/flag.c CHANGED
@@ -18,6 +18,7 @@ typedef struct {
18
18
  pthread_mutex_t lock;
19
19
  bool value;
20
20
  #endif
21
+ VALUE signal;
21
22
  bool initialized;
22
23
  } flag_t;
23
24
 
@@ -42,13 +43,24 @@ flag_memsize(const void *pointer)
42
43
  return pointer ? sizeof(flag_t) : 0;
43
44
  }
44
45
 
46
+ RUBY_REFERENCES(flag_references) = {
47
+ RUBY_REF_EDGE(flag_t, signal),
48
+ RUBY_REF_END,
49
+ };
50
+
45
51
  static const rb_data_type_t flag_type = {
46
52
  .wrap_struct_name = "Ractor::Containers::Flag",
47
53
  .function = {
54
+ .dmark = RUBY_REFS_LIST_PTR(flag_references),
48
55
  .dfree = flag_free,
49
56
  .dsize = flag_memsize,
50
57
  },
51
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
58
+ .flags =
59
+ RUBY_TYPED_DECL_MARKING |
60
+ RUBY_TYPED_WB_PROTECTED |
61
+ RUBY_TYPED_FROZEN_SHAREABLE |
62
+ RUBY_TYPED_FREE_IMMEDIATELY |
63
+ FARCE_TYPED_THREAD_SAFE_FREE,
52
64
  };
53
65
 
54
66
  static VALUE
@@ -77,10 +89,23 @@ flag_allocate(VALUE klass)
77
89
  pthread_mutex_init(&flag->lock, NULL);
78
90
  flag->value = false;
79
91
  #endif
92
+ flag->signal = Qnil;
80
93
  flag->initialized = false;
81
94
  return object;
82
95
  }
83
96
 
97
+ static void
98
+ flag_validate_references(VALUE self)
99
+ {
100
+ containers_check_shareable(get_flag(self)->signal);
101
+ }
102
+
103
+ static VALUE
104
+ flag_change_signal(VALUE self)
105
+ {
106
+ return get_flag(self)->signal;
107
+ }
108
+
84
109
  static VALUE
85
110
  flag_initialize(int argc, VALUE *argv, VALUE self)
86
111
  {
@@ -99,8 +124,9 @@ flag_initialize(int argc, VALUE *argv, VALUE self)
99
124
  #else
100
125
  flag->value = value;
101
126
  #endif
127
+ RB_OBJ_WRITE(self, &flag->signal, containers_signal_new());
102
128
  flag->initialized = true;
103
- return containers_publish_native_reference_free(self);
129
+ return containers_publish_native_with_references(self, flag_validate_references);
104
130
  }
105
131
 
106
132
  static VALUE
@@ -131,8 +157,9 @@ flag_initialize_copy(VALUE self, VALUE other)
131
157
  #else
132
158
  copy->value = value;
133
159
  #endif
160
+ RB_OBJ_WRITE(self, &copy->signal, containers_signal_new());
134
161
  copy->initialized = true;
135
- return containers_publish_native_reference_free(self);
162
+ return containers_publish_native_with_references(self, flag_validate_references);
136
163
  }
137
164
 
138
165
  static VALUE
@@ -147,6 +174,7 @@ flag_set(VALUE self)
147
174
  flag->value = true;
148
175
  pthread_mutex_unlock(&flag->lock);
149
176
  #endif
177
+ containers_signal_broadcast(flag->signal);
150
178
  return Qtrue;
151
179
  }
152
180
 
@@ -162,6 +190,7 @@ flag_unset(VALUE self)
162
190
  flag->value = false;
163
191
  pthread_mutex_unlock(&flag->lock);
164
192
  #endif
193
+ containers_signal_broadcast(flag->signal);
165
194
  return Qfalse;
166
195
  }
167
196
 
@@ -178,6 +207,7 @@ flag_store(VALUE self, VALUE input)
178
207
  flag->value = value;
179
208
  pthread_mutex_unlock(&flag->lock);
180
209
  #endif
210
+ containers_signal_broadcast(flag->signal);
181
211
  return input;
182
212
  }
183
213
 
@@ -199,6 +229,7 @@ flag_swap(VALUE self, VALUE input)
199
229
  flag->value = replacement;
200
230
  pthread_mutex_unlock(&flag->lock);
201
231
  #endif
232
+ containers_signal_broadcast(flag->signal);
202
233
  return flag_boolean(previous);
203
234
  }
204
235
 
@@ -223,6 +254,7 @@ flag_compare_and_set(VALUE self, VALUE expected_input, VALUE replacement_input)
223
254
  if (exchanged) flag->value = replacement;
224
255
  pthread_mutex_unlock(&flag->lock);
225
256
  #endif
257
+ if (exchanged) containers_signal_broadcast(flag->signal);
226
258
  return flag_boolean(exchanged);
227
259
  }
228
260
 
@@ -243,6 +275,7 @@ flag_toggle(VALUE self)
243
275
  memory_order_relaxed,
244
276
  memory_order_relaxed
245
277
  )) {
278
+ containers_signal_broadcast(flag->signal);
246
279
  return flag_boolean(replacement);
247
280
  }
248
281
  }
@@ -250,6 +283,7 @@ flag_toggle(VALUE self)
250
283
  pthread_mutex_lock(&flag->lock);
251
284
  bool value = flag->value = !flag->value;
252
285
  pthread_mutex_unlock(&flag->lock);
286
+ containers_signal_broadcast(flag->signal);
253
287
  return flag_boolean(value);
254
288
  #endif
255
289
  }
@@ -261,6 +295,8 @@ containers_init_flag(VALUE namespace)
261
295
  rb_define_alloc_func(cFlag, flag_allocate);
262
296
  rb_define_method(cFlag, "initialize", flag_initialize, -1);
263
297
  rb_define_private_method(cFlag, "initialize_copy", flag_initialize_copy, 1);
298
+ rb_include_module(cFlag, rb_const_get(namespace, rb_intern("FlagWaiting")));
299
+ rb_define_method(cFlag, "change_signal", flag_change_signal, 0);
264
300
  rb_define_method(cFlag, "value", flag_value, 0);
265
301
  rb_define_alias(cFlag, "get", "value");
266
302
  rb_define_method(cFlag, "set", flag_set, 0);
data/ext/farce/io.c CHANGED
@@ -21,7 +21,7 @@ static VALUE wait_cleanup(VALUE data) {
21
21
  static VALUE wait_body(VALUE data) {
22
22
  VALUE *args = (VALUE *)data;
23
23
  fs_state *s = fs_get(args[0]); fs_wait *w = fs_lookup(s, args[1]);
24
- w->ios = args[2]; // GC root for the watched IO
24
+ RB_OBJ_WRITE(args[0], &w->ios, args[2]); // GC root for the watched IO
25
25
  fs_watch_io(s, w, rb_io_descriptor(args[2]), NUM2INT(args[3]), -1, 0);
26
26
  if (NIL_P(args[4])) return fs_suspend(args[0], args[1]);
27
27
  return rb_funcall(args[0], rb_intern("wait_with_timeout"), 3, args[1], args[4], INT2NUM(0));
@@ -82,7 +82,7 @@ static void transfer_wait(transfer *t, int events) {
82
82
  t->token = fs_arm_checked(t->self);
83
83
  fs_state *s = fs_get(t->self);
84
84
  fs_wait *w = fs_lookup(s, t->token);
85
- w->ios = t->io;
85
+ RB_OBJ_WRITE(t->self, &w->ios, t->io);
86
86
  fs_watch_io(s, w, rb_io_descriptor(t->io), events, -1, 0);
87
87
  fs_suspend(t->self, t->token);
88
88
  fs_retire(t->self, t->token);
@@ -95,7 +95,7 @@ static ssize_t transfer_receive(transfer *t, void *buffer, size_t capacity) {
95
95
  t->token = fs_arm_checked(t->self);
96
96
  fs_state *s = fs_get(t->self);
97
97
  fs_wait *w = fs_lookup(s, t->token);
98
- w->ios = t->io;
98
+ RB_OBJ_WRITE(t->self, &w->ios, t->io);
99
99
  int error = fs_driver_receive(s, w, rb_io_descriptor(t->io), buffer, capacity);
100
100
  if (error) rb_syserr_fail(error, "scheduler receive submission");
101
101
  VALUE result = fs_suspend(t->self, t->token);
data/ext/farce/lock.c CHANGED
@@ -83,22 +83,6 @@ containers_lock_notify_one_locked(containers_lock_t *lock)
83
83
  }
84
84
  }
85
85
 
86
- static void
87
- containers_lock_mark(void *pointer)
88
- {
89
- containers_lock_t *lock = pointer;
90
- rb_gc_mark_movable(lock->owner);
91
- rb_gc_mark_movable(lock->owner_thread);
92
- }
93
-
94
- static void
95
- containers_lock_compact(void *pointer)
96
- {
97
- containers_lock_t *lock = pointer;
98
- lock->owner = rb_gc_location(lock->owner);
99
- lock->owner_thread = rb_gc_location(lock->owner_thread);
100
- }
101
-
102
86
  static void
103
87
  containers_lock_free(void *pointer)
104
88
  {
@@ -113,15 +97,25 @@ containers_lock_memsize(const void *pointer)
113
97
  return pointer ? sizeof(containers_lock_t) : 0;
114
98
  }
115
99
 
100
+ RUBY_REFERENCES(containers_lock_references) = {
101
+ RUBY_REF_EDGE(containers_lock_t, owner),
102
+ RUBY_REF_EDGE(containers_lock_t, owner_thread),
103
+ RUBY_REF_END,
104
+ };
105
+
116
106
  static const rb_data_type_t containers_lock_type = {
117
107
  .wrap_struct_name = "Ractor::Containers::Lock",
118
108
  .function = {
119
- .dmark = containers_lock_mark,
109
+ .dmark = RUBY_REFS_LIST_PTR(containers_lock_references),
120
110
  .dfree = containers_lock_free,
121
111
  .dsize = containers_lock_memsize,
122
- .dcompact = containers_lock_compact,
123
112
  },
124
- .flags = RUBY_TYPED_FROZEN_SHAREABLE,
113
+ .flags =
114
+ RUBY_TYPED_DECL_MARKING |
115
+ RUBY_TYPED_WB_PROTECTED |
116
+ RUBY_TYPED_FROZEN_SHAREABLE |
117
+ RUBY_TYPED_FREE_IMMEDIATELY |
118
+ FARCE_TYPED_THREAD_SAFE_FREE,
125
119
  };
126
120
 
127
121
  static VALUE
@@ -285,8 +279,8 @@ containers_lock_acquire(VALUE self)
285
279
  rb_raise(rb_eThreadError, "deadlock; recursive locking");
286
280
  }
287
281
  if (NIL_P(lock->owner)) {
288
- lock->owner = current;
289
- lock->owner_thread = current_thread;
282
+ RB_OBJ_WRITE(self, &lock->owner, current);
283
+ RB_OBJ_WRITE(self, &lock->owner_thread, current_thread);
290
284
  pthread_mutex_unlock(&lock->guard);
291
285
  return;
292
286
  }
@@ -338,8 +332,8 @@ containers_lock_try_lock(VALUE self)
338
332
 
339
333
  pthread_mutex_lock(&lock->guard);
340
334
  if (NIL_P(lock->owner)) {
341
- lock->owner = current;
342
- lock->owner_thread = rb_thread_current();
335
+ RB_OBJ_WRITE(self, &lock->owner, current);
336
+ RB_OBJ_WRITE(self, &lock->owner_thread, rb_thread_current());
343
337
  acquired = true;
344
338
  }
345
339
  pthread_mutex_unlock(&lock->guard);