farce 0.3.0-java → 0.4.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +117 -1489
- data/docs/compatibility.md +74 -0
- data/docs/concurrency.md +151 -0
- data/docs/data-structures.md +313 -0
- data/docs/installation.md +63 -0
- data/docs/integrations.md +124 -0
- data/docs/introduction.md +266 -0
- data/docs/scheduling.md +176 -0
- data/docs/sharing.md +211 -0
- data/docs/shims.md +144 -0
- data/docs/utilities.md +93 -0
- data/docs/variants-and-scopes.md +92 -0
- data/lib/farce/abstract/flag.rb +6 -0
- data/lib/farce/backports.rb +274 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +3 -0
- data/lib/farce/engine/jruby/scheduler_synchronization.rb +87 -0
- data/lib/farce/engine/ruby/3.4/null_port.rb +21 -0
- data/lib/farce/engine/ruby/3.4/patch.rb +67 -0
- data/lib/farce/engine/ruby/3.4/port.rb +13 -12
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +0 -1
- data/lib/farce/engine/ruby/4.0/null_port.rb +36 -0
- data/lib/farce/engine/ruby/4.0/port.rb +1 -2
- data/lib/farce/engine/ruby/4.1/null_port.rb +5 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/null_port.rb +18 -0
- data/lib/farce/engine/shared/port.rb +41 -3
- data/lib/farce/engine/shared/queue.rb +4 -4
- data/lib/farce/engine/shared/ractor_methods.rb +2 -2
- data/lib/farce/engine/shared/ractor_selector.rb +73 -0
- data/lib/farce/extension.rb +150 -0
- data/lib/farce/integrations/ractor_tmvar.rb +4 -1
- data/lib/farce/internal/fake_ractor.rb +10 -2
- data/lib/farce/internal/scheduler_lifecycle.rb +7 -4
- data/lib/farce/null_port.rb +12 -0
- data/lib/farce/system.rb +10 -2
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +1 -1
- metadata +23 -2
|
@@ -10,11 +10,19 @@ module Farce
|
|
|
10
10
|
include MarshalSupport::Reject
|
|
11
11
|
include Freeze::Unfreezable
|
|
12
12
|
|
|
13
|
-
def initialize
|
|
14
|
-
|
|
13
|
+
def initialize
|
|
14
|
+
@queue = Thread::Queue.new
|
|
15
|
+
@select_mutex = Mutex.new
|
|
16
|
+
@select_waiters = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def closed? = @queue.closed?
|
|
15
20
|
|
|
16
21
|
def close
|
|
17
|
-
@
|
|
22
|
+
@select_mutex.synchronize do
|
|
23
|
+
@queue.close
|
|
24
|
+
@select_waiters.each(&:broadcast)
|
|
25
|
+
end
|
|
18
26
|
self
|
|
19
27
|
end
|
|
20
28
|
|
|
@@ -29,14 +37,44 @@ module Farce
|
|
|
29
37
|
raise Ractor::Error, "can not move #{value.class} object" unless value.is_a?(Unshareable::Movable)
|
|
30
38
|
end
|
|
31
39
|
@queue.push(value)
|
|
40
|
+
notify_selectors
|
|
32
41
|
self
|
|
33
42
|
rescue ::ClosedQueueError
|
|
34
43
|
raise Ractor::ClosedError, "The port was already closed"
|
|
35
44
|
end
|
|
36
45
|
|
|
46
|
+
# @api private
|
|
47
|
+
def register_selector(waiter)
|
|
48
|
+
@select_mutex.synchronize { @select_waiters << waiter }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @api private
|
|
52
|
+
def unregister_selector(waiter)
|
|
53
|
+
@select_mutex.synchronize { @select_waiters.delete(waiter) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @api private
|
|
57
|
+
def select_receive
|
|
58
|
+
@select_mutex.synchronize do
|
|
59
|
+
raise Ractor::ClosedError, "The port was already closed" if closed?
|
|
60
|
+
begin
|
|
61
|
+
value = @queue.pop(true)
|
|
62
|
+
rescue ThreadError
|
|
63
|
+
return
|
|
64
|
+
end
|
|
65
|
+
[self, value]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
37
69
|
alias << send
|
|
38
70
|
|
|
39
71
|
def inspect = "#<#{self.class.name} to:#1 id:#{object_id}>"
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def notify_selectors
|
|
76
|
+
@select_mutex.synchronize { @select_waiters.each(&:broadcast) }
|
|
77
|
+
end
|
|
40
78
|
end
|
|
41
79
|
|
|
42
80
|
BasePort = Port
|
|
@@ -12,10 +12,10 @@ module Farce
|
|
|
12
12
|
attr_reader :capacity
|
|
13
13
|
|
|
14
14
|
def initialize(capacity: 1024, track_age: false)
|
|
15
|
-
@queue
|
|
16
|
-
@capacity
|
|
17
|
-
@signal
|
|
18
|
-
@tracking
|
|
15
|
+
@queue = capacity ? Thread::SizedQueue.new(capacity) : Thread::Queue.new
|
|
16
|
+
@capacity = capacity
|
|
17
|
+
@signal = Signal.new
|
|
18
|
+
@tracking = track_age ? { lock: Mutex.new, timestamps: [], generation: 0 } : nil
|
|
19
19
|
@lifecycle = { lock: Mutex.new, hard_closed: false }
|
|
20
20
|
Freeze.publish(self)
|
|
21
21
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
# Wait for shim port readiness without consuming messages from losing ports.
|
|
9
|
+
class RactorSelector
|
|
10
|
+
def select(*sources, timeout: nil)
|
|
11
|
+
raise ArgumentError, "specify at least one Ractor::Port or Ractor" if sources.empty?
|
|
12
|
+
sources.each do |source|
|
|
13
|
+
next if source.is_a?(Ractor) || source.is_a?(Port)
|
|
14
|
+
raise ArgumentError, "should be Ractor::Port or Ractor"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
timeout = duration(timeout)
|
|
18
|
+
deadline = Clock.now + timeout if timeout
|
|
19
|
+
monitors = {}.compare_by_identity
|
|
20
|
+
ports = sources.uniq.map do |source|
|
|
21
|
+
next source unless source.is_a?(Ractor)
|
|
22
|
+
|
|
23
|
+
port = BasePort.new
|
|
24
|
+
monitors[port] = source
|
|
25
|
+
source.monitor(port)
|
|
26
|
+
port
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
result = wait(ports, deadline)
|
|
30
|
+
return unless result
|
|
31
|
+
|
|
32
|
+
port, value = result
|
|
33
|
+
ractor = monitors[port]
|
|
34
|
+
ractor ? [ractor, ractor.value] : [port, value]
|
|
35
|
+
ensure
|
|
36
|
+
monitors&.each do |port, ractor|
|
|
37
|
+
ractor.unmonitor(port)
|
|
38
|
+
port.close
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def duration(value)
|
|
45
|
+
return if value.nil?
|
|
46
|
+
raise TypeError, "cannot convert String into time interval" if value.is_a?(String)
|
|
47
|
+
value = Float(value)
|
|
48
|
+
raise RangeError, "timeout out of range" unless value.finite?
|
|
49
|
+
raise ArgumentError, "time interval must not be negative" if value.negative?
|
|
50
|
+
value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def wait(ports, deadline)
|
|
54
|
+
wakeup = Signal.new
|
|
55
|
+
ports.each { it.register_selector(wakeup) }
|
|
56
|
+
while true
|
|
57
|
+
# Observe before checking readiness so a send during that check
|
|
58
|
+
# changes the generation and prevents the following wait from parking.
|
|
59
|
+
generation = wakeup.generation
|
|
60
|
+
ports.each do |port|
|
|
61
|
+
result = port.select_receive
|
|
62
|
+
return result if result
|
|
63
|
+
end
|
|
64
|
+
remaining = deadline - Clock.now if deadline
|
|
65
|
+
return if remaining && !remaining.positive?
|
|
66
|
+
return unless ReservationWaiting.wait(wakeup, generation, deadline)
|
|
67
|
+
end
|
|
68
|
+
ensure
|
|
69
|
+
ports.each { it.unregister_selector(wakeup) }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# Defines a reusable extension for adding methods to target classes.
|
|
7
|
+
# These methods can either be activated as refinements, or installed globally to extend the target classes.
|
|
8
|
+
#
|
|
9
|
+
# ```ruby
|
|
10
|
+
# DoubleSize = Farce::Extension.define(String) do
|
|
11
|
+
# def double_size = size * 2
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# module Namespace
|
|
15
|
+
# using DoubleSize
|
|
16
|
+
# "hello".double_size # => 10
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# "hello".respond_to?(:double_size) # => false
|
|
20
|
+
#
|
|
21
|
+
# DoubleSize.install
|
|
22
|
+
# "hello".respond_to?(:double_size) # => true
|
|
23
|
+
# ```
|
|
24
|
+
#
|
|
25
|
+
# ## Extending multiple classes
|
|
26
|
+
#
|
|
27
|
+
# An extension can also modify multiple target classes simultaneously:
|
|
28
|
+
#
|
|
29
|
+
# ```ruby
|
|
30
|
+
# DoubleSize = Farce::Extension.new do
|
|
31
|
+
# define(String) { def double_size = size * 2 }
|
|
32
|
+
# define(Array) { def double_size = sum(&:double_size) }
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# using DoubleSize
|
|
36
|
+
# ["hello", "foo"].double_size # => 16
|
|
37
|
+
# ```
|
|
38
|
+
class Extension < Module
|
|
39
|
+
# @api private
|
|
40
|
+
class Mixin < Module # :nodoc:
|
|
41
|
+
attr_reader :extension, :target
|
|
42
|
+
|
|
43
|
+
def initialize(extension, target, &)
|
|
44
|
+
@extension = extension
|
|
45
|
+
@target = target
|
|
46
|
+
super(&)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def name = -"#{@extension.name}[#{@target.inspect}]"
|
|
50
|
+
|
|
51
|
+
def install
|
|
52
|
+
return if @target.ancestors.include?(self)
|
|
53
|
+
@target.prepend(self)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
private_constant :Mixin
|
|
57
|
+
|
|
58
|
+
# @overload define(*targets)
|
|
59
|
+
# Defines an extension for the given target classes.
|
|
60
|
+
# @param targets [Array<Class>] the target classes to define methods for
|
|
61
|
+
# @yield the block containing method definitions
|
|
62
|
+
# @yieldreceiver [Module, Refinement] the module/refinement used for extending the target class.
|
|
63
|
+
# @return [Extension] the newly created extension instance
|
|
64
|
+
# @see Extension#define
|
|
65
|
+
def self.define(...) = new { define(...) }
|
|
66
|
+
|
|
67
|
+
# Creates a new extension.
|
|
68
|
+
# @yield Optional block for `define` calls or adding methods to the extension itself.
|
|
69
|
+
# @yieldreceiver [Extension] the extension instance itself.
|
|
70
|
+
def initialize
|
|
71
|
+
check_state!
|
|
72
|
+
@definitions = Internal::StrictMap.new
|
|
73
|
+
@lock = Lock.new
|
|
74
|
+
@installed = Flag.new
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @api private
|
|
79
|
+
def [](target) = @definitions[target]
|
|
80
|
+
|
|
81
|
+
# Defines additional methods for a given target class.
|
|
82
|
+
#
|
|
83
|
+
# The given block will be invoked at least twice. Once in the context of a refinement for the target class,
|
|
84
|
+
# and once in the context of the mixin module that will be prepended to the target class.
|
|
85
|
+
#
|
|
86
|
+
# @example
|
|
87
|
+
# extension = Farce::Extension.new
|
|
88
|
+
# extension.define(String) { def double_size = size * 2 }
|
|
89
|
+
#
|
|
90
|
+
# module Namespace
|
|
91
|
+
# using extension
|
|
92
|
+
# String.method_defined?(:double_size) # => true
|
|
93
|
+
# end
|
|
94
|
+
#
|
|
95
|
+
# String.method_defined?(:double_size) # => false
|
|
96
|
+
# extension.install
|
|
97
|
+
# String.method_defined?(:double_size) # => true
|
|
98
|
+
#
|
|
99
|
+
# @param targets [Array<Class>] the target classes to define methods for
|
|
100
|
+
# @yield the block containing method definitions
|
|
101
|
+
# @yieldreceiver [Module, Refinement] the module/refinement used for extending the target class.
|
|
102
|
+
# @return [self] the extension instance
|
|
103
|
+
def define(*targets, &)
|
|
104
|
+
@lock.synchronize do
|
|
105
|
+
check_state!
|
|
106
|
+
targets.each do |target|
|
|
107
|
+
refine(target, &)
|
|
108
|
+
mixin = @definitions.store_if_absent(target) { Mixin.new(self, target) }
|
|
109
|
+
mixin.module_eval(&)
|
|
110
|
+
mixin.install if installed?
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Installs the extension globally.
|
|
117
|
+
# @return [void]
|
|
118
|
+
def install
|
|
119
|
+
@lock.synchronize do
|
|
120
|
+
return false if installed?
|
|
121
|
+
check_state!(allow_frozen: true)
|
|
122
|
+
@definitions.each_value(&:install)
|
|
123
|
+
yield if block_given?
|
|
124
|
+
@installed.set
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @return [Boolean] whether the extension has been installed
|
|
129
|
+
def installed? = @installed.set?
|
|
130
|
+
|
|
131
|
+
# Freezes the extension.
|
|
132
|
+
#
|
|
133
|
+
# No {#define definitions} can be added after freezing the extension.
|
|
134
|
+
# @return [self] the frozen extension
|
|
135
|
+
def freeze
|
|
136
|
+
return self if frozen?
|
|
137
|
+
@lock.synchronize do
|
|
138
|
+
@definitions.freeze
|
|
139
|
+
super
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def check_state!(allow_frozen: false)
|
|
146
|
+
raise Ractor::IsolationError, "must be called from main Ractor" if Internal.native_ractors? && !Ractor.main?
|
|
147
|
+
Internal::Freeze.check(self) unless allow_frozen
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -13,7 +13,10 @@ module Farce
|
|
|
13
13
|
# Take, put, and swap operate on the value staged in this attempt.
|
|
14
14
|
# An empty read, take, or swap, or a put into a full TMVar fails the
|
|
15
15
|
# attempt. Farce.transaction retries these conditions within its retry limit.
|
|
16
|
-
# The try_* methods return nil or false without failing
|
|
16
|
+
# The try_* methods return nil or false when unavailable without failing
|
|
17
|
+
# the attempt. Blocks passed to try_read and try_take run only when full,
|
|
18
|
+
# including for stored nil, and return the block's result.
|
|
19
|
+
# Create an empty TMVar with Ractor::TMVar.new and a full nil with .new(nil).
|
|
17
20
|
# Assigned values are made shareable, matching Ractor::TVar's setter.
|
|
18
21
|
#
|
|
19
22
|
# Run outside Ractor.atomically, as required by {RactorTVar}.
|
|
@@ -21,6 +21,7 @@ module Farce
|
|
|
21
21
|
INSTANCE = Freeze.publish(new)
|
|
22
22
|
DEFAULT_PORT = BasePort.new
|
|
23
23
|
|
|
24
|
+
def alive? = true
|
|
24
25
|
def default_port = DEFAULT_PORT
|
|
25
26
|
def inspect = "#<Farce::Ractor#1 running>"
|
|
26
27
|
def join = sleep
|
|
@@ -78,7 +79,7 @@ module Farce
|
|
|
78
79
|
ensure
|
|
79
80
|
state.mutex.synchronize do
|
|
80
81
|
state.monitors.each do |monitor|
|
|
81
|
-
monitor
|
|
82
|
+
FakeRactor.send_status(monitor, self, state.status)
|
|
82
83
|
end
|
|
83
84
|
state.monitors = nil
|
|
84
85
|
end
|
|
@@ -97,6 +98,8 @@ module Farce
|
|
|
97
98
|
Farce::Ractor[key] = value
|
|
98
99
|
end
|
|
99
100
|
|
|
101
|
+
def alive? = STATES[self].status == :running
|
|
102
|
+
|
|
100
103
|
def monitor(port) # rubocop:disable Naming/PredicateMethod
|
|
101
104
|
state = STATES[self]
|
|
102
105
|
|
|
@@ -108,7 +111,7 @@ module Farce
|
|
|
108
111
|
end
|
|
109
112
|
end
|
|
110
113
|
|
|
111
|
-
port
|
|
114
|
+
FakeRactor.send_status(port, self, state.status)
|
|
112
115
|
false
|
|
113
116
|
end
|
|
114
117
|
|
|
@@ -148,6 +151,11 @@ module Farce
|
|
|
148
151
|
undef clone
|
|
149
152
|
end
|
|
150
153
|
|
|
154
|
+
def self.send_status(port, ractor, status)
|
|
155
|
+
payload = System.ruby_version >= "4.1" ? [ractor, status].freeze : status
|
|
156
|
+
port << payload
|
|
157
|
+
end
|
|
158
|
+
|
|
151
159
|
def self.current
|
|
152
160
|
# JRuby fibers expose a backing thread with a different thread group.
|
|
153
161
|
thread = Internal.storage_thread(Thread.current)
|
|
@@ -82,15 +82,13 @@ module Farce
|
|
|
82
82
|
|
|
83
83
|
def unblock(_blocker, fiber) # rubocop:disable Naming/PredicateMethod
|
|
84
84
|
return false if @closed || !(token = current_wait(fiber))
|
|
85
|
-
|
|
86
|
-
wakeup
|
|
85
|
+
complete_wait(token, true)
|
|
87
86
|
true
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
def fiber_interrupt(fiber, exception) # rubocop:disable Naming/PredicateMethod
|
|
91
90
|
return false if @closed || !(token = current_wait(fiber))
|
|
92
|
-
|
|
93
|
-
wakeup
|
|
91
|
+
complete_wait(token, nil, exception)
|
|
94
92
|
true
|
|
95
93
|
end
|
|
96
94
|
|
|
@@ -202,6 +200,11 @@ module Farce
|
|
|
202
200
|
|
|
203
201
|
private
|
|
204
202
|
|
|
203
|
+
def complete_wait(token, value, error = nil)
|
|
204
|
+
@mailbox << Completion.new(token, value, error).freeze
|
|
205
|
+
wakeup
|
|
206
|
+
end
|
|
207
|
+
|
|
205
208
|
def finish_close
|
|
206
209
|
return if @closed
|
|
207
210
|
shutdown
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# Special, write-only port that discards all messages.
|
|
7
|
+
# If the Ruby environment supports ports, this will be a real Port object.
|
|
8
|
+
# It can therefore be passed to any API expecting a `Ractor::Port`, including C code.
|
|
9
|
+
# Cannot be read from, but does not accumulate messages in memory.
|
|
10
|
+
# @return [Ractor::Port] Write-only port
|
|
11
|
+
NULL_PORT = Internal::NullPort.new
|
|
12
|
+
end
|
data/lib/farce/system.rb
CHANGED
|
@@ -7,8 +7,16 @@ require "etc"
|
|
|
7
7
|
module Farce
|
|
8
8
|
# Information about the system running Farce.
|
|
9
9
|
module System
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
ruby_version = Gem.ruby_version.release
|
|
11
|
+
ruby_version = ::Ractor.make_shareable(ruby_version, copy: true) if defined?(::Ractor)
|
|
12
|
+
RUBY_VERSION = ruby_version
|
|
13
|
+
WINDOWS = Gem.win_platform?
|
|
14
|
+
private_constant :RUBY_VERSION, :WINDOWS
|
|
15
|
+
|
|
16
|
+
# A Version object representing the current Ruby release, without prerelease suffixes.
|
|
17
|
+
# Safe to call from any Ractor.
|
|
18
|
+
# @return [#<=>, #to_s]
|
|
19
|
+
def self.ruby_version = RUBY_VERSION
|
|
12
20
|
|
|
13
21
|
# Whether the current operating system is Windows.
|
|
14
22
|
# Safe to call from any Ractor.
|
data/lib/farce/version.rb
CHANGED
data/lib/farce.rb
CHANGED
|
@@ -46,7 +46,7 @@ require "farce/system"
|
|
|
46
46
|
# defined?(VERSION) # => false
|
|
47
47
|
# ```
|
|
48
48
|
module Farce
|
|
49
|
-
include Internal::Autoloads
|
|
49
|
+
include Internal::Autoloads[null_port: :NULL_PORT]
|
|
50
50
|
|
|
51
51
|
# The valid storage scopes for local values and collections.
|
|
52
52
|
# @return [::Set<Symbol>]
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: farce
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Haase
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-16 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
email:
|
|
13
13
|
- konstantin.mailinglists@googlemail.com
|
|
@@ -22,11 +22,22 @@ files:
|
|
|
22
22
|
- README.md
|
|
23
23
|
- SECURITY.md
|
|
24
24
|
- docs/benchmarks.md
|
|
25
|
+
- docs/compatibility.md
|
|
26
|
+
- docs/concurrency.md
|
|
27
|
+
- docs/data-structures.md
|
|
25
28
|
- docs/gems/dry-types.md
|
|
26
29
|
- docs/gems/msgpack.md
|
|
27
30
|
- docs/gems/ractor-shim.md
|
|
31
|
+
- docs/installation.md
|
|
32
|
+
- docs/integrations.md
|
|
33
|
+
- docs/introduction.md
|
|
28
34
|
- docs/modes.md
|
|
35
|
+
- docs/scheduling.md
|
|
29
36
|
- docs/scopes.md
|
|
37
|
+
- docs/sharing.md
|
|
38
|
+
- docs/shims.md
|
|
39
|
+
- docs/utilities.md
|
|
40
|
+
- docs/variants-and-scopes.md
|
|
30
41
|
- docs/variants.md
|
|
31
42
|
- lib/farce.rb
|
|
32
43
|
- lib/farce/_yard/internal.rb
|
|
@@ -67,6 +78,7 @@ files:
|
|
|
67
78
|
- lib/farce/abstract/weak_set.rb
|
|
68
79
|
- lib/farce/abstract/weak_value_map.rb
|
|
69
80
|
- lib/farce/atom.rb
|
|
81
|
+
- lib/farce/backports.rb
|
|
70
82
|
- lib/farce/class_mirror.rb
|
|
71
83
|
- lib/farce/clock.rb
|
|
72
84
|
- lib/farce/config.rb
|
|
@@ -79,6 +91,7 @@ files:
|
|
|
79
91
|
- lib/farce/engine/jruby/lease_waiting.rb
|
|
80
92
|
- lib/farce/engine/jruby/map.rb
|
|
81
93
|
- lib/farce/engine/jruby/mutable_numeric_copy.rb
|
|
94
|
+
- lib/farce/engine/jruby/scheduler_synchronization.rb
|
|
82
95
|
- lib/farce/engine/jruby/signal.rb
|
|
83
96
|
- lib/farce/engine/jvm.rb
|
|
84
97
|
- lib/farce/engine/jvm/concurrent_weak_registry.rb
|
|
@@ -91,14 +104,18 @@ files:
|
|
|
91
104
|
- lib/farce/engine/jvm/types.rb
|
|
92
105
|
- lib/farce/engine/ruby.rb
|
|
93
106
|
- lib/farce/engine/ruby/3.4/fiber_scheduler.rb
|
|
107
|
+
- lib/farce/engine/ruby/3.4/null_port.rb
|
|
108
|
+
- lib/farce/engine/ruby/3.4/patch.rb
|
|
94
109
|
- lib/farce/engine/ruby/3.4/port.rb
|
|
95
110
|
- lib/farce/engine/ruby/3.4/ractor_methods.rb
|
|
96
111
|
- lib/farce/engine/ruby/3.4/ractor_selector.rb
|
|
97
112
|
- lib/farce/engine/ruby/3.4/vault.rb
|
|
113
|
+
- lib/farce/engine/ruby/4.0/null_port.rb
|
|
98
114
|
- lib/farce/engine/ruby/4.0/port.rb
|
|
99
115
|
- lib/farce/engine/ruby/4.0/ractor_methods.rb
|
|
100
116
|
- lib/farce/engine/ruby/4.0/ractor_selector.rb
|
|
101
117
|
- lib/farce/engine/ruby/4.0/vault.rb
|
|
118
|
+
- lib/farce/engine/ruby/4.1/null_port.rb
|
|
102
119
|
- lib/farce/engine/ruby/4.1/port.rb
|
|
103
120
|
- lib/farce/engine/ruby/4.1/ractor_methods.rb
|
|
104
121
|
- lib/farce/engine/ruby/4.1/ractor_selector.rb
|
|
@@ -127,12 +144,14 @@ files:
|
|
|
127
144
|
- lib/farce/engine/shared/lease_pool.rb
|
|
128
145
|
- lib/farce/engine/shared/main_scheduler.rb
|
|
129
146
|
- lib/farce/engine/shared/map_key_coordination.rb
|
|
147
|
+
- lib/farce/engine/shared/null_port.rb
|
|
130
148
|
- lib/farce/engine/shared/parallel_scheduler.rb
|
|
131
149
|
- lib/farce/engine/shared/port.rb
|
|
132
150
|
- lib/farce/engine/shared/portable_bounded_map.rb
|
|
133
151
|
- lib/farce/engine/shared/proxy_owner.rb
|
|
134
152
|
- lib/farce/engine/shared/queue.rb
|
|
135
153
|
- lib/farce/engine/shared/ractor_methods.rb
|
|
154
|
+
- lib/farce/engine/shared/ractor_selector.rb
|
|
136
155
|
- lib/farce/engine/shared/rebindable.rb
|
|
137
156
|
- lib/farce/engine/shared/strict_atom.rb
|
|
138
157
|
- lib/farce/engine/shared/strict_map.rb
|
|
@@ -171,6 +190,7 @@ files:
|
|
|
171
190
|
- lib/farce/envelope.rb
|
|
172
191
|
- lib/farce/error.rb
|
|
173
192
|
- lib/farce/exchanger.rb
|
|
193
|
+
- lib/farce/extension.rb
|
|
174
194
|
- lib/farce/flag.rb
|
|
175
195
|
- lib/farce/integrations.rb
|
|
176
196
|
- lib/farce/integrations/active_support.rb
|
|
@@ -299,6 +319,7 @@ files:
|
|
|
299
319
|
- lib/farce/mode_manager/smart_rule.rb
|
|
300
320
|
- lib/farce/molecule.rb
|
|
301
321
|
- lib/farce/mutable.rb
|
|
322
|
+
- lib/farce/null_port.rb
|
|
302
323
|
- lib/farce/pool.rb
|
|
303
324
|
- lib/farce/port.rb
|
|
304
325
|
- lib/farce/priority_queue.rb
|