farce 0.0.1.alpha2-x86_64-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 +7 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1524 -0
- data/SECURITY.md +10 -0
- data/docs/benchmarks.md +185 -0
- data/docs/gems/dry-types.md +290 -0
- data/docs/gems/msgpack.md +70 -0
- data/docs/gems/ractor-shim.md +63 -0
- data/docs/modes.md +628 -0
- data/docs/scopes.md +649 -0
- data/docs/variants.md +346 -0
- data/ext/ext_helper.rb +20 -0
- data/ext/farce/README.md +21 -0
- data/ext/farce/atom.c +1023 -0
- data/ext/farce/bounded_map.c +1683 -0
- data/ext/farce/containers.h +77 -0
- data/ext/farce/counter.c +399 -0
- data/ext/farce/darwin.c +100 -0
- data/ext/farce/depend +12 -0
- data/ext/farce/dict.c +1523 -0
- data/ext/farce/dict.h +152 -0
- data/ext/farce/drivers.c +237 -0
- data/ext/farce/exchanger.c +299 -0
- data/ext/farce/extconf.rb +99 -0
- data/ext/farce/farce.c +359 -0
- data/ext/farce/flag.c +288 -0
- data/ext/farce/io.c +338 -0
- data/ext/farce/lock.c +510 -0
- data/ext/farce/map.c +2240 -0
- data/ext/farce/priority_queue.c +2056 -0
- data/ext/farce/queue.c +1059 -0
- data/ext/farce/reactor.c +820 -0
- data/ext/farce/reactor.h +103 -0
- data/ext/farce/shareable.h +31 -0
- data/ext/farce/signal.c +350 -0
- data/ext/farce/transaction.c +354 -0
- data/ext/farce/transaction.h +40 -0
- data/ext/farce/tree_map.c +1953 -0
- data/ext/farce/trie.c +2020 -0
- data/ext/farce/unshareable.c +155 -0
- data/ext/farce/unshared_io_pool.h +234 -0
- data/ext/farce/unshared_signal.c +263 -0
- data/ext/farce/unshared_wait.h +193 -0
- data/ext/farce/unsupported.c +6 -0
- data/ext/farce/vector.c +1195 -0
- data/ext/farce/weak_map.c +1714 -0
- data/ext/java/org/farce/BoundedMap.java +394 -0
- data/ext/java/org/farce/FiberScheduler.java +141 -0
- data/ext/java/org/farce/PriorityKey.java +45 -0
- data/ext/java/org/farce/PriorityQueue.java +373 -0
- data/ext/java/org/farce/QueueSignal.java +28 -0
- data/ext/rebind/README.md +14 -0
- data/ext/rebind/extconf.rb +10 -0
- data/ext/rebind/rebind.c +186 -0
- data/lib/farce/_yard/internal.rb +13 -0
- data/lib/farce/_yard/macros.rb +61 -0
- data/lib/farce/_yard/ractor.rb +46 -0
- data/lib/farce/abstract/atom.rb +186 -0
- data/lib/farce/abstract/bounded_map.rb +232 -0
- data/lib/farce/abstract/collection.rb +151 -0
- data/lib/farce/abstract/concurrent_map.rb +381 -0
- data/lib/farce/abstract/counter.rb +193 -0
- data/lib/farce/abstract/duplicable_map.rb +229 -0
- data/lib/farce/abstract/exchanger.rb +26 -0
- data/lib/farce/abstract/flag.rb +71 -0
- data/lib/farce/abstract/lazy.rb +115 -0
- data/lib/farce/abstract/lease.rb +104 -0
- data/lib/farce/abstract/lease_map.rb +261 -0
- data/lib/farce/abstract/lease_pool.rb +91 -0
- data/lib/farce/abstract/lfu_map.rb +20 -0
- data/lib/farce/abstract/lru_map.rb +25 -0
- data/lib/farce/abstract/map.rb +345 -0
- data/lib/farce/abstract/molecule.rb +245 -0
- data/lib/farce/abstract/port.rb +74 -0
- data/lib/farce/abstract/priority_queue.rb +117 -0
- data/lib/farce/abstract/queue.rb +269 -0
- data/lib/farce/abstract/scheduler.rb +111 -0
- data/lib/farce/abstract/set.rb +910 -0
- data/lib/farce/abstract/sorted_set.rb +172 -0
- data/lib/farce/abstract/timer_queue.rb +136 -0
- data/lib/farce/abstract/tree_map.rb +269 -0
- data/lib/farce/abstract/value.rb +68 -0
- data/lib/farce/abstract/vector.rb +1126 -0
- data/lib/farce/abstract/weak_atom.rb +32 -0
- data/lib/farce/abstract/weak_key_map.rb +12 -0
- data/lib/farce/abstract/weak_map.rb +13 -0
- data/lib/farce/abstract/weak_set.rb +12 -0
- data/lib/farce/abstract/weak_value_map.rb +12 -0
- data/lib/farce/abstract.rb +17 -0
- data/lib/farce/atom.rb +293 -0
- data/lib/farce/class_mirror.rb +87 -0
- data/lib/farce/clock.rb +121 -0
- data/lib/farce/config.rb +229 -0
- data/lib/farce/counter.rb +71 -0
- data/lib/farce/deduper.rb +122 -0
- data/lib/farce/engine/jruby/bounded_map.rb +314 -0
- data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
- data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
- data/lib/farce/engine/jruby/map.rb +505 -0
- data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
- data/lib/farce/engine/jruby/signal.rb +147 -0
- data/lib/farce/engine/jruby.rb +63 -0
- data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
- data/lib/farce/engine/jvm/counter.rb +102 -0
- data/lib/farce/engine/jvm/extension.rb +32 -0
- data/lib/farce/engine/jvm/farce.jar +0 -0
- data/lib/farce/engine/jvm/flag.rb +79 -0
- data/lib/farce/engine/jvm/priority_queue.rb +217 -0
- data/lib/farce/engine/jvm/tree_map.rb +350 -0
- data/lib/farce/engine/jvm/types.rb +180 -0
- data/lib/farce/engine/jvm.rb +19 -0
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
- data/lib/farce/engine/ruby/3.4/port.rb +186 -0
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
- data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
- data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/port.rb +19 -0
- data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
- data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
- data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
- data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
- data/lib/farce/engine/ruby/4.1/port.rb +21 -0
- data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
- data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
- data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
- data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
- data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
- data/lib/farce/engine/ruby/shared/lease.rb +26 -0
- data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
- data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
- data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
- data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
- data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
- data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
- data/lib/farce/engine/ruby/shared/vault.rb +144 -0
- data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
- data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
- data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
- data/lib/farce/engine/ruby.rb +130 -0
- data/lib/farce/engine/shared/atom.rb +10 -0
- data/lib/farce/engine/shared/exchanger.rb +130 -0
- data/lib/farce/engine/shared/identity_key.rb +22 -0
- data/lib/farce/engine/shared/lease.rb +10 -0
- data/lib/farce/engine/shared/lease_pool.rb +10 -0
- data/lib/farce/engine/shared/main_scheduler.rb +20 -0
- data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
- data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/shared/port.rb +44 -0
- data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
- data/lib/farce/engine/shared/proxy_owner.rb +43 -0
- data/lib/farce/engine/shared/queue.rb +233 -0
- data/lib/farce/engine/shared/ractor_methods.rb +73 -0
- data/lib/farce/engine/shared/rebindable.rb +15 -0
- data/lib/farce/engine/shared/strict_atom.rb +73 -0
- data/lib/farce/engine/shared/strict_map.rb +117 -0
- data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
- data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
- data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
- data/lib/farce/engine/shared/trie.rb +317 -0
- data/lib/farce/engine/shared/trie_builder.rb +199 -0
- data/lib/farce/engine/shared/unshareable.rb +14 -0
- data/lib/farce/engine/shared/unshared_atom.rb +256 -0
- data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
- data/lib/farce/engine/shared/unshared_queue.rb +18 -0
- data/lib/farce/engine/shared/unshared_signal.rb +21 -0
- data/lib/farce/engine/shared/unshared_vector.rb +377 -0
- data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
- data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
- data/lib/farce/engine/shared/vault.rb +31 -0
- data/lib/farce/engine/shared/vector.rb +83 -0
- data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
- data/lib/farce/engine/shared/weak_atom.rb +20 -0
- data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
- data/lib/farce/engine/shared/weak_map/index.rb +249 -0
- data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
- data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
- data/lib/farce/engine/shared.rb +63 -0
- data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
- data/lib/farce/engine/truffleruby/lock.rb +121 -0
- data/lib/farce/engine/truffleruby/map.rb +656 -0
- data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
- data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
- data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
- data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
- data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
- data/lib/farce/engine/truffleruby/signal.rb +77 -0
- data/lib/farce/engine/truffleruby.rb +148 -0
- data/lib/farce/envelope.rb +335 -0
- data/lib/farce/error.rb +35 -0
- data/lib/farce/exchanger.rb +41 -0
- data/lib/farce/flag.rb +27 -0
- data/lib/farce/integrations/active_support/blank.rb +68 -0
- data/lib/farce/integrations/active_support/clock.rb +17 -0
- data/lib/farce/integrations/active_support/duplicable.rb +78 -0
- data/lib/farce/integrations/active_support/map.rb +175 -0
- data/lib/farce/integrations/active_support/set.rb +60 -0
- data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
- data/lib/farce/integrations/active_support/vector.rb +231 -0
- data/lib/farce/integrations/active_support.rb +9 -0
- data/lib/farce/integrations/activesupport.rb +5 -0
- data/lib/farce/integrations/bson.rb +108 -0
- data/lib/farce/integrations/cbor.rb +51 -0
- data/lib/farce/integrations/concurrent.rb +112 -0
- data/lib/farce/integrations/dry-types.rb +5 -0
- data/lib/farce/integrations/dry_types.rb +694 -0
- data/lib/farce/integrations/json.rb +7 -0
- data/lib/farce/integrations/msgpack.rb +112 -0
- data/lib/farce/integrations/oj.rb +69 -0
- data/lib/farce/integrations/psych.rb +191 -0
- data/lib/farce/integrations/ractor-sharing.rb +5 -0
- data/lib/farce/integrations/ractor-tmvar.rb +5 -0
- data/lib/farce/integrations/ractor_sharing.rb +172 -0
- data/lib/farce/integrations/ractor_tmvar.rb +64 -0
- data/lib/farce/integrations/shared/to_json.rb +42 -0
- data/lib/farce/integrations/sorted_set.rb +11 -0
- data/lib/farce/integrations/weakref.rb +38 -0
- data/lib/farce/integrations/yajl.rb +10 -0
- data/lib/farce/integrations.rb +156 -0
- data/lib/farce/internal/_frozen_config.rb +11 -0
- data/lib/farce/internal/autoloads.rb +47 -0
- data/lib/farce/internal/blocking_priority_queue.rb +122 -0
- data/lib/farce/internal/converter.rb +106 -0
- data/lib/farce/internal/copyable.rb +31 -0
- data/lib/farce/internal/delegation.rb +20 -0
- data/lib/farce/internal/external_transaction.rb +59 -0
- data/lib/farce/internal/fake_ractor.rb +179 -0
- data/lib/farce/internal/freeze.rb +118 -0
- data/lib/farce/internal/inspect.rb +157 -0
- data/lib/farce/internal/key_lock_map.rb +29 -0
- data/lib/farce/internal/key_normalizer.rb +289 -0
- data/lib/farce/internal/lease_initialization.rb +115 -0
- data/lib/farce/internal/lease_map.rb +441 -0
- data/lib/farce/internal/lease_pool_state.rb +228 -0
- data/lib/farce/internal/lease_state.rb +342 -0
- data/lib/farce/internal/lease_waiting.rb +13 -0
- data/lib/farce/internal/managed_queue.rb +26 -0
- data/lib/farce/internal/map_value_modes.rb +227 -0
- data/lib/farce/internal/marshal_support.rb +227 -0
- data/lib/farce/internal/mixin.rb +20 -0
- data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
- data/lib/farce/internal/noncopyable.rb +17 -0
- data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
- data/lib/farce/internal/pool_supervisor.rb +41 -0
- data/lib/farce/internal/pool_worker.rb +61 -0
- data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
- data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
- data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
- data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
- data/lib/farce/internal/portable_transaction.rb +164 -0
- data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
- data/lib/farce/internal/reservation_waiting.rb +24 -0
- data/lib/farce/internal/scheduled_task.rb +48 -0
- data/lib/farce/internal/scheduler_io.rb +171 -0
- data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
- data/lib/farce/internal/select_scheduler.rb +235 -0
- data/lib/farce/internal/storage.rb +162 -0
- data/lib/farce/internal/strict_lease.rb +30 -0
- data/lib/farce/internal/strict_lease_map.rb +20 -0
- data/lib/farce/internal/strict_lease_pool.rb +29 -0
- data/lib/farce/internal/thread_pool.rb +166 -0
- data/lib/farce/internal/transaction_conflict.rb +9 -0
- data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
- data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
- data/lib/farce/internal/undefined.rb +22 -0
- data/lib/farce/internal/unshared_lease.rb +29 -0
- data/lib/farce/internal/unshared_lease_pool.rb +34 -0
- data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
- data/lib/farce/internal/value_serialization.rb +13 -0
- data/lib/farce/internal/weak_map_value_modes.rb +58 -0
- data/lib/farce/internal/weak_mode_manager.rb +26 -0
- data/lib/farce/internal.rb +129 -0
- data/lib/farce/lazy.rb +100 -0
- data/lib/farce/lazy_ref.rb +40 -0
- data/lib/farce/lease.rb +28 -0
- data/lib/farce/lease_map.rb +34 -0
- data/lib/farce/lease_pool.rb +29 -0
- data/lib/farce/lfu_map.rb +53 -0
- data/lib/farce/local/atom.rb +23 -0
- data/lib/farce/local/counter.rb +88 -0
- data/lib/farce/local/flag.rb +65 -0
- data/lib/farce/local/lazy.rb +38 -0
- data/lib/farce/local/lazy_ref.rb +36 -0
- data/lib/farce/local/lease.rb +77 -0
- data/lib/farce/local/lease_map.rb +80 -0
- data/lib/farce/local/lease_pool.rb +38 -0
- data/lib/farce/local/lfu_map.rb +55 -0
- data/lib/farce/local/lru_map.rb +62 -0
- data/lib/farce/local/map.rb +47 -0
- data/lib/farce/local/molecule.rb +45 -0
- data/lib/farce/local/priority_queue.rb +53 -0
- data/lib/farce/local/queue.rb +32 -0
- data/lib/farce/local/scoped.rb +166 -0
- data/lib/farce/local/set.rb +18 -0
- data/lib/farce/local/sorted_set.rb +50 -0
- data/lib/farce/local/timer_queue.rb +41 -0
- data/lib/farce/local/tree_map.rb +47 -0
- data/lib/farce/local/vector.rb +30 -0
- data/lib/farce/local/weak_atom.rb +23 -0
- data/lib/farce/local/weak_key_map.rb +39 -0
- data/lib/farce/local/weak_map.rb +39 -0
- data/lib/farce/local/weak_set.rb +18 -0
- data/lib/farce/local/weak_value_map.rb +39 -0
- data/lib/farce/local.rb +35 -0
- data/lib/farce/lock.rb +54 -0
- data/lib/farce/lru_map.rb +63 -0
- data/lib/farce/map.rb +58 -0
- data/lib/farce/mode_manager.rb +142 -0
- data/lib/farce/molecule.rb +60 -0
- data/lib/farce/mutable.rb +171 -0
- data/lib/farce/pool.rb +332 -0
- data/lib/farce/port.rb +134 -0
- data/lib/farce/priority_queue.rb +70 -0
- data/lib/farce/proxy/register.rb +101 -0
- data/lib/farce/proxy/supervisor.rb +137 -0
- data/lib/farce/proxy/wrapper.rb +49 -0
- data/lib/farce/proxy.rb +291 -0
- data/lib/farce/queue.rb +60 -0
- data/lib/farce/ractor.rb +269 -0
- data/lib/farce/read_write_lock.rb +256 -0
- data/lib/farce/reference.rb +158 -0
- data/lib/farce/resolv/dns.rb +42 -0
- data/lib/farce/resolv.rb +85 -0
- data/lib/farce/scheduler.rb +536 -0
- data/lib/farce/set.rb +39 -0
- data/lib/farce/shareable.rb +150 -0
- data/lib/farce/signal.rb +97 -0
- data/lib/farce/sorted_set.rb +36 -0
- data/lib/farce/strict/atom.rb +34 -0
- data/lib/farce/strict/counter.rb +10 -0
- data/lib/farce/strict/exchanger.rb +25 -0
- data/lib/farce/strict/flag.rb +10 -0
- data/lib/farce/strict/lazy.rb +26 -0
- data/lib/farce/strict/lazy_ref.rb +26 -0
- data/lib/farce/strict/lease.rb +27 -0
- data/lib/farce/strict/lease_map.rb +33 -0
- data/lib/farce/strict/lease_pool.rb +28 -0
- data/lib/farce/strict/lfu_map.rb +27 -0
- data/lib/farce/strict/lru_map.rb +28 -0
- data/lib/farce/strict/map.rb +54 -0
- data/lib/farce/strict/molecule.rb +16 -0
- data/lib/farce/strict/port.rb +40 -0
- data/lib/farce/strict/priority_queue.rb +20 -0
- data/lib/farce/strict/queue.rb +17 -0
- data/lib/farce/strict/set.rb +14 -0
- data/lib/farce/strict/sorted_set.rb +19 -0
- data/lib/farce/strict/timer_queue.rb +13 -0
- data/lib/farce/strict/tree_map.rb +27 -0
- data/lib/farce/strict/vector.rb +24 -0
- data/lib/farce/strict/weak_atom.rb +31 -0
- data/lib/farce/strict/weak_key_map.rb +49 -0
- data/lib/farce/strict/weak_map.rb +49 -0
- data/lib/farce/strict/weak_set.rb +14 -0
- data/lib/farce/strict/weak_value_map.rb +48 -0
- data/lib/farce/strict.rb +28 -0
- data/lib/farce/system.rb +40 -0
- data/lib/farce/thread_scheduler.rb +70 -0
- data/lib/farce/timer_queue.rb +66 -0
- data/lib/farce/transaction/atom.rb +73 -0
- data/lib/farce/transaction/map.rb +25 -0
- data/lib/farce/transaction/map_operations.rb +143 -0
- data/lib/farce/transaction/molecule.rb +90 -0
- data/lib/farce/transaction/mutable.rb +61 -0
- data/lib/farce/transaction/set.rb +17 -0
- data/lib/farce/transaction/set_operations.rb +48 -0
- data/lib/farce/transaction/sorted_set.rb +18 -0
- data/lib/farce/transaction/tree_map.rb +78 -0
- data/lib/farce/transaction/vector.rb +139 -0
- data/lib/farce/transaction/wrapper.rb +202 -0
- data/lib/farce/transaction.rb +343 -0
- data/lib/farce/tree_map.rb +56 -0
- data/lib/farce/unsafe/lfu_map.rb +36 -0
- data/lib/farce/unsafe/lru_map.rb +36 -0
- data/lib/farce/unsafe/tree_map.rb +21 -0
- data/lib/farce/unsafe.rb +29 -0
- data/lib/farce/unshareable.rb +67 -0
- data/lib/farce/unshared/atom.rb +24 -0
- data/lib/farce/unshared/counter.rb +10 -0
- data/lib/farce/unshared/flag.rb +10 -0
- data/lib/farce/unshared/lazy.rb +38 -0
- data/lib/farce/unshared/lazy_ref.rb +26 -0
- data/lib/farce/unshared/lease.rb +27 -0
- data/lib/farce/unshared/lease_map.rb +26 -0
- data/lib/farce/unshared/lease_pool.rb +25 -0
- data/lib/farce/unshared/lfu_map.rb +20 -0
- data/lib/farce/unshared/lru_map.rb +20 -0
- data/lib/farce/unshared/map.rb +49 -0
- data/lib/farce/unshared/molecule.rb +16 -0
- data/lib/farce/unshared/priority_queue.rb +16 -0
- data/lib/farce/unshared/queue.rb +27 -0
- data/lib/farce/unshared/set.rb +14 -0
- data/lib/farce/unshared/sorted_set.rb +28 -0
- data/lib/farce/unshared/timer_queue.rb +16 -0
- data/lib/farce/unshared/tree_map.rb +21 -0
- data/lib/farce/unshared/vector.rb +19 -0
- data/lib/farce/unshared/weak_atom.rb +31 -0
- data/lib/farce/unshared/weak_key_map.rb +44 -0
- data/lib/farce/unshared/weak_map.rb +44 -0
- data/lib/farce/unshared/weak_set.rb +14 -0
- data/lib/farce/unshared/weak_value_map.rb +43 -0
- data/lib/farce/unshared.rb +28 -0
- data/lib/farce/vector.rb +228 -0
- data/lib/farce/version.rb +8 -0
- data/lib/farce/walker/definitions.rb +186 -0
- data/lib/farce/walker/modification.rb +355 -0
- data/lib/farce/walker.rb +319 -0
- data/lib/farce/weak_atom.rb +121 -0
- data/lib/farce/weak_key_map.rb +31 -0
- data/lib/farce/weak_map.rb +33 -0
- data/lib/farce/weak_ref.rb +67 -0
- data/lib/farce/weak_set.rb +82 -0
- data/lib/farce/weak_value.rb +195 -0
- data/lib/farce/weak_value_map.rb +32 -0
- data/lib/farce.rb +519 -0
- metadata +468 -0
data/ext/farce/dict.h
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Dictionary Abstract Data Type
|
|
3
|
+
* Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
|
|
4
|
+
*
|
|
5
|
+
* Free Software License:
|
|
6
|
+
*
|
|
7
|
+
* All rights are reserved by the author, with the following exceptions:
|
|
8
|
+
* Permission is granted to freely reproduce and distribute this software,
|
|
9
|
+
* possibly in exchange for a fee, provided that this copyright notice appears
|
|
10
|
+
* intact. Permission is also granted to adapt this software to produce
|
|
11
|
+
* derivative works, as long as the modified versions carry this copyright
|
|
12
|
+
* notice and additional notices stating that the work has been modified.
|
|
13
|
+
* This source code may be translated into executable form and incorporated
|
|
14
|
+
* into proprietary software; there is no requirement for such software to
|
|
15
|
+
* contain a copyright notice related to this source.
|
|
16
|
+
*
|
|
17
|
+
* $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $
|
|
18
|
+
* $Name: kazlib_1_20 $
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Modified for Ruby/RBTree.
|
|
23
|
+
* Modified by Farce to expose reusable unique-key insertion positions.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
#ifndef DICT_H
|
|
27
|
+
#define DICT_H
|
|
28
|
+
|
|
29
|
+
#include <limits.h>
|
|
30
|
+
#ifdef KAZLIB_SIDEEFFECT_DEBUG
|
|
31
|
+
#include "sfx.h"
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Blurb for inclusion into C++ translation units
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
#ifdef __cplusplus
|
|
39
|
+
extern "C" {
|
|
40
|
+
#endif
|
|
41
|
+
|
|
42
|
+
typedef unsigned long dictcount_t;
|
|
43
|
+
#define DICTCOUNT_T_MAX ULONG_MAX
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* The dictionary is implemented as a red-black tree
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
typedef enum { dnode_red, dnode_black } dnode_color_t;
|
|
50
|
+
|
|
51
|
+
typedef struct dnode_t {
|
|
52
|
+
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
|
|
53
|
+
struct dnode_t *dict_left;
|
|
54
|
+
struct dnode_t *dict_right;
|
|
55
|
+
struct dnode_t *dict_parent;
|
|
56
|
+
dnode_color_t dict_color;
|
|
57
|
+
const void *dict_key;
|
|
58
|
+
void *dict_data;
|
|
59
|
+
#else
|
|
60
|
+
int dict_dummy;
|
|
61
|
+
#endif
|
|
62
|
+
} dnode_t;
|
|
63
|
+
|
|
64
|
+
typedef int (*dict_comp_t)(const void *, const void *, void *);
|
|
65
|
+
typedef dnode_t *(*dnode_alloc_t)(void *);
|
|
66
|
+
typedef void (*dnode_free_t)(dnode_t *, void *);
|
|
67
|
+
|
|
68
|
+
typedef struct dict_t {
|
|
69
|
+
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
|
|
70
|
+
dnode_t dict_nilnode;
|
|
71
|
+
dictcount_t dict_nodecount;
|
|
72
|
+
dict_comp_t dict_compare;
|
|
73
|
+
dnode_alloc_t dict_allocnode;
|
|
74
|
+
dnode_free_t dict_freenode;
|
|
75
|
+
void *dict_context;
|
|
76
|
+
int dict_dupes;
|
|
77
|
+
#else
|
|
78
|
+
int dict_dummmy;
|
|
79
|
+
#endif
|
|
80
|
+
} dict_t;
|
|
81
|
+
|
|
82
|
+
typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
|
|
83
|
+
|
|
84
|
+
typedef struct dict_load_t {
|
|
85
|
+
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
|
|
86
|
+
dict_t *dict_dictptr;
|
|
87
|
+
dnode_t dict_nilnode;
|
|
88
|
+
#else
|
|
89
|
+
int dict_dummmy;
|
|
90
|
+
#endif
|
|
91
|
+
} dict_load_t;
|
|
92
|
+
|
|
93
|
+
extern dict_t *dict_create(dict_comp_t);
|
|
94
|
+
extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
|
|
95
|
+
extern void dict_destroy(dict_t *);
|
|
96
|
+
extern void dict_free_nodes(dict_t *);
|
|
97
|
+
extern void dict_free(dict_t *);
|
|
98
|
+
extern dict_t *dict_init(dict_t *, dict_comp_t);
|
|
99
|
+
extern void dict_init_like(dict_t *, const dict_t *);
|
|
100
|
+
extern int dict_verify(dict_t *);
|
|
101
|
+
extern int dict_similar(const dict_t *, const dict_t *);
|
|
102
|
+
extern dnode_t *dict_lookup(dict_t *, const void *);
|
|
103
|
+
extern dnode_t *dict_lower_bound(dict_t *, const void *);
|
|
104
|
+
extern dnode_t *dict_upper_bound(dict_t *, const void *);
|
|
105
|
+
extern int dict_insert(dict_t *, dnode_t *, const void *);
|
|
106
|
+
/* Farce extension: find a unique key or retain its insertion position. The
|
|
107
|
+
* caller must keep the tree and key ordering unchanged until insert_at. */
|
|
108
|
+
extern dnode_t *dict_lookup_position(dict_t *, const void *, dnode_t **, int *);
|
|
109
|
+
extern int dict_insert_at(dict_t *, dnode_t *, const void *, dnode_t *, int);
|
|
110
|
+
extern dnode_t *dict_delete(dict_t *, dnode_t *);
|
|
111
|
+
extern int dict_alloc_insert(dict_t *, const void *, void *);
|
|
112
|
+
extern void dict_delete_free(dict_t *, dnode_t *);
|
|
113
|
+
extern dnode_t *dict_first(dict_t *);
|
|
114
|
+
extern dnode_t *dict_last(dict_t *);
|
|
115
|
+
extern dnode_t *dict_next(dict_t *, dnode_t *);
|
|
116
|
+
extern dnode_t *dict_prev(dict_t *, dnode_t *);
|
|
117
|
+
extern dictcount_t dict_count(dict_t *);
|
|
118
|
+
extern int dict_isempty(dict_t *);
|
|
119
|
+
extern int dict_isfull(dict_t *);
|
|
120
|
+
extern int dict_contains(dict_t *, dnode_t *);
|
|
121
|
+
extern void dict_allow_dupes(dict_t *);
|
|
122
|
+
extern int dnode_is_in_a_dict(dnode_t *);
|
|
123
|
+
extern dnode_t *dnode_create(void *);
|
|
124
|
+
extern dnode_t *dnode_init(dnode_t *, void *);
|
|
125
|
+
extern void dnode_destroy(dnode_t *);
|
|
126
|
+
extern void *dnode_get(dnode_t *);
|
|
127
|
+
extern const void *dnode_getkey(dnode_t *);
|
|
128
|
+
extern void dnode_put(dnode_t *, void *);
|
|
129
|
+
extern void dict_process(dict_t *, void *, dnode_process_t);
|
|
130
|
+
extern void dict_load_begin(dict_load_t *, dict_t *);
|
|
131
|
+
extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
|
|
132
|
+
extern void dict_load_end(dict_load_t *);
|
|
133
|
+
extern void dict_merge(dict_t *, dict_t *);
|
|
134
|
+
|
|
135
|
+
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
|
|
136
|
+
#ifdef KAZLIB_SIDEEFFECT_DEBUG
|
|
137
|
+
#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
|
|
138
|
+
#else
|
|
139
|
+
#define dict_isfull(D) ((D)->dict_nodecount == DICTCOUNT_T_MAX)
|
|
140
|
+
#endif
|
|
141
|
+
#define dict_count(D) ((D)->dict_nodecount)
|
|
142
|
+
#define dict_isempty(D) ((D)->dict_nodecount == 0)
|
|
143
|
+
#define dnode_get(N) ((N)->dict_data)
|
|
144
|
+
#define dnode_getkey(N) ((N)->dict_key)
|
|
145
|
+
#define dnode_put(N, X) ((N)->dict_data = (X))
|
|
146
|
+
#endif
|
|
147
|
+
|
|
148
|
+
#ifdef __cplusplus
|
|
149
|
+
}
|
|
150
|
+
#endif
|
|
151
|
+
|
|
152
|
+
#endif
|
data/ext/farce/drivers.c
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#include "reactor.h"
|
|
2
|
+
#include <unistd.h>
|
|
3
|
+
#include <poll.h>
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <limits.h>
|
|
6
|
+
#include <fcntl.h>
|
|
7
|
+
#include <math.h>
|
|
8
|
+
#ifdef HAVE_SYS_EPOLL_H
|
|
9
|
+
#include <sys/epoll.h>
|
|
10
|
+
#endif
|
|
11
|
+
#ifdef HAVE_SYS_EVENT_H
|
|
12
|
+
#include <sys/event.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
static struct timespec relative_time(double seconds) {
|
|
16
|
+
struct timespec t;
|
|
17
|
+
t.tv_sec = (time_t)seconds;
|
|
18
|
+
t.tv_nsec = (long)((seconds - (double)t.tv_sec) * 1e9);
|
|
19
|
+
return t;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
int fs_driver_init(fs_state *s, int driver) {
|
|
23
|
+
s->driver = driver;
|
|
24
|
+
#ifdef HAVE_SYS_EPOLL_H
|
|
25
|
+
if (driver == FS_EPOLL) {
|
|
26
|
+
s->descriptor = epoll_create1(EPOLL_CLOEXEC);
|
|
27
|
+
return s->descriptor < 0 ? errno : 0;
|
|
28
|
+
}
|
|
29
|
+
#endif
|
|
30
|
+
#ifdef HAVE_SYS_EVENT_H
|
|
31
|
+
if (driver == FS_KQUEUE) {
|
|
32
|
+
s->descriptor = kqueue();
|
|
33
|
+
return s->descriptor < 0 ? errno : 0;
|
|
34
|
+
}
|
|
35
|
+
#endif
|
|
36
|
+
#ifdef FARCE_URING
|
|
37
|
+
if (driver == FS_URING_DRIVER) {
|
|
38
|
+
int result = io_uring_queue_init(1024, &s->ring, 0);
|
|
39
|
+
if (result < 0) return -result;
|
|
40
|
+
s->ring_live = 1;
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
#endif
|
|
44
|
+
return ENOSYS;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#ifdef FARCE_URING
|
|
48
|
+
static struct io_uring_sqe *sqe(fs_state *s) {
|
|
49
|
+
struct io_uring_sqe *entry = io_uring_get_sqe(&s->ring);
|
|
50
|
+
if (!entry) {
|
|
51
|
+
int result = io_uring_submit(&s->ring);
|
|
52
|
+
if (result < 0) { errno = -result; return NULL; }
|
|
53
|
+
entry = io_uring_get_sqe(&s->ring);
|
|
54
|
+
}
|
|
55
|
+
if (!entry) errno = EBUSY;
|
|
56
|
+
return entry;
|
|
57
|
+
}
|
|
58
|
+
#endif
|
|
59
|
+
|
|
60
|
+
int fs_driver_receive(fs_state *s, fs_wait *w, int fd, void *buffer, size_t size) {
|
|
61
|
+
#ifdef FARCE_URING
|
|
62
|
+
struct io_uring_sqe *entry = sqe(s);
|
|
63
|
+
if (!entry) return errno;
|
|
64
|
+
io_uring_prep_recv(entry, fd, buffer, size > INT_MAX ? INT_MAX : (unsigned)size, 0);
|
|
65
|
+
#ifdef IORING_RECVSEND_POLL_FIRST
|
|
66
|
+
entry->ioprio |= IORING_RECVSEND_POLL_FIRST;
|
|
67
|
+
#endif
|
|
68
|
+
entry->user_data = FS_RECEIVE | NUM2ULL(w->token);
|
|
69
|
+
w->receive_pending = 1;
|
|
70
|
+
// Consume every queued SQE while holding the GVL, before Ruby can close or
|
|
71
|
+
// reopen this fd. SQPOLL is not enabled. The kernel then owns its file ref.
|
|
72
|
+
while (io_uring_sq_ready(&s->ring)) {
|
|
73
|
+
int result = io_uring_submit(&s->ring);
|
|
74
|
+
if (result < 0 && result != -EINTR) return -result;
|
|
75
|
+
}
|
|
76
|
+
return 0;
|
|
77
|
+
#else
|
|
78
|
+
return ENOSYS;
|
|
79
|
+
#endif
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
int fs_driver_update(fs_state *s, fs_reg *reg, int events) {
|
|
83
|
+
uint64_t previous = reg->generation;
|
|
84
|
+
uint64_t generation = ++s->generation;
|
|
85
|
+
int old = reg->events;
|
|
86
|
+
#ifdef HAVE_SYS_EPOLL_H
|
|
87
|
+
if (s->driver == FS_EPOLL) {
|
|
88
|
+
struct epoll_event ev = {.data.u64 = generation};
|
|
89
|
+
if (events & FS_READ) ev.events |= EPOLLIN | EPOLLRDHUP;
|
|
90
|
+
if (events & FS_WRITE) ev.events |= EPOLLOUT;
|
|
91
|
+
if (events & FS_PRI) ev.events |= EPOLLPRI;
|
|
92
|
+
int action = !events ? EPOLL_CTL_DEL : old ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
|
|
93
|
+
if (epoll_ctl(s->descriptor, action, reg->fd, &ev) < 0 &&
|
|
94
|
+
!(events == 0 && (errno == ENOENT || errno == EBADF))) return errno;
|
|
95
|
+
}
|
|
96
|
+
#endif
|
|
97
|
+
#ifdef HAVE_SYS_EVENT_H
|
|
98
|
+
if (s->driver == FS_KQUEUE) {
|
|
99
|
+
struct timespec zero = {0, 0};
|
|
100
|
+
for (int bit = FS_READ; bit <= FS_WRITE; bit <<= 1) {
|
|
101
|
+
if (!(old & bit) && !(events & bit)) continue;
|
|
102
|
+
if (reg->poll_events & bit) continue;
|
|
103
|
+
if (bit != FS_PRI) {
|
|
104
|
+
if (s->change_count == s->change_capacity) {
|
|
105
|
+
s->change_capacity = s->change_capacity ? s->change_capacity * 2 : 256;
|
|
106
|
+
REALLOC_N(s->changes, struct kevent, s->change_capacity);
|
|
107
|
+
}
|
|
108
|
+
struct kevent *change = &s->changes[s->change_count++];
|
|
109
|
+
EV_SET(change, reg->fd, bit == FS_READ ? EVFILT_READ : EVFILT_WRITE,
|
|
110
|
+
events & bit ? EV_ADD | EV_ENABLE : EV_DELETE, 0, 0, (void *)(uintptr_t)generation);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
struct kevent change, result;
|
|
114
|
+
EV_SET(&change, reg->fd, bit == FS_READ ? EVFILT_READ : bit == FS_WRITE ? EVFILT_WRITE : EVFILT_EXCEPT,
|
|
115
|
+
(events & bit ? EV_ADD | EV_ENABLE : EV_DELETE) | EV_RECEIPT, bit == FS_PRI ? NOTE_OOB : 0, 0,
|
|
116
|
+
(void *)(uintptr_t)generation);
|
|
117
|
+
int count = kevent(s->descriptor, &change, 1, &result, 1, &zero);
|
|
118
|
+
if (count < 0) return errno;
|
|
119
|
+
// EVFILT_EXCEPT is not supported by every descriptor (e.g. pipes).
|
|
120
|
+
// Retain the logical interest and snapshot it with poll instead.
|
|
121
|
+
if (count && bit == FS_PRI && (events & bit) &&
|
|
122
|
+
(result.data == EINVAL || result.data == ENOTSUP)) {
|
|
123
|
+
reg->poll_events |= bit;
|
|
124
|
+
s->polling_regs++;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (count && result.data && !(!(events & bit) &&
|
|
128
|
+
(result.data == ENOENT || result.data == EBADF))) return (int)result.data;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
#endif
|
|
132
|
+
#ifdef FARCE_URING
|
|
133
|
+
if (s->driver == FS_URING_DRIVER) {
|
|
134
|
+
if (old) {
|
|
135
|
+
struct io_uring_sqe *entry = sqe(s);
|
|
136
|
+
if (!entry) return errno;
|
|
137
|
+
io_uring_prep_poll_remove(entry, previous);
|
|
138
|
+
entry->user_data = 0; // cancellation acknowledgement has no storage pointer
|
|
139
|
+
}
|
|
140
|
+
if (events) {
|
|
141
|
+
struct io_uring_sqe *entry = sqe(s);
|
|
142
|
+
if (!entry) return errno;
|
|
143
|
+
unsigned mask = 0;
|
|
144
|
+
if (events & FS_READ) mask |= POLLIN;
|
|
145
|
+
if (events & FS_WRITE) mask |= POLLOUT;
|
|
146
|
+
if (events & FS_PRI) mask |= POLLPRI;
|
|
147
|
+
io_uring_prep_poll_add(entry, reg->fd, mask);
|
|
148
|
+
entry->user_data = generation;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
#endif
|
|
152
|
+
if (previous) { st_data_t key = previous; st_delete(s->generations, &key, NULL); }
|
|
153
|
+
reg->generation = generation;
|
|
154
|
+
reg->events = events;
|
|
155
|
+
if (events) st_insert(s->generations, generation, (st_data_t)reg);
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
void *fs_driver_poll(void *data) {
|
|
160
|
+
fs_state *s = data;
|
|
161
|
+
s->event_count = s->poll_error = 0;
|
|
162
|
+
struct timespec t = relative_time(s->timeout < 0 ? 0 : s->timeout);
|
|
163
|
+
#ifdef HAVE_SYS_EPOLL_H
|
|
164
|
+
if (s->driver == FS_EPOLL) {
|
|
165
|
+
struct epoll_event events[FS_EVENTS];
|
|
166
|
+
int n;
|
|
167
|
+
#ifdef HAVE_EPOLL_PWAIT2
|
|
168
|
+
n = epoll_pwait2(s->descriptor, events, FS_EVENTS, s->timeout < 0 ? NULL : &t, NULL);
|
|
169
|
+
if (n < 0 && errno == ENOSYS)
|
|
170
|
+
#endif
|
|
171
|
+
n = epoll_wait(s->descriptor, events, FS_EVENTS,
|
|
172
|
+
s->timeout < 0 ? -1 : (int)fmin(ceil(s->timeout * 1000), INT_MAX));
|
|
173
|
+
if (n < 0) { s->poll_error = errno; return NULL; }
|
|
174
|
+
for (int i = 0; i < n; i++) {
|
|
175
|
+
uint32_t e = events[i].events;
|
|
176
|
+
int mask = 0;
|
|
177
|
+
if (e & (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR)) mask |= FS_READ;
|
|
178
|
+
if (e & (EPOLLOUT | EPOLLHUP | EPOLLERR)) mask |= FS_WRITE;
|
|
179
|
+
if (e & EPOLLPRI) mask |= FS_PRI;
|
|
180
|
+
s->events[s->event_count++] = (fs_event){events[i].data.u64, mask, 0};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
#endif
|
|
184
|
+
#ifdef HAVE_SYS_EVENT_H
|
|
185
|
+
if (s->driver == FS_KQUEUE) {
|
|
186
|
+
struct kevent events[FS_EVENTS];
|
|
187
|
+
int n = kevent(s->descriptor, s->changes, s->change_count, events, FS_EVENTS, s->timeout < 0 ? NULL : &t);
|
|
188
|
+
if (n < 0) { s->poll_error = errno; return NULL; }
|
|
189
|
+
s->change_count = 0;
|
|
190
|
+
for (int i = 0; i < n; i++)
|
|
191
|
+
s->events[s->event_count++] = (fs_event){(uint64_t)(uintptr_t)events[i].udata,
|
|
192
|
+
events[i].filter == EVFILT_READ ? FS_READ : events[i].filter == EVFILT_WRITE ? FS_WRITE : FS_PRI,
|
|
193
|
+
events[i].flags & EV_ERROR ? (int)events[i].data : 0};
|
|
194
|
+
}
|
|
195
|
+
#endif
|
|
196
|
+
#ifdef FARCE_URING
|
|
197
|
+
if (s->driver == FS_URING_DRIVER) {
|
|
198
|
+
int result = io_uring_submit(&s->ring);
|
|
199
|
+
if (result < 0) { s->poll_error = -result; return NULL; }
|
|
200
|
+
struct io_uring_cqe *cqe;
|
|
201
|
+
if (s->timeout != 0 && io_uring_peek_cqe(&s->ring, &cqe) == -EAGAIN) {
|
|
202
|
+
struct __kernel_timespec kt = {t.tv_sec, t.tv_nsec};
|
|
203
|
+
result = s->timeout < 0 ? io_uring_wait_cqe(&s->ring, &cqe) :
|
|
204
|
+
io_uring_wait_cqe_timeout(&s->ring, &cqe, &kt);
|
|
205
|
+
if (result < 0 && result != -ETIME && result != -EINTR) s->poll_error = -result;
|
|
206
|
+
}
|
|
207
|
+
unsigned head, consumed = 0;
|
|
208
|
+
io_uring_for_each_cqe(&s->ring, head, cqe) {
|
|
209
|
+
if (s->event_count == FS_EVENTS) break;
|
|
210
|
+
consumed++;
|
|
211
|
+
if (cqe->user_data && cqe->user_data != LIBURING_UDATA_TIMEOUT) {
|
|
212
|
+
int e = cqe->res, mask = 0;
|
|
213
|
+
if (!(cqe->user_data & FS_RECEIVE) && e >= 0) {
|
|
214
|
+
if (e & (POLLIN | POLLHUP | POLLERR)) mask |= FS_READ;
|
|
215
|
+
if (e & (POLLOUT | POLLHUP | POLLERR)) mask |= FS_WRITE;
|
|
216
|
+
if (e & POLLPRI) mask |= FS_PRI;
|
|
217
|
+
}
|
|
218
|
+
s->events[s->event_count++] = (fs_event){cqe->user_data, mask,
|
|
219
|
+
cqe->user_data & FS_RECEIVE ? e : e < 0 && e != -ECANCELED ? -e : 0};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
io_uring_cq_advance(&s->ring, consumed);
|
|
223
|
+
}
|
|
224
|
+
#endif
|
|
225
|
+
return NULL;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void fs_driver_close(fs_state *s) {
|
|
229
|
+
#ifdef HAVE_SYS_EVENT_H
|
|
230
|
+
xfree(s->changes); s->changes = NULL;
|
|
231
|
+
s->change_count = s->change_capacity = 0;
|
|
232
|
+
#endif
|
|
233
|
+
#ifdef FARCE_URING
|
|
234
|
+
if (s->ring_live) { io_uring_queue_exit(&s->ring); s->ring_live = 0; }
|
|
235
|
+
#endif
|
|
236
|
+
if (s->descriptor >= 0) { close(s->descriptor); s->descriptor = -1; }
|
|
237
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#include "containers.h"
|
|
2
|
+
#include "ruby/io.h"
|
|
3
|
+
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <fcntl.h>
|
|
6
|
+
#include <math.h>
|
|
7
|
+
#include <time.h>
|
|
8
|
+
#include <unistd.h>
|
|
9
|
+
|
|
10
|
+
static VALUE cExchanger;
|
|
11
|
+
|
|
12
|
+
typedef struct {
|
|
13
|
+
int read_fd;
|
|
14
|
+
int write_fd;
|
|
15
|
+
} exchanger_signal_t;
|
|
16
|
+
|
|
17
|
+
typedef struct exchanger_waiter {
|
|
18
|
+
VALUE offered;
|
|
19
|
+
VALUE received;
|
|
20
|
+
exchanger_signal_t signal;
|
|
21
|
+
bool matched;
|
|
22
|
+
} exchanger_waiter_t;
|
|
23
|
+
|
|
24
|
+
typedef struct {
|
|
25
|
+
pthread_mutex_t lock;
|
|
26
|
+
exchanger_waiter_t *waiting;
|
|
27
|
+
bool initialized;
|
|
28
|
+
} exchanger_t;
|
|
29
|
+
|
|
30
|
+
typedef struct {
|
|
31
|
+
bool finite;
|
|
32
|
+
double deadline;
|
|
33
|
+
} exchanger_timeout_t;
|
|
34
|
+
|
|
35
|
+
typedef struct {
|
|
36
|
+
exchanger_t *exchanger;
|
|
37
|
+
exchanger_waiter_t *waiter;
|
|
38
|
+
exchanger_timeout_t *timeout;
|
|
39
|
+
} exchanger_wait_context_t;
|
|
40
|
+
|
|
41
|
+
static void
|
|
42
|
+
exchanger_set_fd_flags(int fd)
|
|
43
|
+
{
|
|
44
|
+
#ifdef _WIN32
|
|
45
|
+
(void)fd;
|
|
46
|
+
#else
|
|
47
|
+
int flags = fcntl(fd, F_GETFL, 0);
|
|
48
|
+
if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
49
|
+
flags = fcntl(fd, F_GETFD, 0);
|
|
50
|
+
if (flags >= 0) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
|
51
|
+
#endif
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static bool
|
|
55
|
+
exchanger_signal_initialize(exchanger_signal_t *signal)
|
|
56
|
+
{
|
|
57
|
+
int descriptors[2];
|
|
58
|
+
if (pipe(descriptors) != 0) return false;
|
|
59
|
+
signal->read_fd = descriptors[0];
|
|
60
|
+
signal->write_fd = descriptors[1];
|
|
61
|
+
exchanger_set_fd_flags(signal->read_fd);
|
|
62
|
+
exchanger_set_fd_flags(signal->write_fd);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static void
|
|
67
|
+
exchanger_signal_close(exchanger_signal_t *signal)
|
|
68
|
+
{
|
|
69
|
+
if (signal->read_fd >= 0) close(signal->read_fd);
|
|
70
|
+
if (signal->write_fd >= 0) close(signal->write_fd);
|
|
71
|
+
signal->read_fd = -1;
|
|
72
|
+
signal->write_fd = -1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static void
|
|
76
|
+
exchanger_signal_set(exchanger_signal_t *signal)
|
|
77
|
+
{
|
|
78
|
+
unsigned char byte = 1;
|
|
79
|
+
ssize_t result;
|
|
80
|
+
|
|
81
|
+
do {
|
|
82
|
+
result = write(signal->write_fd, &byte, 1);
|
|
83
|
+
} while (result < 0 && errno == EINTR);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static double
|
|
87
|
+
exchanger_monotonic_now(void)
|
|
88
|
+
{
|
|
89
|
+
struct timespec now;
|
|
90
|
+
#ifdef CLOCK_MONOTONIC
|
|
91
|
+
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
|
|
92
|
+
return (double)now.tv_sec + (double)now.tv_nsec / 1000000000.0;
|
|
93
|
+
}
|
|
94
|
+
#endif
|
|
95
|
+
struct timeval fallback;
|
|
96
|
+
gettimeofday(&fallback, NULL);
|
|
97
|
+
return (double)fallback.tv_sec + (double)fallback.tv_usec / 1000000.0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static exchanger_timeout_t
|
|
101
|
+
exchanger_parse_timeout(VALUE timeout)
|
|
102
|
+
{
|
|
103
|
+
exchanger_timeout_t parsed = {.finite = false, .deadline = 0};
|
|
104
|
+
if (NIL_P(timeout)) return parsed;
|
|
105
|
+
|
|
106
|
+
double seconds = NUM2DBL(timeout);
|
|
107
|
+
if (!isfinite(seconds) || seconds < 0) {
|
|
108
|
+
rb_raise(rb_eArgError, "timeout must be a finite, non-negative number or nil");
|
|
109
|
+
}
|
|
110
|
+
parsed.finite = true;
|
|
111
|
+
parsed.deadline = exchanger_monotonic_now() + seconds;
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static bool
|
|
116
|
+
exchanger_wait_for_descriptor(int fd, exchanger_timeout_t *timeout)
|
|
117
|
+
{
|
|
118
|
+
VALUE wait_timeout = Qnil;
|
|
119
|
+
if (timeout->finite) {
|
|
120
|
+
double remaining = timeout->deadline - exchanger_monotonic_now();
|
|
121
|
+
if (remaining <= 0) return false;
|
|
122
|
+
wait_timeout = DBL2NUM(remaining);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return containers_wait_for_readable(fd, wait_timeout);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static void
|
|
129
|
+
exchanger_free(void *pointer)
|
|
130
|
+
{
|
|
131
|
+
exchanger_t *exchanger = pointer;
|
|
132
|
+
pthread_mutex_destroy(&exchanger->lock);
|
|
133
|
+
ruby_xfree(exchanger);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static size_t
|
|
137
|
+
exchanger_memsize(const void *pointer)
|
|
138
|
+
{
|
|
139
|
+
return pointer ? sizeof(exchanger_t) : 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static const rb_data_type_t exchanger_type = {
|
|
143
|
+
.wrap_struct_name = "Ractor::Containers::Exchanger",
|
|
144
|
+
.function = {
|
|
145
|
+
.dmark = NULL,
|
|
146
|
+
.dfree = exchanger_free,
|
|
147
|
+
.dsize = exchanger_memsize,
|
|
148
|
+
.dcompact = NULL,
|
|
149
|
+
},
|
|
150
|
+
.flags = RUBY_TYPED_FROZEN_SHAREABLE,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
static VALUE
|
|
154
|
+
exchanger_allocate(VALUE klass)
|
|
155
|
+
{
|
|
156
|
+
exchanger_t *exchanger;
|
|
157
|
+
VALUE object = TypedData_Make_Struct(klass, exchanger_t, &exchanger_type, exchanger);
|
|
158
|
+
pthread_mutex_init(&exchanger->lock, NULL);
|
|
159
|
+
exchanger->waiting = NULL;
|
|
160
|
+
exchanger->initialized = false;
|
|
161
|
+
return object;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static exchanger_t *
|
|
165
|
+
get_exchanger(VALUE self)
|
|
166
|
+
{
|
|
167
|
+
exchanger_t *exchanger;
|
|
168
|
+
TypedData_Get_Struct(self, exchanger_t, &exchanger_type, exchanger);
|
|
169
|
+
if (!exchanger->initialized) rb_raise(rb_eRuntimeError, "uninitialized Exchanger");
|
|
170
|
+
return exchanger;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static VALUE
|
|
174
|
+
exchanger_frozen_p(VALUE self)
|
|
175
|
+
{
|
|
176
|
+
(void)self;
|
|
177
|
+
return Qfalse;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static VALUE
|
|
181
|
+
exchanger_freeze(VALUE self)
|
|
182
|
+
{
|
|
183
|
+
containers_raise_unfreezable(self);
|
|
184
|
+
return Qnil;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static VALUE
|
|
188
|
+
exchanger_initialize(VALUE self)
|
|
189
|
+
{
|
|
190
|
+
exchanger_t *exchanger;
|
|
191
|
+
TypedData_Get_Struct(self, exchanger_t, &exchanger_type, exchanger);
|
|
192
|
+
if (exchanger->initialized) rb_raise(rb_eRuntimeError, "Exchanger is already initialized");
|
|
193
|
+
exchanger->initialized = true;
|
|
194
|
+
containers_publish_native_reference_free(self);
|
|
195
|
+
return self;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static VALUE
|
|
199
|
+
exchanger_wait_body(VALUE opaque)
|
|
200
|
+
{
|
|
201
|
+
exchanger_wait_context_t *context = (exchanger_wait_context_t *)opaque;
|
|
202
|
+
return exchanger_wait_for_descriptor(context->waiter->signal.read_fd, context->timeout)
|
|
203
|
+
? Qtrue
|
|
204
|
+
: Qfalse;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static VALUE
|
|
208
|
+
exchanger_wait_cleanup(VALUE opaque)
|
|
209
|
+
{
|
|
210
|
+
exchanger_wait_context_t *context = (exchanger_wait_context_t *)opaque;
|
|
211
|
+
pthread_mutex_lock(&context->exchanger->lock);
|
|
212
|
+
if (context->exchanger->waiting == context->waiter) {
|
|
213
|
+
context->exchanger->waiting = NULL;
|
|
214
|
+
}
|
|
215
|
+
pthread_mutex_unlock(&context->exchanger->lock);
|
|
216
|
+
exchanger_signal_close(&context->waiter->signal);
|
|
217
|
+
return Qnil;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static VALUE
|
|
221
|
+
exchanger_exchange(int argc, VALUE *argv, VALUE self)
|
|
222
|
+
{
|
|
223
|
+
VALUE offered;
|
|
224
|
+
VALUE keywords = Qnil;
|
|
225
|
+
VALUE timeout_value = Qnil;
|
|
226
|
+
ID keyword_ids[] = {rb_intern("timeout")};
|
|
227
|
+
VALUE keyword_values[1];
|
|
228
|
+
|
|
229
|
+
rb_scan_args(argc, argv, "1:", &offered, &keywords);
|
|
230
|
+
if (!NIL_P(keywords)) {
|
|
231
|
+
rb_get_kwargs(keywords, keyword_ids, 0, 1, keyword_values);
|
|
232
|
+
if (keyword_values[0] != Qundef) timeout_value = keyword_values[0];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
containers_check_shareable(offered);
|
|
236
|
+
exchanger_timeout_t timeout = exchanger_parse_timeout(timeout_value);
|
|
237
|
+
exchanger_t *exchanger = get_exchanger(self);
|
|
238
|
+
|
|
239
|
+
pthread_mutex_lock(&exchanger->lock);
|
|
240
|
+
if (exchanger->waiting != NULL) {
|
|
241
|
+
exchanger_waiter_t *partner = exchanger->waiting;
|
|
242
|
+
exchanger->waiting = NULL;
|
|
243
|
+
VALUE received = partner->offered;
|
|
244
|
+
partner->received = offered;
|
|
245
|
+
partner->matched = true;
|
|
246
|
+
exchanger_signal_set(&partner->signal);
|
|
247
|
+
pthread_mutex_unlock(&exchanger->lock);
|
|
248
|
+
RB_GC_GUARD(offered);
|
|
249
|
+
return received;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (timeout.finite && timeout.deadline <= exchanger_monotonic_now()) {
|
|
253
|
+
pthread_mutex_unlock(&exchanger->lock);
|
|
254
|
+
return rb_block_given_p() ? rb_yield_values(0) : Qnil;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
exchanger_waiter_t waiter = {
|
|
258
|
+
.offered = offered,
|
|
259
|
+
.received = Qnil,
|
|
260
|
+
.signal = {.read_fd = -1, .write_fd = -1},
|
|
261
|
+
.matched = false,
|
|
262
|
+
};
|
|
263
|
+
if (!exchanger_signal_initialize(&waiter.signal)) {
|
|
264
|
+
int error = errno;
|
|
265
|
+
pthread_mutex_unlock(&exchanger->lock);
|
|
266
|
+
errno = error;
|
|
267
|
+
rb_sys_fail("pipe");
|
|
268
|
+
}
|
|
269
|
+
exchanger->waiting = &waiter;
|
|
270
|
+
pthread_mutex_unlock(&exchanger->lock);
|
|
271
|
+
|
|
272
|
+
exchanger_wait_context_t context = {
|
|
273
|
+
.exchanger = exchanger,
|
|
274
|
+
.waiter = &waiter,
|
|
275
|
+
.timeout = &timeout,
|
|
276
|
+
};
|
|
277
|
+
(void)rb_ensure(
|
|
278
|
+
exchanger_wait_body,
|
|
279
|
+
(VALUE)&context,
|
|
280
|
+
exchanger_wait_cleanup,
|
|
281
|
+
(VALUE)&context
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
RB_GC_GUARD(offered);
|
|
285
|
+
RB_GC_GUARD(waiter.received);
|
|
286
|
+
if (waiter.matched) return waiter.received;
|
|
287
|
+
return rb_block_given_p() ? rb_yield_values(0) : Qnil;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
void
|
|
291
|
+
containers_init_exchanger(VALUE namespace)
|
|
292
|
+
{
|
|
293
|
+
cExchanger = rb_define_class_under(namespace, "Exchanger", rb_cObject);
|
|
294
|
+
rb_define_alloc_func(cExchanger, exchanger_allocate);
|
|
295
|
+
rb_define_method(cExchanger, "initialize", exchanger_initialize, 0);
|
|
296
|
+
rb_define_method(cExchanger, "exchange", exchanger_exchange, -1);
|
|
297
|
+
rb_define_method(cExchanger, "freeze", exchanger_freeze, 0);
|
|
298
|
+
rb_define_method(cExchanger, "frozen?", exchanger_frozen_p, 0);
|
|
299
|
+
}
|