farce 0.1.0-aarch64-linux-gnu → 0.2.0-aarch64-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -1
- data/README.md +72 -16
- data/docs/gems/dry-types.md +8 -8
- data/docs/modes.md +67 -10
- data/ext/farce/atom.c +37 -22
- data/ext/farce/bounded_map.c +17 -13
- data/ext/farce/containers.h +15 -0
- data/ext/farce/counter.c +13 -18
- data/ext/farce/exchanger.c +5 -1
- data/ext/farce/farce.c +1 -1
- data/ext/farce/flag.c +39 -3
- data/ext/farce/io.c +3 -3
- data/ext/farce/lock.c +17 -23
- data/ext/farce/map.c +88 -66
- data/ext/farce/priority_queue.c +55 -43
- data/ext/farce/queue.c +10 -4
- data/ext/farce/reactor.c +52 -25
- data/ext/farce/reactor.h +1 -1
- data/ext/farce/signal.c +5 -1
- data/ext/farce/transaction.c +20 -24
- data/ext/farce/tree_map.c +33 -18
- data/ext/farce/trie.c +81 -43
- data/ext/farce/unshareable.c +168 -19
- data/ext/farce/unshared_io_pool.h +21 -12
- data/ext/farce/unshared_signal.c +13 -2
- data/ext/farce/unshared_wait.h +3 -0
- data/ext/farce/vector.c +82 -18
- data/ext/farce/weak_map.c +75 -63
- data/lib/farce/_yard/macros.rb +18 -3
- data/lib/farce/abstract/flag.rb +73 -0
- data/lib/farce/abstract/queue.rb +4 -3
- data/lib/farce/abstract/scheduler.rb +3 -3
- data/lib/farce/abstract/set.rb +17 -5
- data/lib/farce/abstract/sorted_set.rb +2 -2
- data/lib/farce/abstract/timer_queue.rb +49 -10
- data/lib/farce/abstract/vector.rb +510 -28
- data/lib/farce/atom.rb +1 -1
- data/lib/farce/class_mirror.rb +20 -7
- data/lib/farce/config.rb +7 -1
- data/lib/farce/engine/jvm/flag.rb +15 -3
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/unshared_vector.rb +31 -4
- data/lib/farce/engine/shared/vector.rb +8 -0
- data/lib/farce/engine/shared/weak_map/index.rb +14 -1
- data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
- data/lib/farce/envelope.rb +54 -7
- data/lib/farce/exchanger.rb +1 -1
- data/lib/farce/flag.rb +2 -0
- data/lib/farce/integrations/active_support.rb +1 -1
- data/lib/farce/integrations/bson.rb +1 -1
- data/lib/farce/integrations/cbor.rb +1 -1
- data/lib/farce/integrations/concurrent.rb +3 -3
- data/lib/farce/integrations/date.rb +8 -0
- data/lib/farce/integrations/dry_types.rb +7 -4
- data/lib/farce/integrations/json.rb +2 -2
- data/lib/farce/integrations/msgpack.rb +1 -1
- data/lib/farce/integrations/oj.rb +3 -4
- data/lib/farce/integrations/psych.rb +1 -1
- data/lib/farce/integrations/ractor_sharing.rb +1 -1
- data/lib/farce/integrations/sorted_set.rb +1 -1
- data/lib/farce/integrations/weakref.rb +9 -1
- data/lib/farce/integrations/yajl.rb +3 -3
- data/lib/farce/integrations.rb +33 -23
- data/lib/farce/internal/flag_waiting.rb +30 -0
- data/lib/farce/internal/freeze.rb +8 -3
- data/lib/farce/internal/map_value_modes.rb +1 -1
- data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
- data/lib/farce/lazy.rb +4 -4
- data/lib/farce/lazy_ref.rb +3 -3
- data/lib/farce/lfu_map.rb +1 -1
- data/lib/farce/local/flag.rb +4 -0
- data/lib/farce/local/scoped.rb +1 -1
- data/lib/farce/lru_map.rb +1 -1
- data/lib/farce/map.rb +2 -2
- data/lib/farce/mode_manager/smart_rule.rb +138 -0
- data/lib/farce/mode_manager.rb +12 -3
- data/lib/farce/molecule.rb +2 -2
- data/lib/farce/pool.rb +1 -1
- data/lib/farce/port.rb +4 -4
- data/lib/farce/priority_queue.rb +1 -1
- data/lib/farce/proxy/register.rb +6 -0
- data/lib/farce/proxy/supervisor.rb +1 -1
- data/lib/farce/proxy.rb +7 -2
- data/lib/farce/queue.rb +1 -1
- data/lib/farce/scheduler.rb +2 -2
- data/lib/farce/set.rb +1 -1
- data/lib/farce/sorted_set.rb +1 -1
- data/lib/farce/timer_queue.rb +20 -6
- data/lib/farce/transaction/vector.rb +43 -9
- data/lib/farce/transaction/wrapper.rb +14 -0
- data/lib/farce/tree_map.rb +1 -1
- data/lib/farce/unsafe/lfu_map.rb +2 -0
- data/lib/farce/unsafe/lru_map.rb +2 -0
- data/lib/farce/unsafe/tree_map.rb +2 -0
- data/lib/farce/unshareable.rb +8 -19
- data/lib/farce/unshared/atom.rb +3 -0
- data/lib/farce/unshared/lfu_map.rb +2 -0
- data/lib/farce/unshared/lru_map.rb +2 -0
- data/lib/farce/unshared/map.rb +3 -0
- data/lib/farce/unshared/set.rb +1 -0
- data/lib/farce/unshared/sorted_set.rb +1 -0
- data/lib/farce/unshared/tree_map.rb +5 -1
- data/lib/farce/unshared/vector.rb +3 -0
- data/lib/farce/unshared/weak_atom.rb +5 -1
- data/lib/farce/unshared/weak_key_map.rb +3 -0
- data/lib/farce/unshared/weak_map.rb +3 -0
- data/lib/farce/unshared/weak_set.rb +1 -0
- data/lib/farce/unshared/weak_value_map.rb +3 -0
- data/lib/farce/vector.rb +44 -19
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +11 -8
- 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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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 =
|
|
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
|
|
303
|
-
atom->updating_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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
945
|
-
atom->updating_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
|
data/ext/farce/bounded_map.c
CHANGED
|
@@ -153,17 +153,17 @@ lru_compact(void *opaque)
|
|
|
153
153
|
lru_map_t *map = opaque;
|
|
154
154
|
if (map == NULL) return;
|
|
155
155
|
|
|
156
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
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
|
-
|
|
175
|
-
|
|
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 =
|
|
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
|
-
|
|
1324
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
1377
|
+
rb_ary_push(keys, rb_ary_entry(entries, index));
|
|
1374
1378
|
}
|
|
1375
1379
|
RB_GC_GUARD(entries);
|
|
1376
1380
|
rb_obj_freeze(keys);
|
data/ext/farce/containers.h
CHANGED
|
@@ -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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
181
|
+
RB_OBJ_WRITE(self, ©->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);
|
data/ext/farce/exchanger.c
CHANGED
|
@@ -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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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, ©->signal, containers_signal_new());
|
|
134
161
|
copy->initialized = true;
|
|
135
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
289
|
-
lock->owner_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
|
|
342
|
-
lock->owner_thread
|
|
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);
|