farce 0.0.1.alpha2-x86-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -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/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. metadata +468 -0
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # A shareable FIFO queue with transfer modes for unshareable values.
7
+ class Queue < Farce::Abstract::Queue
8
+ include Internal::ManagedQueue
9
+ include Shareable::Unfreezable
10
+
11
+ # (see Farce::Abstract::Queue#initialize)
12
+ # @!macro modes
13
+ # @param mode [Symbol] the default mode for sending unshareable values
14
+ def initialize(capacity: 1024, mode: :copy, track_age: false)
15
+ @manager = ModeManager.new(mode:)
16
+ @queue = Internal::Queue.new(capacity:, track_age:)
17
+ super()
18
+ end
19
+
20
+ # (see Farce::Abstract::Queue#push)
21
+ # @!macro modes
22
+ # @param mode [Symbol] the default mode for sending unshareable values
23
+ def push(value, non_block = false, timeout: nil, mode: nil) # rubocop:disable Style/OptionalBooleanParameter
24
+ value = @manager.wrap(value, mode:)
25
+
26
+ if non_block
27
+ return true if @queue.try_push(value)
28
+ raise ThreadError, "queue full"
29
+ end
30
+
31
+ timeout.nil? ? @queue.push(value) : @queue.push(value, timeout:)
32
+ end
33
+
34
+ # (see Farce::Abstract::Queue#try_push)
35
+ # @!macro modes
36
+ # @param mode [Symbol] the default mode for sending unshareable values
37
+ def try_push(value, mode: nil)
38
+ return true if @queue.try_push(@manager.wrap(value, mode:))
39
+ block_given? ? yield : false
40
+ end
41
+
42
+ # (see Farce::Abstract::Queue#pop)
43
+ def pop(non_block = false, timeout: nil) # rubocop:disable Style/OptionalBooleanParameter
44
+ return try_pop { raise ThreadError, "queue empty" } if non_block
45
+
46
+ empty = false
47
+ result = timeout.nil? ? @queue.pop { empty = true } : @queue.pop(timeout:) { empty = true }
48
+ return @manager.unwrap(result) unless empty
49
+ yield if block_given?
50
+ end
51
+
52
+ # (see Farce::Abstract::Queue#try_pop)
53
+ def try_pop
54
+ empty = false
55
+ result = @queue.try_pop { empty = true }
56
+ return @manager.unwrap(result) unless empty
57
+ yield if block_given?
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,269 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # Entry point for Ractor support.
7
+ #
8
+ # This is always a module, but if native Ractor support is available:
9
+ # * It gets mixed into Ractor. This has no effect beyond another entry in the inheritance chain,
10
+ # so `is_a?(Farce::Ractor)` and `Farce::Ractor === ractor` work as expected.
11
+ # * It delegates, wraps, or backports known Ractor class methods.
12
+ #
13
+ # If not, then this module provides a polyfill for Ractors. With the following caveats:
14
+ # * It uses thread groups to keep track of Thread-to-Ractor associations.
15
+ # * All objects are considered shareable.
16
+ # * It does not monkey-patch `Thread`. This means in particular:
17
+ # * `Thread.list` will include all threads from all Ractors.
18
+ # Use {.threads Farce::Ractor.threads} instead.
19
+ # * `Thread.main` will return the main thread of the main Ractor, even if called from a different Ractor.
20
+ # Use {.main_thread Farce::Ractor.main_thread} instead.
21
+ #
22
+ # @!method [](key)
23
+ # @!scope class
24
+ # Retrieves a value from the current Ractor's storage by key.
25
+ # @param key [Symbol] The key to retrieve.
26
+ # @return [BasicObject, nil] The value associated with the key, or `nil` if not found.
27
+ #
28
+ # @!method []=(key, value)
29
+ # @!scope class
30
+ # Stores a value in the current Ractor's storage by key.
31
+ # @param key [Symbol] The key to store the value under.
32
+ # @param value [BasicObject] The value to store.
33
+ #
34
+ # @!method builtin?
35
+ # @!scope class
36
+ # @note This method isn't part of the official Ractor API, but is compatible with the `ractor-shim` gem.
37
+ # @return [Boolean] `true` if native Ractors are available, `false` otherwise.
38
+ #
39
+ # @!method count
40
+ # @!scope class
41
+ # Returns the number of Ractors.
42
+ # @return [Integer] The number of Ractors.
43
+ #
44
+ # @!method current
45
+ # @!scope class
46
+ # Returns the current Ractor instance.
47
+ # @return [Ractor] The current Ractor instance.
48
+ #
49
+ # @!method main
50
+ # @!scope class
51
+ # Returns the main Ractor instance.
52
+ # @return [Ractor] The main Ractor instance.
53
+ #
54
+ # @!method make_shareable(object, copy: false)
55
+ # @!scope class
56
+ # @note If native Ractors aren't available, this method simply returns the object, as all objects are shareable.
57
+ # Makes an object shareable between Ractors.
58
+ # @param object [BasicObject] The object to make shareable.
59
+ # @param copy [Boolean] Whether to create a copy of the object.
60
+ # @return [BasicObject] The shareable object.
61
+ #
62
+ # @!method main?
63
+ # @!scope class
64
+ # Checks if the current Ractor is the main Ractor.
65
+ # @return [Boolean] `true` if the current Ractor is the main Ractor, `false` otherwise.
66
+ #
67
+ # @!method main_thread
68
+ # @!scope class
69
+ # @note This method is not part of the official Ractor API, but is a replacement for a Ractor-unaware `Thread.main`.
70
+ # Returns the main thread of the current Ractor.
71
+ # @return [Thread] The main thread of the current Ractor.
72
+ #
73
+ # @!method new(*args, name: nil)
74
+ # @!scope class
75
+ # Creates a new Ractor instance.
76
+ # @param args [Array] The arguments to pass to the Ractor's block. Will be copied if not {.shareable? shareable}.
77
+ # @param name [String, nil] The name of the Ractor, or `nil` for no name.
78
+ # @yield [*args] The block to execute in the new Ractor.
79
+ # @yieldparam args [Array] The arguments passed to the Ractor.
80
+ # @yieldreturn [BasicObject] The {#value value} returned by the Ractor's block.
81
+ # @yieldreceiver [Ractor] The new Ractor instance.
82
+ # @return [Ractor] The new Ractor instance.
83
+ #
84
+ # @!method receive(timeout: nil)
85
+ # @!scope class
86
+ # Receives a message on the current Ractor's {#default_port default port}.
87
+ # @param timeout [Numeric, nil] The timeout in seconds, or `nil` for no timeout.
88
+ # @return [BasicObject, nil] The received message, or `nil` if the timeout has been reached.
89
+ #
90
+ # @!method select(*ractors_or_ports, timeout: nil)
91
+ # @!scope class
92
+ # Blocks the current Thread until one of the given Ractors or Ports produces a value, or until the timeout
93
+ # has been reached.
94
+ #
95
+ # Returns an array containing the Ractor or Port that produced the value, and the value itself.
96
+ # Or `nil` if the timeout has been reached.
97
+ #
98
+ # @param ractors_or_ports [Array<Ractor, Farce::Abstract::Port>] The Ractors or Ports to select from.
99
+ # @param timeout [Numeric, nil] The timeout in seconds, or `nil` for no timeout.
100
+ # @return [Array(Object, BasicObject), nil]
101
+ # An array containing the Ractor or Port that produced the value, and the value itself,
102
+ # or `nil` if the timeout has been reached.
103
+ #
104
+ # @!method shareable?(object)
105
+ # @!scope class
106
+ # @note If native Ractors aren't available, this method always returns `true`, as all objects are shareable.
107
+ # Checks if an object is shareable between Ractors.
108
+ # @param object [BasicObject] The object to check.
109
+ # @return [Boolean] `true` if the object is shareable, `false` otherwise.
110
+ #
111
+ # @!method shareable_lambda(self: nil)
112
+ # @!scope class
113
+ # {Farce.rebind Binds} a lambda to the given `self` and {.make_shareable makes it shareable} between Ractors.
114
+ # @yield The block to convert into a shareable lambda.
115
+ # @yieldreceiver [BasicObject] The object passed as `self` (or `nil`)
116
+ # @param self [BasicObject] The object to bind as `self`.
117
+ # @return [Proc] The shareable lambda.
118
+ # @see .shareable_proc
119
+ #
120
+ # @!method shareable_proc(self: nil)
121
+ # @!scope class
122
+ # {Farce.rebind Binds} a proc to the given `self` and {.make_shareable makes it shareable} between Ractors.
123
+ # @yield The block to convert into a shareable proc.
124
+ # @yieldreceiver [BasicObject] The object passed as `self` (or `nil`)
125
+ # @param self [BasicObject] The object to bind as `self`.
126
+ # @return [Proc] The shareable proc.
127
+ # @see .shareable_lambda
128
+ #
129
+ # @!method shim?
130
+ # @!scope class
131
+ # @note This method isn't part of the official Ractor API, but is compatible with the `ractor-shim` gem.
132
+ # @return [Boolean] `false` if native Ractors are available, `true` otherwise.
133
+ #
134
+ # @!method store_if_absent(key)
135
+ # @!scope class
136
+ # Stores a value in the current Ractor's storage by key if it is not already present. This method is thread-safe.
137
+ # @param key [Symbol] The key to store the value under.
138
+ # @yield Block that computes the value to store if the key is absent.
139
+ # @yieldreturn [BasicObject] The value to store if the key is absent.
140
+ # @return [BasicObject] The existing or newly stored value.
141
+ #
142
+ # @!method threads
143
+ # @!scope class
144
+ # @note This method isn't part of the official Ractor API, but is a replacement for a Ractor-unaware `Thread.list`.
145
+ # Returns the list of threads in the current Ractor.
146
+ # @return [Array<Thread>] The list of threads in the current Ractor.
147
+ #
148
+ # @!method default_port
149
+ # @return [Ractor::Port] The default port for the Ractor.
150
+ #
151
+ # @!method join
152
+ # Blocks the current Thread until the Ractor has terminated.
153
+ # @return [self]
154
+ #
155
+ # @!method main?
156
+ # @return [Boolean] `true` if the Ractor is the main Ractor
157
+ #
158
+ # @!method monitor(port)
159
+ # Monitors the given port for termination of the Ractor. If the Ractor is already terminated, the port will receive
160
+ # the Ractor's status immediately. The port will receive wither `:exited` or `:aborted` depending on whether the
161
+ # Ractor terminated normally or with an unhandled exception.
162
+ # @ruby CRuby 4.0+, JRuby, TruffleRuby
163
+ # @param port [Ractor::Port] The port to monitor.
164
+ # @return [Boolean]
165
+ # `true` if the Ractor is running and the port was successfully monitored,
166
+ # `false` if the Ractor is already terminated and the port received the Ractor's status.
167
+ # @see #unmonitor
168
+ #
169
+ # @!method unmonitor(port)
170
+ # Stops monitoring the given port for termination of the Ractor. If the port was not being monitored, this method
171
+ # has no effect.
172
+ # @ruby CRuby 4.0+, JRuby, TruffleRuby
173
+ # @return [self]
174
+ # @see #monitor
175
+ #
176
+ # @!method name
177
+ # @return [String, nil] The name of the Ractor, or `nil` if it has no name.
178
+ #
179
+ # @!method receive(timeout: nil)
180
+ # Receives a message on the Ractor's {#default_port default port}.
181
+ # @param timeout [Numeric, nil] The timeout in seconds, or `nil` for no timeout.
182
+ # @return [BasicObject, nil] The received message, or `nil` if the timeout has been reached.
183
+ #
184
+ # @!method send(message, move: false)
185
+ # Sends a message to the Ractor's {#default_port default port}.
186
+ # @param message [BasicObject] The message to send.
187
+ # @param move [Boolean] Whether to move the message to the Ractor if it isn't sharable.
188
+ # @return [self]
189
+ #
190
+ # @!method name
191
+ # @return [String, nil] The name of the Ractor, or `nil` if it has no name.
192
+ #
193
+ # @!method receive(timeout: nil)
194
+ # Receives a message on the Ractor's {#default_port default port}.
195
+ # @param timeout [Numeric, nil] The timeout in seconds, or `nil` for no timeout.
196
+ # @return [BasicObject, nil] The received message, or `nil` if the timeout has been reached.
197
+ #
198
+ # @!method send(message, move: false)
199
+ # Sends a message to the Ractor's {#default_port default port}.
200
+ # @param message [BasicObject] The message to send.
201
+ # @param move [Boolean] Whether to move the message to the Ractor if it isn't sharable.
202
+ # @return [self]
203
+ #
204
+ # @!method value
205
+ # Blocks the current Thread until the Ractor has terminated, and returns the value returned by the
206
+ # Ractor's block. Will re-raise any unhandled exception raised in the Ractor's block.
207
+ # @ruby CRuby 4.0+, JRuby, TruffleRuby
208
+ # @return [BasicObject] The value returned by the Ractor's block.
209
+ #
210
+ # @!method take
211
+ # @deprecated
212
+ # This method only exists on CRuby 3.x (outdated Ractor API). Use {#value} if you don't have to support
213
+ # CRuby 3.x, or use {Farce::Port}.
214
+ # Receives a message from the Ractor. This may be the ractor's return value.
215
+ # @ruby CRuby 3.x
216
+ # @return [BasicObject] The received message.
217
+ module Ractor
218
+ include Internal::MarshalSupport::Reject
219
+ ::Ractor.include(self) if Internal.native_ractors?
220
+
221
+ # @!parse
222
+ # # @!scope class
223
+ # alias recv receive
224
+ # alias recv receive
225
+ # alias << send
226
+
227
+ # Either `Ractor::Error` or a subclass of `RuntimeError` if native Ractors are not available.
228
+ # @!macro RactorError_note
229
+ # Will pick up an error class defined by a shim/polyfill if one is loaded,
230
+ # like [ractor-shim](https://github.com/eregon/ractor-shim).
231
+ Error = defined?(::Ractor::Error) ? ::Ractor::Error : Class.new(RuntimeError)
232
+
233
+ # Either `Ractor::ClosedError` or a subclass of `StopIteration` if native Ractors are not available.
234
+ # @!macro RactorError_note
235
+ ClosedError = defined?(::Ractor::ClosedError) ? ::Ractor::ClosedError : Class.new(StopIteration)
236
+
237
+ # Either `Ractor::IsolationError` or a subclass of {Error} if native Ractors are not available.
238
+ # @!macro RactorError_note
239
+ IsolationError = defined?(::Ractor::IsolationError) ? ::Ractor::IsolationError : Class.new(Error)
240
+
241
+ # Either `Ractor::MovedError` or a subclass of {Error} if native Ractors are not available.
242
+ # @!macro RactorError_note
243
+ MovedError = defined?(::Ractor::MovedError) ? ::Ractor::MovedError : Class.new(Error)
244
+
245
+ # Either `Ractor::RemoteError` or a subclass of {Error} if native Ractors are not available.
246
+ # @!macro RactorError_note
247
+ RemoteError = defined?(::Ractor::RemoteError) ? ::Ractor::RemoteError : Class.new(Error)
248
+
249
+ # Either `Ractor::UnsafeError` or a subclass of {Error} if native Ractors are not available.
250
+ # @!macro RactorError_note
251
+ UnsafeError = defined?(::Ractor::UnsafeError) ? ::Ractor::UnsafeError : Class.new(Error)
252
+
253
+ # Either `Ractor::MovedObject` or a subclass of `BasicObject` if native Ractors are not available.
254
+ # Cannot be instantiated directly, but can be used to check if an object has been moved to another Ractor.
255
+ MovedObject = defined?(::Ractor::MovedObject) ? ::Ractor::MovedObject :
256
+ Class.new(BasicObject) { def self.new(...) = raise TypeError, "allocator undefined for #{inspect}" }
257
+
258
+ extend Internal::RactorMethods
259
+
260
+ def self.const_missing(name) = name == :Port ? Internal::BasePort : super
261
+ private_class_method :const_missing
262
+
263
+ # @!visibility private
264
+ def self.included(base)
265
+ return if base.const_defined?(:Port, false)
266
+ base.const_set(:Port, Internal::BasePort)
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,256 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # A Ractor-shareable read/write lock with fiber-scheduler-aware waiting.
7
+ #
8
+ # Multiple execution contexts may hold the read lock concurrently. The write
9
+ # lock is exclusive and may be acquired while the current context holds a
10
+ # read lock. One concurrent upgrader retains its read lock continuously.
11
+ # Additional upgraders yield their read slot to avoid deadlock and restore it
12
+ # before returning to the outer read-lock block.
13
+ class ReadWriteLock
14
+ include Internal::MarshalSupport::Reject
15
+ include Internal::Copyable
16
+ include Shareable::Unfreezable
17
+
18
+ READER_BITS = 30
19
+ READER_MASK = (1 << READER_BITS) - 1
20
+ WRITER_BIT = 1 << READER_BITS
21
+ UPGRADER_BIT = 1 << (READER_BITS + 1)
22
+ WAITER_UNIT = 1 << (READER_BITS + 2)
23
+ MAX_WAITERS = ((1 << 63) - 1) / WAITER_UNIT
24
+ READ_DEPTH = 0
25
+ WRITE_DEPTH = 1
26
+ LOCAL_STATES = :__farce_read_write_lock_states__
27
+ INTERRUPTS_IMMEDIATE = { Exception => :immediate }.freeze
28
+ private_constant :READER_BITS, :READER_MASK, :WRITER_BIT, :UPGRADER_BIT,
29
+ :WAITER_UNIT, :MAX_WAITERS, :READ_DEPTH, :WRITE_DEPTH, :LOCAL_STATES,
30
+ :INTERRUPTS_IMMEDIATE
31
+
32
+ def initialize
33
+ @state = Internal::Vector.new([0])
34
+ @signal = Internal::Signal.new
35
+ super
36
+ end
37
+
38
+ # Runs the block while holding a shared read lock.
39
+ #
40
+ # @yield the block to run while holding the read lock
41
+ # @return [Object] the block result
42
+ def with_read_lock
43
+ raise LocalJumpError, "no block given" unless block_given?
44
+
45
+ local = local_state
46
+ Thread.handle_interrupt(Internal::INTERRUPT_MASK) do
47
+ global = local[READ_DEPTH].zero? && local[WRITE_DEPTH].zero?
48
+ acquire_read_lock if global
49
+ local[READ_DEPTH] += 1
50
+
51
+ begin
52
+ # Block capture allocates on every lock operation.
53
+ # rubocop:disable-next Style/ExplicitBlockArgument
54
+ Thread.handle_interrupt(INTERRUPTS_IMMEDIATE) { yield }
55
+ ensure
56
+ local[READ_DEPTH] -= 1
57
+ release_read_lock if global
58
+ clear_local_state(local)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Runs the block while holding an exclusive write lock.
64
+ #
65
+ # Calling this method from inside {#with_read_lock} upgrades the read lock.
66
+ #
67
+ # @yield the block to run while holding the write lock
68
+ # @return [Object] the block result
69
+ def with_write_lock
70
+ raise LocalJumpError, "no block given" unless block_given?
71
+
72
+ local = local_state
73
+ Thread.handle_interrupt(Internal::INTERRUPT_MASK) do
74
+ reentrant = local[WRITE_DEPTH].positive?
75
+ upgraded = !reentrant && local[READ_DEPTH].positive?
76
+ acquire_write_lock(upgraded) unless reentrant
77
+ local[WRITE_DEPTH] += 1
78
+
79
+ begin
80
+ # Block capture allocates on every lock operation.
81
+ # rubocop:disable-next Style/ExplicitBlockArgument
82
+ Thread.handle_interrupt(INTERRUPTS_IMMEDIATE) { yield }
83
+ ensure
84
+ local[WRITE_DEPTH] -= 1
85
+ unless reentrant
86
+ upgraded ? downgrade_write_lock : release_write_lock
87
+ end
88
+ clear_local_state(local)
89
+ end
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def initialize_copy(other)
96
+ super
97
+ @state = Internal::Vector.new([0])
98
+ @signal = Internal::Signal.new
99
+ end
100
+
101
+ def local_state
102
+ states = Thread.current[LOCAL_STATES] ||= {}
103
+ states[self] ||= [0, 0]
104
+ end
105
+
106
+ def clear_local_state(local)
107
+ return unless local[READ_DEPTH].zero? && local[WRITE_DEPTH].zero?
108
+
109
+ states = Thread.current[LOCAL_STATES]
110
+ states.delete(self)
111
+ Thread.current[LOCAL_STATES] = nil if states.empty?
112
+ end
113
+
114
+ def acquire_read_lock
115
+ return if try_acquire_read_lock
116
+
117
+ # Kernel.loop allocates on every acquisition.
118
+ while true
119
+ generation = @signal.generation
120
+ return if try_acquire_read_lock
121
+
122
+ wait_for_change(generation)
123
+ end
124
+ end
125
+
126
+ def try_acquire_read_lock
127
+ change_state do |current|
128
+ if readers_allowed?(current)
129
+ raise ThreadError, "maximum reader count exceeded" if reader_count(current) == READER_MASK
130
+ [current + 1, true]
131
+ else
132
+ [current, false]
133
+ end
134
+ end
135
+ end
136
+
137
+ def release_read_lock
138
+ change_state do |current|
139
+ raise ThreadError, "read lock is not held" if reader_count(current).zero?
140
+ [current - 1, nil]
141
+ end
142
+ @signal.broadcast
143
+ end
144
+
145
+ def acquire_write_lock(upgrade)
146
+ mode = upgrade ? register_upgrade : register_writer
147
+ acquired = false
148
+
149
+ begin
150
+ acquired = try_acquire_write_lock(mode)
151
+ return if acquired
152
+
153
+ # Kernel.loop allocates on every acquisition.
154
+ while true
155
+ generation = @signal.generation
156
+ acquired = try_acquire_write_lock(mode)
157
+ return if acquired
158
+
159
+ wait_for_change(generation)
160
+ end
161
+ ensure
162
+ cancel_write_request(mode) unless acquired
163
+ end
164
+ end
165
+
166
+ def try_acquire_write_lock(mode)
167
+ change_state do |current|
168
+ retained = mode == :retained
169
+ target_readers = retained ? 1 : 0
170
+ available = !writer_locked?(current) && reader_count(current) == target_readers
171
+ available &&= upgrader?(current) if retained
172
+
173
+ if available
174
+ replacement = current - WAITER_UNIT + WRITER_BIT
175
+ replacement -= UPGRADER_BIT + 1 if retained
176
+ [replacement, true]
177
+ else
178
+ [current, false]
179
+ end
180
+ end
181
+ end
182
+
183
+ def register_writer
184
+ change_state { |current| [add_waiter(current), :writer] }
185
+ end
186
+
187
+ def register_upgrade
188
+ mode = change_state do |current|
189
+ raise ThreadError, "read lock is not held" if reader_count(current).zero?
190
+
191
+ if upgrader?(current)
192
+ [add_waiter(current) - 1, :released]
193
+ else
194
+ [add_waiter(current) + UPGRADER_BIT, :retained]
195
+ end
196
+ end
197
+ @signal.broadcast if mode == :released
198
+ mode
199
+ end
200
+
201
+ def cancel_write_request(mode)
202
+ case mode
203
+ when :retained
204
+ change_state { |current| [current - WAITER_UNIT - UPGRADER_BIT, nil] }
205
+ when :released, :writer
206
+ change_state { |current| [current - WAITER_UNIT, nil] }
207
+ end
208
+ @signal.broadcast
209
+ acquire_read_lock if mode == :released
210
+ end
211
+
212
+ def release_write_lock
213
+ change_state do |current|
214
+ raise ThreadError, "write lock is not held" unless writer_locked?(current)
215
+ [current - WRITER_BIT, nil]
216
+ end
217
+ @signal.broadcast
218
+ end
219
+
220
+ def downgrade_write_lock
221
+ change_state do |current|
222
+ raise ThreadError, "write lock is not held" unless writer_locked?(current)
223
+ [current - WRITER_BIT + 1, nil]
224
+ end
225
+ @signal.broadcast
226
+ end
227
+
228
+ def change_state
229
+ result = nil
230
+ @state.update(0) do |current|
231
+ replacement, result = yield(current)
232
+ replacement
233
+ end
234
+ result
235
+ end
236
+
237
+ def wait_for_change(generation)
238
+ Thread.handle_interrupt(INTERRUPTS_IMMEDIATE) { @signal.wait(generation) }
239
+ end
240
+
241
+ def add_waiter(current)
242
+ raise ThreadError, "maximum writer count exceeded" if waiting_writers(current) == MAX_WAITERS
243
+ current + WAITER_UNIT
244
+ end
245
+
246
+ def readers_allowed?(current)
247
+ !writer_locked?(current) && waiting_writers(current).zero?
248
+ end
249
+
250
+ def reader_count(current) = current & READER_MASK
251
+ def waiting_writers(current) = current / WAITER_UNIT
252
+ def writer_locked?(current) = current.anybits?(WRITER_BIT)
253
+ def upgrader?(current) = current.anybits?(UPGRADER_BIT)
254
+ def instance_variables_to_inspect = Internal::EMPTY_ARRAY
255
+ end
256
+ end