farce 0 → 0.1.0

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 (420) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/CODE_OF_CONDUCT.md +26 -0
  4. data/CONTRIBUTING.md +71 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +1525 -0
  7. data/SECURITY.md +10 -0
  8. data/docs/benchmarks.md +185 -0
  9. data/docs/gems/dry-types.md +290 -0
  10. data/docs/gems/msgpack.md +70 -0
  11. data/docs/gems/ractor-shim.md +63 -0
  12. data/docs/modes.md +628 -0
  13. data/docs/scopes.md +649 -0
  14. data/docs/variants.md +346 -0
  15. data/ext/ext_helper.rb +20 -0
  16. data/ext/farce/README.md +21 -0
  17. data/ext/farce/atom.c +1023 -0
  18. data/ext/farce/bounded_map.c +1683 -0
  19. data/ext/farce/containers.h +77 -0
  20. data/ext/farce/counter.c +399 -0
  21. data/ext/farce/darwin.c +100 -0
  22. data/ext/farce/depend +12 -0
  23. data/ext/farce/dict.c +1523 -0
  24. data/ext/farce/dict.h +152 -0
  25. data/ext/farce/drivers.c +237 -0
  26. data/ext/farce/exchanger.c +299 -0
  27. data/ext/farce/extconf.rb +99 -0
  28. data/ext/farce/farce.c +359 -0
  29. data/ext/farce/flag.c +288 -0
  30. data/ext/farce/io.c +338 -0
  31. data/ext/farce/lock.c +510 -0
  32. data/ext/farce/map.c +2240 -0
  33. data/ext/farce/priority_queue.c +2056 -0
  34. data/ext/farce/queue.c +1059 -0
  35. data/ext/farce/reactor.c +820 -0
  36. data/ext/farce/reactor.h +103 -0
  37. data/ext/farce/shareable.h +31 -0
  38. data/ext/farce/signal.c +350 -0
  39. data/ext/farce/transaction.c +354 -0
  40. data/ext/farce/transaction.h +40 -0
  41. data/ext/farce/tree_map.c +1953 -0
  42. data/ext/farce/trie.c +2020 -0
  43. data/ext/farce/unshareable.c +155 -0
  44. data/ext/farce/unshared_io_pool.h +234 -0
  45. data/ext/farce/unshared_signal.c +263 -0
  46. data/ext/farce/unshared_wait.h +193 -0
  47. data/ext/farce/unsupported.c +6 -0
  48. data/ext/farce/vector.c +1195 -0
  49. data/ext/farce/weak_map.c +1714 -0
  50. data/ext/java/org/farce/BoundedMap.java +394 -0
  51. data/ext/java/org/farce/FiberScheduler.java +141 -0
  52. data/ext/java/org/farce/PriorityKey.java +45 -0
  53. data/ext/java/org/farce/PriorityQueue.java +373 -0
  54. data/ext/java/org/farce/QueueSignal.java +28 -0
  55. data/ext/rebind/README.md +14 -0
  56. data/ext/rebind/extconf.rb +10 -0
  57. data/ext/rebind/rebind.c +186 -0
  58. data/lib/farce/_yard/internal.rb +13 -0
  59. data/lib/farce/_yard/macros.rb +61 -0
  60. data/lib/farce/_yard/ractor.rb +46 -0
  61. data/lib/farce/abstract/atom.rb +186 -0
  62. data/lib/farce/abstract/bounded_map.rb +232 -0
  63. data/lib/farce/abstract/collection.rb +151 -0
  64. data/lib/farce/abstract/concurrent_map.rb +381 -0
  65. data/lib/farce/abstract/counter.rb +193 -0
  66. data/lib/farce/abstract/duplicable_map.rb +229 -0
  67. data/lib/farce/abstract/exchanger.rb +26 -0
  68. data/lib/farce/abstract/flag.rb +71 -0
  69. data/lib/farce/abstract/lazy.rb +115 -0
  70. data/lib/farce/abstract/lease.rb +104 -0
  71. data/lib/farce/abstract/lease_map.rb +261 -0
  72. data/lib/farce/abstract/lease_pool.rb +91 -0
  73. data/lib/farce/abstract/lfu_map.rb +20 -0
  74. data/lib/farce/abstract/lru_map.rb +25 -0
  75. data/lib/farce/abstract/map.rb +345 -0
  76. data/lib/farce/abstract/molecule.rb +245 -0
  77. data/lib/farce/abstract/port.rb +74 -0
  78. data/lib/farce/abstract/priority_queue.rb +117 -0
  79. data/lib/farce/abstract/queue.rb +269 -0
  80. data/lib/farce/abstract/scheduler.rb +111 -0
  81. data/lib/farce/abstract/set.rb +910 -0
  82. data/lib/farce/abstract/sorted_set.rb +172 -0
  83. data/lib/farce/abstract/timer_queue.rb +136 -0
  84. data/lib/farce/abstract/tree_map.rb +269 -0
  85. data/lib/farce/abstract/value.rb +68 -0
  86. data/lib/farce/abstract/vector.rb +1126 -0
  87. data/lib/farce/abstract/weak_atom.rb +32 -0
  88. data/lib/farce/abstract/weak_key_map.rb +12 -0
  89. data/lib/farce/abstract/weak_map.rb +13 -0
  90. data/lib/farce/abstract/weak_set.rb +12 -0
  91. data/lib/farce/abstract/weak_value_map.rb +12 -0
  92. data/lib/farce/abstract.rb +17 -0
  93. data/lib/farce/atom.rb +293 -0
  94. data/lib/farce/class_mirror.rb +87 -0
  95. data/lib/farce/clock.rb +121 -0
  96. data/lib/farce/config.rb +229 -0
  97. data/lib/farce/counter.rb +71 -0
  98. data/lib/farce/deduper.rb +122 -0
  99. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  101. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  102. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  103. data/lib/farce/engine/jruby/map.rb +505 -0
  104. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  105. data/lib/farce/engine/jruby/signal.rb +147 -0
  106. data/lib/farce/engine/jruby.rb +63 -0
  107. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  108. data/lib/farce/engine/jvm/counter.rb +102 -0
  109. data/lib/farce/engine/jvm/extension.rb +32 -0
  110. data/lib/farce/engine/jvm/farce.jar +0 -0
  111. data/lib/farce/engine/jvm/flag.rb +79 -0
  112. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  113. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  114. data/lib/farce/engine/jvm/types.rb +180 -0
  115. data/lib/farce/engine/jvm.rb +19 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  121. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  122. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  123. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  124. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  125. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  126. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  127. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  128. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  129. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  130. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  131. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  132. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  133. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  134. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  135. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  136. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  137. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  138. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  139. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  140. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  141. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  142. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  143. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  144. data/lib/farce/engine/ruby.rb +130 -0
  145. data/lib/farce/engine/shared/atom.rb +10 -0
  146. data/lib/farce/engine/shared/exchanger.rb +130 -0
  147. data/lib/farce/engine/shared/identity_key.rb +22 -0
  148. data/lib/farce/engine/shared/lease.rb +10 -0
  149. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  150. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  151. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  152. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  153. data/lib/farce/engine/shared/port.rb +44 -0
  154. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  155. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  156. data/lib/farce/engine/shared/queue.rb +233 -0
  157. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  158. data/lib/farce/engine/shared/rebindable.rb +15 -0
  159. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  160. data/lib/farce/engine/shared/strict_map.rb +117 -0
  161. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  162. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  163. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  164. data/lib/farce/engine/shared/trie.rb +317 -0
  165. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  166. data/lib/farce/engine/shared/unshareable.rb +14 -0
  167. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  168. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  169. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  170. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  171. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  172. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  173. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  174. data/lib/farce/engine/shared/vault.rb +31 -0
  175. data/lib/farce/engine/shared/vector.rb +83 -0
  176. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  177. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  178. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  179. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  180. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  181. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  182. data/lib/farce/engine/shared.rb +63 -0
  183. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  184. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  185. data/lib/farce/engine/truffleruby/map.rb +656 -0
  186. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  187. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  188. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  189. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  190. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  191. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  192. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  193. data/lib/farce/engine/truffleruby.rb +148 -0
  194. data/lib/farce/envelope.rb +335 -0
  195. data/lib/farce/error.rb +35 -0
  196. data/lib/farce/exchanger.rb +41 -0
  197. data/lib/farce/flag.rb +27 -0
  198. data/lib/farce/integrations/active_support/blank.rb +68 -0
  199. data/lib/farce/integrations/active_support/clock.rb +17 -0
  200. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  201. data/lib/farce/integrations/active_support/map.rb +175 -0
  202. data/lib/farce/integrations/active_support/set.rb +60 -0
  203. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  204. data/lib/farce/integrations/active_support/vector.rb +231 -0
  205. data/lib/farce/integrations/active_support.rb +9 -0
  206. data/lib/farce/integrations/activesupport.rb +5 -0
  207. data/lib/farce/integrations/bson.rb +108 -0
  208. data/lib/farce/integrations/cbor.rb +51 -0
  209. data/lib/farce/integrations/concurrent.rb +112 -0
  210. data/lib/farce/integrations/dry-types.rb +5 -0
  211. data/lib/farce/integrations/dry_types.rb +694 -0
  212. data/lib/farce/integrations/json.rb +7 -0
  213. data/lib/farce/integrations/msgpack.rb +112 -0
  214. data/lib/farce/integrations/oj.rb +69 -0
  215. data/lib/farce/integrations/psych.rb +191 -0
  216. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  217. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  218. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  219. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  220. data/lib/farce/integrations/shared/to_json.rb +42 -0
  221. data/lib/farce/integrations/sorted_set.rb +11 -0
  222. data/lib/farce/integrations/weakref.rb +38 -0
  223. data/lib/farce/integrations/yajl.rb +10 -0
  224. data/lib/farce/integrations.rb +156 -0
  225. data/lib/farce/internal/_frozen_config.rb +11 -0
  226. data/lib/farce/internal/autoloads.rb +47 -0
  227. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  228. data/lib/farce/internal/converter.rb +106 -0
  229. data/lib/farce/internal/copyable.rb +31 -0
  230. data/lib/farce/internal/delegation.rb +20 -0
  231. data/lib/farce/internal/external_transaction.rb +59 -0
  232. data/lib/farce/internal/fake_ractor.rb +179 -0
  233. data/lib/farce/internal/freeze.rb +118 -0
  234. data/lib/farce/internal/inspect.rb +157 -0
  235. data/lib/farce/internal/key_lock_map.rb +29 -0
  236. data/lib/farce/internal/key_normalizer.rb +289 -0
  237. data/lib/farce/internal/lease_initialization.rb +115 -0
  238. data/lib/farce/internal/lease_map.rb +441 -0
  239. data/lib/farce/internal/lease_pool_state.rb +228 -0
  240. data/lib/farce/internal/lease_state.rb +342 -0
  241. data/lib/farce/internal/lease_waiting.rb +13 -0
  242. data/lib/farce/internal/managed_queue.rb +26 -0
  243. data/lib/farce/internal/map_value_modes.rb +227 -0
  244. data/lib/farce/internal/marshal_support.rb +227 -0
  245. data/lib/farce/internal/mixin.rb +20 -0
  246. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  247. data/lib/farce/internal/noncopyable.rb +17 -0
  248. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  249. data/lib/farce/internal/pool_supervisor.rb +41 -0
  250. data/lib/farce/internal/pool_worker.rb +61 -0
  251. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  252. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  253. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  254. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  255. data/lib/farce/internal/portable_transaction.rb +164 -0
  256. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  257. data/lib/farce/internal/reservation_waiting.rb +24 -0
  258. data/lib/farce/internal/scheduled_task.rb +48 -0
  259. data/lib/farce/internal/scheduler_io.rb +171 -0
  260. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  261. data/lib/farce/internal/select_scheduler.rb +235 -0
  262. data/lib/farce/internal/storage.rb +162 -0
  263. data/lib/farce/internal/strict_lease.rb +30 -0
  264. data/lib/farce/internal/strict_lease_map.rb +20 -0
  265. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  266. data/lib/farce/internal/thread_pool.rb +166 -0
  267. data/lib/farce/internal/transaction_conflict.rb +9 -0
  268. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  269. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  270. data/lib/farce/internal/undefined.rb +22 -0
  271. data/lib/farce/internal/unshared_lease.rb +29 -0
  272. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  273. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  274. data/lib/farce/internal/value_serialization.rb +13 -0
  275. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  276. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  277. data/lib/farce/internal.rb +129 -0
  278. data/lib/farce/lazy.rb +100 -0
  279. data/lib/farce/lazy_ref.rb +40 -0
  280. data/lib/farce/lease.rb +28 -0
  281. data/lib/farce/lease_map.rb +34 -0
  282. data/lib/farce/lease_pool.rb +29 -0
  283. data/lib/farce/lfu_map.rb +53 -0
  284. data/lib/farce/local/atom.rb +23 -0
  285. data/lib/farce/local/counter.rb +88 -0
  286. data/lib/farce/local/flag.rb +65 -0
  287. data/lib/farce/local/lazy.rb +38 -0
  288. data/lib/farce/local/lazy_ref.rb +36 -0
  289. data/lib/farce/local/lease.rb +77 -0
  290. data/lib/farce/local/lease_map.rb +80 -0
  291. data/lib/farce/local/lease_pool.rb +38 -0
  292. data/lib/farce/local/lfu_map.rb +55 -0
  293. data/lib/farce/local/lru_map.rb +62 -0
  294. data/lib/farce/local/map.rb +47 -0
  295. data/lib/farce/local/molecule.rb +45 -0
  296. data/lib/farce/local/priority_queue.rb +53 -0
  297. data/lib/farce/local/queue.rb +32 -0
  298. data/lib/farce/local/scoped.rb +166 -0
  299. data/lib/farce/local/set.rb +18 -0
  300. data/lib/farce/local/sorted_set.rb +50 -0
  301. data/lib/farce/local/timer_queue.rb +41 -0
  302. data/lib/farce/local/tree_map.rb +47 -0
  303. data/lib/farce/local/vector.rb +30 -0
  304. data/lib/farce/local/weak_atom.rb +23 -0
  305. data/lib/farce/local/weak_key_map.rb +39 -0
  306. data/lib/farce/local/weak_map.rb +39 -0
  307. data/lib/farce/local/weak_set.rb +18 -0
  308. data/lib/farce/local/weak_value_map.rb +39 -0
  309. data/lib/farce/local.rb +35 -0
  310. data/lib/farce/lock.rb +54 -0
  311. data/lib/farce/lru_map.rb +63 -0
  312. data/lib/farce/map.rb +58 -0
  313. data/lib/farce/mode_manager.rb +142 -0
  314. data/lib/farce/molecule.rb +60 -0
  315. data/lib/farce/mutable.rb +171 -0
  316. data/lib/farce/pool.rb +332 -0
  317. data/lib/farce/port.rb +134 -0
  318. data/lib/farce/priority_queue.rb +70 -0
  319. data/lib/farce/proxy/register.rb +101 -0
  320. data/lib/farce/proxy/supervisor.rb +137 -0
  321. data/lib/farce/proxy/wrapper.rb +49 -0
  322. data/lib/farce/proxy.rb +291 -0
  323. data/lib/farce/queue.rb +60 -0
  324. data/lib/farce/ractor.rb +269 -0
  325. data/lib/farce/read_write_lock.rb +256 -0
  326. data/lib/farce/reference.rb +158 -0
  327. data/lib/farce/resolv/dns.rb +42 -0
  328. data/lib/farce/resolv.rb +85 -0
  329. data/lib/farce/scheduler.rb +536 -0
  330. data/lib/farce/set.rb +39 -0
  331. data/lib/farce/shareable.rb +150 -0
  332. data/lib/farce/signal.rb +97 -0
  333. data/lib/farce/sorted_set.rb +36 -0
  334. data/lib/farce/strict/atom.rb +34 -0
  335. data/lib/farce/strict/counter.rb +10 -0
  336. data/lib/farce/strict/exchanger.rb +25 -0
  337. data/lib/farce/strict/flag.rb +10 -0
  338. data/lib/farce/strict/lazy.rb +26 -0
  339. data/lib/farce/strict/lazy_ref.rb +26 -0
  340. data/lib/farce/strict/lease.rb +27 -0
  341. data/lib/farce/strict/lease_map.rb +33 -0
  342. data/lib/farce/strict/lease_pool.rb +28 -0
  343. data/lib/farce/strict/lfu_map.rb +27 -0
  344. data/lib/farce/strict/lru_map.rb +28 -0
  345. data/lib/farce/strict/map.rb +54 -0
  346. data/lib/farce/strict/molecule.rb +16 -0
  347. data/lib/farce/strict/port.rb +40 -0
  348. data/lib/farce/strict/priority_queue.rb +20 -0
  349. data/lib/farce/strict/queue.rb +17 -0
  350. data/lib/farce/strict/set.rb +14 -0
  351. data/lib/farce/strict/sorted_set.rb +19 -0
  352. data/lib/farce/strict/timer_queue.rb +13 -0
  353. data/lib/farce/strict/tree_map.rb +27 -0
  354. data/lib/farce/strict/vector.rb +24 -0
  355. data/lib/farce/strict/weak_atom.rb +31 -0
  356. data/lib/farce/strict/weak_key_map.rb +49 -0
  357. data/lib/farce/strict/weak_map.rb +49 -0
  358. data/lib/farce/strict/weak_set.rb +14 -0
  359. data/lib/farce/strict/weak_value_map.rb +48 -0
  360. data/lib/farce/strict.rb +28 -0
  361. data/lib/farce/system.rb +40 -0
  362. data/lib/farce/thread_scheduler.rb +70 -0
  363. data/lib/farce/timer_queue.rb +66 -0
  364. data/lib/farce/transaction/atom.rb +73 -0
  365. data/lib/farce/transaction/map.rb +25 -0
  366. data/lib/farce/transaction/map_operations.rb +143 -0
  367. data/lib/farce/transaction/molecule.rb +90 -0
  368. data/lib/farce/transaction/mutable.rb +61 -0
  369. data/lib/farce/transaction/set.rb +17 -0
  370. data/lib/farce/transaction/set_operations.rb +48 -0
  371. data/lib/farce/transaction/sorted_set.rb +18 -0
  372. data/lib/farce/transaction/tree_map.rb +78 -0
  373. data/lib/farce/transaction/vector.rb +139 -0
  374. data/lib/farce/transaction/wrapper.rb +202 -0
  375. data/lib/farce/transaction.rb +343 -0
  376. data/lib/farce/tree_map.rb +56 -0
  377. data/lib/farce/unsafe/lfu_map.rb +36 -0
  378. data/lib/farce/unsafe/lru_map.rb +36 -0
  379. data/lib/farce/unsafe/tree_map.rb +21 -0
  380. data/lib/farce/unsafe.rb +29 -0
  381. data/lib/farce/unshareable.rb +67 -0
  382. data/lib/farce/unshared/atom.rb +24 -0
  383. data/lib/farce/unshared/counter.rb +10 -0
  384. data/lib/farce/unshared/flag.rb +10 -0
  385. data/lib/farce/unshared/lazy.rb +38 -0
  386. data/lib/farce/unshared/lazy_ref.rb +26 -0
  387. data/lib/farce/unshared/lease.rb +27 -0
  388. data/lib/farce/unshared/lease_map.rb +26 -0
  389. data/lib/farce/unshared/lease_pool.rb +25 -0
  390. data/lib/farce/unshared/lfu_map.rb +20 -0
  391. data/lib/farce/unshared/lru_map.rb +20 -0
  392. data/lib/farce/unshared/map.rb +49 -0
  393. data/lib/farce/unshared/molecule.rb +16 -0
  394. data/lib/farce/unshared/priority_queue.rb +16 -0
  395. data/lib/farce/unshared/queue.rb +27 -0
  396. data/lib/farce/unshared/set.rb +14 -0
  397. data/lib/farce/unshared/sorted_set.rb +28 -0
  398. data/lib/farce/unshared/timer_queue.rb +16 -0
  399. data/lib/farce/unshared/tree_map.rb +21 -0
  400. data/lib/farce/unshared/vector.rb +19 -0
  401. data/lib/farce/unshared/weak_atom.rb +31 -0
  402. data/lib/farce/unshared/weak_key_map.rb +44 -0
  403. data/lib/farce/unshared/weak_map.rb +44 -0
  404. data/lib/farce/unshared/weak_set.rb +14 -0
  405. data/lib/farce/unshared/weak_value_map.rb +43 -0
  406. data/lib/farce/unshared.rb +28 -0
  407. data/lib/farce/vector.rb +228 -0
  408. data/lib/farce/version.rb +8 -0
  409. data/lib/farce/walker/definitions.rb +186 -0
  410. data/lib/farce/walker/modification.rb +355 -0
  411. data/lib/farce/walker.rb +319 -0
  412. data/lib/farce/weak_atom.rb +121 -0
  413. data/lib/farce/weak_key_map.rb +31 -0
  414. data/lib/farce/weak_map.rb +33 -0
  415. data/lib/farce/weak_ref.rb +67 -0
  416. data/lib/farce/weak_set.rb +82 -0
  417. data/lib/farce/weak_value.rb +195 -0
  418. data/lib/farce/weak_value_map.rb +32 -0
  419. data/lib/farce.rb +519 -0
  420. metadata +435 -8
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require_relative "../ext_helper"
5
+
6
+ if RUBY_ENGINE != "ruby"
7
+ File.write("Makefile", "all:\ninstall:\n")
8
+ return
9
+ end
10
+
11
+ # rubocop:disable Style/GlobalVars -- mkmf configuration variables
12
+ %w[pthread.h ruby/ractor.h ruby/thread.h ruby/fiber/scheduler.h].each do |header|
13
+ have_header(header) or abort "#{header} is required"
14
+ end
15
+
16
+ ruby_major, ruby_minor = RUBY_VERSION.split(".").first(2).map!(&:to_i)
17
+ ruby_api = (ruby_major * 100) + ruby_minor
18
+ if ruby_api >= 401
19
+ have_macro("RB_OBJ_SET_SHAREABLE", "ruby/ractor.h") or abort "RB_OBJ_SET_SHAREABLE is required"
20
+ $defs << "-DFARCE_HAVE_EXPORTED_SHAREABLE_MARKER"
21
+ elsif ruby_api >= 304
22
+ # CRuby 3.4/4.0 have no exported marker on supported builds. The native
23
+ # publisher rejects Ruby ivars and requires audited typed-data payloads.
24
+ $defs << "-DFARCE_USE_LEGACY_SHAREABLE_FLAG"
25
+ else
26
+ abort "Native unfrozen publication requires CRuby 3.4 or newer"
27
+ end
28
+
29
+ if ruby_api == 304
30
+ have_func("rb_thread_lock_native_thread", "ruby/thread.h") or abort "rb_thread_lock_native_thread is required"
31
+ end
32
+
33
+ have_func("clock_gettime", "time.h")
34
+
35
+ if /mswin|mingw/ =~ RUBY_PLATFORM
36
+ have_func("rb_objspace_reachable_objects_from") or abort "Windows waits require rb_objspace_reachable_objects_from"
37
+ end
38
+
39
+ if have_header("pthread/qos.h")
40
+ have_func("pthread_set_qos_class_self_np", "pthread/qos.h")
41
+ have_func("pthread_get_qos_class_np", "pthread/qos.h")
42
+ have_func("qos_class_main", "pthread/qos.h")
43
+ end
44
+
45
+ have_func("sysctlbyname", "sys/sysctl.h") if have_header("sys/sysctl.h")
46
+
47
+ epoll = have_header("sys/epoll.h")
48
+ kqueue = have_header("sys/event.h")
49
+ $srcs = %w[
50
+ atom.c bounded_map.c counter.c darwin.c dict.c exchanger.c farce.c flag.c lock.c map.c priority_queue.c
51
+ queue.c signal.c transaction.c tree_map.c trie.c unshareable.c unshared_signal.c vector.c weak_map.c
52
+ ]
53
+ $srcs.concat(epoll || kqueue ? %w[drivers.c io.c reactor.c] : ["unsupported.c"])
54
+
55
+ if epoll || kqueue
56
+ have_func("epoll_pwait2", "sys/epoll.h") if epoll
57
+ have_func("rb_io_timeout", "ruby/io.h")
58
+ if enable_config("io-uring", true) && have_header("liburing.h") && have_library("uring", "io_uring_queue_init")
59
+ $defs << "-DFARCE_HAVE_LIBURING"
60
+ end
61
+ end
62
+
63
+ weak_callback = try_compile(<<~SOURCE)
64
+ #include "ruby.h"
65
+
66
+ static void handle_weak_references(void *pointer) { (void)pointer; }
67
+ static const rb_data_type_t probe_type = {
68
+ .wrap_struct_name = "weak-reference-probe",
69
+ .function = {
70
+ .handle_weak_references = handle_weak_references,
71
+ },
72
+ };
73
+
74
+ int main(void) { return probe_type.function.handle_weak_references == 0; }
75
+ SOURCE
76
+
77
+ weak_declare = have_func("rb_gc_declare_weak_references")
78
+ weak_alive = have_func("rb_gc_handle_weak_references_alive_p")
79
+
80
+ # Kazlib deliberately puts full-tree integrity walks behind assert(3).
81
+ # Enable them only while debugging the priority queue.
82
+ $defs << "-DNDEBUG" unless ENV["FARCE_PRIORITY_QUEUE_ASSERTIONS"] == "1"
83
+ $defs << "-DRC_HAVE_NATIVE_WEAK_REFERENCES=1" if weak_callback && weak_declare && weak_alive
84
+ $defs << "-DFARCE_TRIE_FAILURE_INJECTION" if ENV["FARCE_TRIE_FAILURE_INJECTION"] == "1"
85
+ $CFLAGS = "#{$CFLAGS} -std=c11 -fvisibility=hidden -Wall -Wextra -Wno-unused-parameter -Wno-unused-function"
86
+ $LDFLAGS = "#{$LDFLAGS} -pthread" unless /mswin|mingw/ =~ RUBY_PLATFORM
87
+
88
+ if ENV["FARCE_SCHEDULER_SANITIZE"]
89
+ flags = " -O1 -g -fno-omit-frame-pointer -fsanitize=#{ENV.fetch("FARCE_SCHEDULER_SANITIZE")}"
90
+ $CFLAGS << flags
91
+ $LDFLAGS << flags
92
+ end
93
+
94
+ if try_cflags("-flto") && try_ldflags("-flto")
95
+ $CFLAGS << " -flto"
96
+ $LDFLAGS << " -flto"
97
+ end
98
+ create_makefile ExtHelper.ext_path("farce")
99
+ # rubocop:enable Style/GlobalVars
data/ext/farce/farce.c ADDED
@@ -0,0 +1,359 @@
1
+ #include "containers.h"
2
+ #include "transaction.h"
3
+ #include "shareable.h"
4
+ #include "ruby/fiber/scheduler.h"
5
+ #include "ruby/io.h"
6
+
7
+ #include <errno.h>
8
+ #include <math.h>
9
+ #include <unistd.h>
10
+
11
+ #ifdef _WIN32
12
+ #include <io.h>
13
+ #include <windows.h>
14
+ /* Older MinGW headers omit this flag even when the runtime supports it. */
15
+ #ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
16
+ #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
17
+ #endif
18
+ #endif
19
+
20
+ static VALUE eIsolationError;
21
+
22
+ void farce_init_fiber_scheduler(VALUE namespace);
23
+
24
+ RBIMPL_ATTR_NORETURN()
25
+ static void
26
+ raise_unshareable(VALUE value)
27
+ {
28
+ rb_raise(eIsolationError, "value is not shareable: %" PRIsVALUE, rb_inspect(value));
29
+ }
30
+
31
+ void
32
+ containers_check_shareable(VALUE value)
33
+ {
34
+ if (!rb_ractor_shareable_p(value)) raise_unshareable(value);
35
+ }
36
+
37
+ bool
38
+ containers_strict_bool(VALUE value, const char *name)
39
+ {
40
+ if (value == Qtrue) return true;
41
+ if (value == Qfalse) return false;
42
+ rb_raise(rb_eArgError, "%s must be true or false", name);
43
+ }
44
+
45
+ static void
46
+ containers_check_native_publication_target(VALUE self)
47
+ {
48
+ if (!RB_TYPE_P(self, T_DATA) || !RTYPEDDATA_P(self)) {
49
+ rb_raise(rb_eTypeError, "native publication requires a typed-data object");
50
+ }
51
+ if (!(RTYPEDDATA_TYPE(self)->flags & RUBY_TYPED_FROZEN_SHAREABLE)) {
52
+ rb_raise(rb_eTypeError, "native publication requires a shareable typed-data descriptor");
53
+ }
54
+
55
+ VALUE instance_variables = rb_obj_instance_variables(self);
56
+ if (RARRAY_LEN(instance_variables) != 0) {
57
+ rb_raise(
58
+ rb_eTypeError,
59
+ "%s cannot be published with Ruby instance variables",
60
+ rb_obj_classname(self)
61
+ );
62
+ }
63
+ RB_GC_GUARD(instance_variables);
64
+ }
65
+
66
+ VALUE
67
+ containers_publish_native_reference_free(VALUE self)
68
+ {
69
+ containers_check_native_publication_target(self);
70
+ return farce_ruby_mark_shareable(self);
71
+ }
72
+
73
+ VALUE
74
+ containers_publish_native_with_references(
75
+ VALUE self,
76
+ containers_native_reference_validator_t validate_references
77
+ )
78
+ {
79
+ if (!validate_references) {
80
+ rb_raise(rb_eArgError, "native publication requires a reference validator");
81
+ }
82
+ containers_check_native_publication_target(self);
83
+ validate_references(self);
84
+ return farce_ruby_mark_shareable(self);
85
+ }
86
+
87
+ VALUE
88
+ containers_raise_unfreezable(VALUE self)
89
+ {
90
+ rb_raise(rb_eTypeError, "%s cannot be frozen", rb_obj_classname(self));
91
+ }
92
+
93
+ VALUE
94
+ containers_normalize_string_key(VALUE key)
95
+ {
96
+ VALUE stored_key;
97
+
98
+ if (!RB_TYPE_P(key, T_STRING)) return key;
99
+ if (rb_obj_class(key) == rb_cString) return rb_str_to_interned_str(key);
100
+
101
+ /* Preserve String subclasses and their instance state without dispatching
102
+ * overridable duplication or freezing methods. */
103
+ stored_key = rb_obj_alloc(rb_obj_class(key));
104
+ rb_str_replace(stored_key, key);
105
+ {
106
+ VALUE instance_variables = rb_obj_instance_variables(key);
107
+ long index;
108
+
109
+ for (index = 0; index < RARRAY_LEN(instance_variables); index++) {
110
+ ID id = SYM2ID(RARRAY_AREF(instance_variables, index));
111
+ rb_ivar_set(stored_key, id, rb_ivar_get(key, id));
112
+ }
113
+ RB_GC_GUARD(instance_variables);
114
+ }
115
+ rb_obj_freeze(stored_key);
116
+ return stored_key;
117
+ }
118
+
119
+ #ifdef _WIN32
120
+ typedef struct {
121
+ int fd;
122
+ bool readable;
123
+ int error;
124
+ } containers_read_context_t;
125
+
126
+ static void *
127
+ containers_poll_without_gvl(void *opaque)
128
+ {
129
+ containers_read_context_t *context = opaque;
130
+ intptr_t descriptor = _get_osfhandle(context->fd);
131
+ if (descriptor == -1) {
132
+ context->error = EBADF;
133
+ return NULL;
134
+ }
135
+
136
+ DWORD available = 0;
137
+ if (!PeekNamedPipe((HANDLE)descriptor, NULL, 0, NULL, &available, NULL)) {
138
+ context->error = EIO;
139
+ return NULL;
140
+ }
141
+ /* Match rb_io_wait: observe readiness without consuming the notification.
142
+ * The caller owns its notification's lifetime and cleanup. */
143
+ context->readable = available > 0;
144
+ return NULL;
145
+ }
146
+
147
+ RUBY_EXTERN void rb_objspace_reachable_objects_from(VALUE, void (*)(VALUE, void *), void *);
148
+
149
+ void
150
+ containers_wait_safepoint(void)
151
+ {
152
+ /* A Windows VM-barrier interrupt can target a sleeping sibling thread.
153
+ * Checking only this thread's interrupts then misses the pending barrier.
154
+ * The exported reachability API acquires the VM lock and joins that barrier.
155
+ * nil has no children, so this does not traverse, allocate, or collect. */
156
+ rb_objspace_reachable_objects_from(Qnil, NULL, NULL);
157
+ }
158
+
159
+ static void *
160
+ containers_sleep_without_gvl(void *opaque)
161
+ {
162
+ (void)opaque;
163
+ /* SleepEx rounds short waits to the system timer tick. Keep pipe handoffs
164
+ * responsive without changing the process-wide timer resolution. */
165
+ HANDLE timer = CreateWaitableTimerExW(
166
+ NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
167
+ TIMER_MODIFY_STATE | SYNCHRONIZE
168
+ );
169
+ if (timer) {
170
+ LARGE_INTEGER due = {.QuadPart = -10000}; /* One millisecond. */
171
+ bool armed = SetWaitableTimer(timer, &due, 0, NULL, NULL, FALSE);
172
+ DWORD result = armed ? WaitForSingleObject(timer, 10) : WAIT_FAILED;
173
+ /* Close before returning to Ruby, which may deliver an interrupt. */
174
+ CloseHandle(timer);
175
+ if (result != WAIT_FAILED) return NULL;
176
+ }
177
+ /* Ruby redirects Sleep to rb_w32_Sleep, which requires the GVL. */
178
+ SleepEx(1, FALSE);
179
+ return NULL;
180
+ }
181
+ #endif
182
+
183
+ /* Called only after releasing the container's native mutex. GC and scheduler
184
+ * callbacks can run Ruby, mutate the container, or raise. The caller must
185
+ * recheck its condition and original deadline after every return. */
186
+ void
187
+ containers_wait_without_descriptor(int error, const char *operation, bool *collected, VALUE timeout)
188
+ {
189
+ if (error != EMFILE && error != ENFILE) {
190
+ errno = error;
191
+ rb_sys_fail(operation);
192
+ }
193
+ if (!*collected) {
194
+ *collected = true;
195
+ rb_gc_start();
196
+ return;
197
+ }
198
+
199
+ /* Descriptor pressure must not turn a cooperative fiber wait into a
200
+ * whole-thread block. Timed polling needs no new notification descriptor
201
+ * and lets a producer on the same scheduler make progress. */
202
+ double seconds = 0.001;
203
+ if (!NIL_P(timeout)) {
204
+ double remaining = NUM2DBL(timeout);
205
+ if (remaining <= 0) return;
206
+ if (remaining < seconds) seconds = remaining;
207
+ }
208
+ VALUE scheduler = rb_fiber_scheduler_current();
209
+ if (!NIL_P(scheduler)) {
210
+ rb_fiber_scheduler_kernel_sleep(scheduler, DBL2NUM(seconds));
211
+ }
212
+ else {
213
+ struct timeval interval = {.tv_sec = 0, .tv_usec = (int)ceil(seconds * 1000000)};
214
+ rb_thread_wait_for(interval);
215
+ }
216
+ }
217
+
218
+ static VALUE
219
+ containers_io_wait(VALUE opaque)
220
+ {
221
+ VALUE *arguments = (VALUE *)opaque;
222
+ return rb_io_wait(arguments[0], INT2NUM(RUBY_IO_READABLE), arguments[1]);
223
+ }
224
+
225
+ static VALUE
226
+ containers_io_close(VALUE opaque)
227
+ {
228
+ VALUE *arguments = (VALUE *)opaque;
229
+ return rb_io_close(arguments[0]);
230
+ }
231
+
232
+ bool
233
+ containers_wait_for_readable(int fd, VALUE timeout)
234
+ {
235
+ #ifdef _WIN32
236
+ /* Blocking CRT pipe reads do not reliably unblock on Thread#kill.
237
+ * Use short no-GVL probes even for indefinite waits so Ruby can deliver
238
+ * interrupts between slices and run the caller's waiter cleanup.
239
+ * Scheduler-backed waits retain rb_io_wait integration. */
240
+ if (NIL_P(rb_fiber_scheduler_current())) {
241
+ double seconds = NIL_P(timeout) ? 0 : NUM2DBL(timeout);
242
+ bool finite = !NIL_P(timeout);
243
+ ULONGLONG deadline = GetTickCount64() + (ULONGLONG)ceil(seconds * 1000);
244
+ containers_read_context_t context = {
245
+ .fd = fd,
246
+ .readable = false,
247
+ .error = 0,
248
+ };
249
+ for (;;) {
250
+ context.readable = false;
251
+ context.error = 0;
252
+ rb_thread_call_without_gvl(
253
+ containers_poll_without_gvl,
254
+ &context,
255
+ NULL,
256
+ NULL
257
+ );
258
+ if (context.error) {
259
+ errno = context.error;
260
+ rb_sys_fail("PeekNamedPipe");
261
+ }
262
+ if (context.readable) return true;
263
+ if (finite && GetTickCount64() >= deadline) return false;
264
+ containers_wait_safepoint();
265
+ rb_thread_call_without_gvl(
266
+ containers_sleep_without_gvl,
267
+ NULL,
268
+ NULL,
269
+ NULL
270
+ );
271
+ }
272
+ }
273
+ #endif
274
+
275
+ VALUE arguments[] = {
276
+ rb_io_open_descriptor(
277
+ rb_cIO,
278
+ fd,
279
+ FMODE_READABLE | FMODE_EXTERNAL,
280
+ Qnil,
281
+ Qnil,
282
+ NULL
283
+ ),
284
+ timeout,
285
+ };
286
+ VALUE result = rb_ensure(
287
+ containers_io_wait,
288
+ (VALUE)arguments,
289
+ containers_io_close,
290
+ (VALUE)arguments
291
+ );
292
+ RB_GC_GUARD(arguments[0]);
293
+ return RTEST(result);
294
+ }
295
+
296
+ void
297
+ containers_raise_key_error(VALUE receiver, VALUE key)
298
+ {
299
+ VALUE message = rb_sprintf("key not found: %" PRIsVALUE, rb_inspect(key));
300
+ VALUE keywords = rb_hash_new();
301
+ rb_hash_aset(keywords, ID2SYM(rb_intern("receiver")), receiver);
302
+ rb_hash_aset(keywords, ID2SYM(rb_intern("key")), key);
303
+ VALUE arguments[] = {message, keywords};
304
+ VALUE exception = rb_class_new_instance_kw(2, arguments, rb_eKeyError, RB_PASS_KEYWORDS);
305
+ rb_exc_raise(exception);
306
+ }
307
+
308
+ static VALUE
309
+ farce_load_native_fiber_scheduler(VALUE namespace)
310
+ {
311
+ farce_init_fiber_scheduler(namespace);
312
+ return Qnil;
313
+ }
314
+
315
+ #if RUBY_API_VERSION_CODE == 30400
316
+ static VALUE
317
+ farce_lock_native_thread(VALUE namespace)
318
+ {
319
+ rb_thread_lock_native_thread();
320
+ return Qnil;
321
+ }
322
+ #endif
323
+
324
+ RUBY_FUNC_EXPORTED void
325
+ Init_farce(void)
326
+ {
327
+ rb_ext_ractor_safe(true);
328
+ VALUE mFarce = rb_const_get(rb_cObject, rb_intern("Farce"));
329
+ VALUE mInternal = rb_const_get(mFarce, rb_intern("Internal"));
330
+ VALUE singleton = rb_singleton_class(mInternal);
331
+ eIsolationError = rb_const_get(rb_cRactor, rb_intern("IsolationError"));
332
+ #if RUBY_API_VERSION_CODE == 30400
333
+ rb_define_singleton_method(mInternal, "lock_native_thread", farce_lock_native_thread, 0);
334
+ #endif
335
+ rb_define_private_method(
336
+ singleton,
337
+ "load_native_fiber_scheduler",
338
+ farce_load_native_fiber_scheduler,
339
+ 0
340
+ );
341
+ containers_init_transaction(mInternal);
342
+ containers_init_atom(mInternal);
343
+ containers_init_counter(mInternal);
344
+ containers_init_exchanger(mInternal);
345
+ containers_init_flag(mInternal);
346
+ containers_init_lock(mInternal);
347
+ containers_init_lru_maps(mInternal);
348
+ containers_init_map(mInternal);
349
+ containers_init_priority_queue(mInternal);
350
+ containers_init_darwin(mInternal);
351
+ containers_init_queue(mInternal);
352
+ containers_init_signal(mInternal);
353
+ containers_init_unshared_signal(mInternal);
354
+ containers_init_unshareable(mInternal);
355
+ containers_init_vector(mInternal);
356
+ containers_init_weak_maps(mInternal);
357
+ containers_init_tree_maps(mInternal);
358
+ containers_init_trie(mInternal);
359
+ }