ractorize 0.0.8 → 0.0.10
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 +9 -0
- data/src/ractorize/garbage_collection/tracker.rb +27 -2
- data/src/ractorize/garbage_collection/tracking_ractor.rb +40 -0
- data/src/ractorize/garbage_collection.rb +19 -28
- data/src/ractorize/ractorized_object/ractorized_ractor.rb +133 -0
- data/src/ractorize/ractorized_object.rb +9 -7
- data/src/ractorize/thunk.rb +12 -5
- data/src/ractorize.rb +16 -135
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7827fd6bd911724e81479f2966f75aafb825c1320fb870531b08db1079b5b9c
|
|
4
|
+
data.tar.gz: bf7da9b30088e3554637b646ef4bb5ceab085d076f3e0097c68f236d647b3baf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e7858c116a76c408a6c341ee8007a91a50e4caae089978564d2704535845248e14272c18909bd8f4e5458e6dbe97262afb2acc088fd79412f5231ff1f56d3de1
|
|
7
|
+
data.tar.gz: 0e3b0165b66489c83b3dc7ebe37873ad6600e4fb9239eeaa326440d700112bf13255a67532f84fdfd15c3d37afcb93285742a4a50e5eef0993231bab1c5976ff
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [0.0.10] - 2026-06-30
|
|
2
|
+
|
|
3
|
+
- Handle thunks being cloned
|
|
4
|
+
|
|
5
|
+
## [0.0.9] - 2026-06-29
|
|
6
|
+
|
|
7
|
+
- Fix bug that results from moving Time, which is neither shareable nor movable!
|
|
8
|
+
- Handle deadlocks that seem to arise from re-entrant #inspect calls
|
|
9
|
+
|
|
1
10
|
## [0.0.8] - 2026-06-24
|
|
2
11
|
|
|
3
12
|
- Add GarbageCollector to close abandoned RactorizedObject ractors and Thunk ractors
|
|
@@ -2,11 +2,13 @@ module Ractorize
|
|
|
2
2
|
module GarbageCollection
|
|
3
3
|
class Tracker
|
|
4
4
|
attr_accessor :ractorized_object_id_to_ractor,
|
|
5
|
-
:thunk_id_to_ractor
|
|
5
|
+
:thunk_id_to_ractor,
|
|
6
|
+
:ractor_to_thunk_ids
|
|
6
7
|
|
|
7
8
|
def initialize
|
|
8
9
|
self.ractorized_object_id_to_ractor = ObjectSpace::WeakMap.new
|
|
9
10
|
self.thunk_id_to_ractor = ObjectSpace::WeakMap.new
|
|
11
|
+
self.ractor_to_thunk_ids = ObjectSpace::WeakKeyMap.new
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def track_ractorized_object(ractorized_object)
|
|
@@ -24,9 +26,32 @@ module Ractorize
|
|
|
24
26
|
thunk_id_to_ractor[thunk_id] = ractor
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
def thunk_cloned(old_thunk_id, new_thunk_id, thunk_ractor)
|
|
30
|
+
thunk_ids = ractor_to_thunk_ids[thunk_ractor]
|
|
31
|
+
|
|
32
|
+
if thunk_ids
|
|
33
|
+
thunk_ids << new_thunk_id
|
|
34
|
+
else
|
|
35
|
+
ractor_to_thunk_ids[thunk_ractor] = [old_thunk_id, new_thunk_id]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
thunk_id_to_ractor[new_thunk_id] = thunk_ractor
|
|
39
|
+
end
|
|
40
|
+
|
|
27
41
|
def cleanup_after_thunk(thunk_id)
|
|
28
42
|
ractor = thunk_id_to_ractor.delete(thunk_id)
|
|
29
|
-
|
|
43
|
+
|
|
44
|
+
return unless ractor
|
|
45
|
+
|
|
46
|
+
thunk_ids = ractor_to_thunk_ids[ractor]
|
|
47
|
+
|
|
48
|
+
if thunk_ids
|
|
49
|
+
thunk_ids.delete(thunk_id)
|
|
50
|
+
|
|
51
|
+
return unless thunk_ids.empty?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
ractor << :__close__
|
|
30
55
|
rescue Ractor::ClosedError
|
|
31
56
|
# do nothing
|
|
32
57
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require_relative "../base_ractor"
|
|
2
|
+
require_relative "tracker"
|
|
3
|
+
|
|
4
|
+
module Ractorize
|
|
5
|
+
module GarbageCollection
|
|
6
|
+
class TrackingRactor < BaseRactor
|
|
7
|
+
class << self
|
|
8
|
+
def new
|
|
9
|
+
super(name: "GarbageCollection::TrackingRactor") do
|
|
10
|
+
tracker = Tracker.new
|
|
11
|
+
|
|
12
|
+
loop do
|
|
13
|
+
# SimpleCov branch coverage doesn't like that we aren't testing not matching anything
|
|
14
|
+
# but this does result in an error unlike case/when so no point in checking that.
|
|
15
|
+
# :nocov:
|
|
16
|
+
case receive
|
|
17
|
+
# :nocov:
|
|
18
|
+
in :track_ractorized_object, ractorized_object
|
|
19
|
+
tracker.track_ractorized_object(ractorized_object)
|
|
20
|
+
in :cleanup_after_ractorized_object, ractorized_object_id
|
|
21
|
+
tracker.cleanup_after_ractorized_object(ractorized_object_id)
|
|
22
|
+
in :track_thunk, thunk_id, thunk_ractor
|
|
23
|
+
tracker.track_thunk(thunk_id, thunk_ractor)
|
|
24
|
+
in :thunk_cloned, old_thunk_id, new_thunk_id, thunk_ractor
|
|
25
|
+
tracker.thunk_cloned(old_thunk_id, new_thunk_id, thunk_ractor)
|
|
26
|
+
in :cleanup_after_thunk, thunk_id
|
|
27
|
+
tracker.cleanup_after_thunk(thunk_id)
|
|
28
|
+
end
|
|
29
|
+
rescue TrackingRactor::ClosedError
|
|
30
|
+
# do nothing
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
TRACKING_RACTOR = TrackingRactor.new
|
|
38
|
+
private_constant :TRACKING_RACTOR
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
module Ractorize
|
|
2
2
|
module GarbageCollection
|
|
3
|
-
class TrackingRactor < BaseRactor; end
|
|
4
|
-
|
|
5
3
|
class << self
|
|
6
4
|
def track_ractorized_object(ractorized_object)
|
|
7
5
|
# We have to define the finalizer here, not in the tracker, because it's not frozen yet
|
|
@@ -16,7 +14,7 @@ module Ractorize
|
|
|
16
14
|
end
|
|
17
15
|
|
|
18
16
|
def track_thunk(thunk)
|
|
19
|
-
# We have to define the finalizer here, not in the tracker, because it's not
|
|
17
|
+
# We have to define the finalizer here, not in the tracker, because it's not shareable
|
|
20
18
|
ObjectSpace.define_finalizer(thunk, &finalize_thunk_proc)
|
|
21
19
|
|
|
22
20
|
begin
|
|
@@ -26,6 +24,24 @@ module Ractorize
|
|
|
26
24
|
end
|
|
27
25
|
end
|
|
28
26
|
|
|
27
|
+
def thunk_cloned(old_thunk, new_thunk)
|
|
28
|
+
ractor = old_thunk.__thunk_ractor__
|
|
29
|
+
|
|
30
|
+
# We have to define the finalizer here, not in the tracker, because it's not shareable
|
|
31
|
+
# ObjectSpace.define_finalizer(new_thunk, &finalize_thunk_proc)
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
TRACKING_RACTOR << [
|
|
35
|
+
:thunk_cloned,
|
|
36
|
+
old_thunk.__object_id__,
|
|
37
|
+
new_thunk.__object_id__,
|
|
38
|
+
ractor
|
|
39
|
+
].freeze
|
|
40
|
+
rescue TrackingRactor::ClosedError
|
|
41
|
+
# do nothing
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
29
45
|
def cleanup_after_ractorized_object(ractorized_object_id)
|
|
30
46
|
TRACKING_RACTOR << [:cleanup_after_ractorized_object, ractorized_object_id].freeze
|
|
31
47
|
rescue Ractor::ClosedError
|
|
@@ -52,30 +68,5 @@ module Ractorize
|
|
|
52
68
|
end
|
|
53
69
|
end
|
|
54
70
|
end
|
|
55
|
-
|
|
56
|
-
TRACKING_RACTOR = TrackingRactor.new do
|
|
57
|
-
tracker = Tracker.new
|
|
58
|
-
|
|
59
|
-
loop do
|
|
60
|
-
# SimpleCov branch coverage doesn't like that we aren't testing not matching anything
|
|
61
|
-
# but this does result in an error unlike case/when so no point in checking that.
|
|
62
|
-
# :nocov:
|
|
63
|
-
case receive
|
|
64
|
-
# :nocov:
|
|
65
|
-
in :track_ractorized_object, ractorized_object
|
|
66
|
-
tracker.track_ractorized_object(ractorized_object)
|
|
67
|
-
in :cleanup_after_ractorized_object, ractorized_object_id
|
|
68
|
-
tracker.cleanup_after_ractorized_object(ractorized_object_id)
|
|
69
|
-
in :track_thunk, thunk_id, thunk_ractor
|
|
70
|
-
tracker.track_thunk(thunk_id, thunk_ractor)
|
|
71
|
-
in :cleanup_after_thunk, thunk_id
|
|
72
|
-
tracker.cleanup_after_thunk(thunk_id)
|
|
73
|
-
end
|
|
74
|
-
rescue TrackingRactor::ClosedError
|
|
75
|
-
# do nothing
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private_constant :TRACKING_RACTOR
|
|
80
71
|
end
|
|
81
72
|
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require_relative "../base_ractor"
|
|
2
|
+
|
|
3
|
+
module Ractorize
|
|
4
|
+
class RactorizedObject < BasicObject
|
|
5
|
+
class RactorizedRactor < ::BaseRactor
|
|
6
|
+
class << self
|
|
7
|
+
def new(name: nil)
|
|
8
|
+
super do
|
|
9
|
+
mode = receive
|
|
10
|
+
|
|
11
|
+
object = case mode
|
|
12
|
+
when :class
|
|
13
|
+
klass, args, opts, block = receive
|
|
14
|
+
target_class = klass
|
|
15
|
+
klass.new(*args.freeze, **opts.freeze, &block)
|
|
16
|
+
when :object
|
|
17
|
+
o = receive
|
|
18
|
+
target_class = o.class
|
|
19
|
+
o
|
|
20
|
+
when :class_arg_by_arg
|
|
21
|
+
klass = receive
|
|
22
|
+
target_class = klass
|
|
23
|
+
|
|
24
|
+
args, opts, block = Ractorize.extract_args(self)
|
|
25
|
+
|
|
26
|
+
klass.new(*args.freeze, **opts.freeze, &block)
|
|
27
|
+
else
|
|
28
|
+
# :nocov:
|
|
29
|
+
raise "Invalid mode #{mode}"
|
|
30
|
+
# :nocov:
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
loop do
|
|
34
|
+
# rubocop:disable Lint/UselessAssignment
|
|
35
|
+
value = method_name = method_args = opts = return_port = thunk_ractor = block_given = nil
|
|
36
|
+
# rubocop:enable Lint/UselessAssignment
|
|
37
|
+
method_name, method_args, opts, return_port, thunk_ractor, block_given = receive
|
|
38
|
+
|
|
39
|
+
case method_name
|
|
40
|
+
when :__close__
|
|
41
|
+
begin
|
|
42
|
+
# Time is not movable but also not shareable!
|
|
43
|
+
move = !Ractor.shareable?(object) && !(Time === object)
|
|
44
|
+
thunk_ractor&.send([:success, object].freeze, move:)
|
|
45
|
+
rescue RactorizedRactor::ClosedError
|
|
46
|
+
# do nothing
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
object = nil
|
|
50
|
+
close
|
|
51
|
+
break
|
|
52
|
+
when :__target_object_id__
|
|
53
|
+
return_port = method_args
|
|
54
|
+
|
|
55
|
+
target_object_id = ::Object.instance_method(:object_id).bind_call(object)
|
|
56
|
+
return_port << target_object_id
|
|
57
|
+
else
|
|
58
|
+
if method_name == :__invoke_arg_by_arg__
|
|
59
|
+
args_port = Ractorize::RactorizedObject::RactorizedRactor::Port.new
|
|
60
|
+
return_port << args_port
|
|
61
|
+
|
|
62
|
+
method_name = args_port.receive
|
|
63
|
+
method_args, opts = Ractorize.extract_args(args_port)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if block_given
|
|
67
|
+
block_result_port = Ractorize::RactorizedObject::RactorizedRactor::Port.new
|
|
68
|
+
|
|
69
|
+
value = object.__send__(method_name, *method_args, **opts) do |*args, **opts, &b|
|
|
70
|
+
Ractorize.prepare_args(target_class, args, opts, skip_move: true)
|
|
71
|
+
|
|
72
|
+
return_port << [:yield, [args.dup.freeze, opts.dup.freeze, b].freeze, block_result_port].freeze
|
|
73
|
+
|
|
74
|
+
outcome_type, return_value = block_result_port.receive
|
|
75
|
+
|
|
76
|
+
case outcome_type
|
|
77
|
+
when :normal
|
|
78
|
+
return_value
|
|
79
|
+
when :break
|
|
80
|
+
# TODO: handle error situation
|
|
81
|
+
break
|
|
82
|
+
else
|
|
83
|
+
# :nocov:
|
|
84
|
+
raise "Not sure how to handle outcome_type #{outcome_type}"
|
|
85
|
+
# :nocov:
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
return_port << [:return, value].freeze
|
|
90
|
+
else
|
|
91
|
+
value = object.__send__(method_name, *method_args, **opts)
|
|
92
|
+
value = value.__value__ while Ractorize::Thunk === value
|
|
93
|
+
|
|
94
|
+
begin
|
|
95
|
+
if thunk_ractor
|
|
96
|
+
thunk_ractor.send([:success, value].freeze)
|
|
97
|
+
else
|
|
98
|
+
return_port << value
|
|
99
|
+
end
|
|
100
|
+
rescue IOError => e
|
|
101
|
+
# Unclear why this sometimes manifests as this error instead of ClosedError but
|
|
102
|
+
# need to handle them both.
|
|
103
|
+
# :nocov:
|
|
104
|
+
raise unless e.message == "closed stream"
|
|
105
|
+
# :nocov:
|
|
106
|
+
rescue Ractor::ClosedError
|
|
107
|
+
# Whoa... this error inherits from StopIteration and will kill the loop!!!
|
|
108
|
+
# Nothing really to do here but keep the loop going and handle other
|
|
109
|
+
# method calls to the ractorized object from other ractors.
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
nil
|
|
118
|
+
# object
|
|
119
|
+
rescue => e
|
|
120
|
+
# :nocov:
|
|
121
|
+
puts
|
|
122
|
+
puts "an unhandled error!!! #{e.class} #{e.message} #{e}"
|
|
123
|
+
puts e.backtrace
|
|
124
|
+
puts
|
|
125
|
+
|
|
126
|
+
raise
|
|
127
|
+
# :nocov:
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -3,8 +3,6 @@ require_relative "thunk"
|
|
|
3
3
|
|
|
4
4
|
module Ractorize
|
|
5
5
|
class RactorizedObject < BasicObject
|
|
6
|
-
class RactorizedRactor < ::BaseRactor; end
|
|
7
|
-
|
|
8
6
|
class << self
|
|
9
7
|
def method_should_use_thunk?(method_symbol)
|
|
10
8
|
method_symbol != :== && method_symbol != :! && method_symbol != :!= &&
|
|
@@ -16,14 +14,14 @@ module Ractorize
|
|
|
16
14
|
attr_reader :__object_id__, :__ractor__
|
|
17
15
|
|
|
18
16
|
def initialize(mode, *args, **opts, &block)
|
|
19
|
-
@__ractor__ = RactorizedRactor.new(name: "#{args.first}<#{args.first.object_id}>"
|
|
17
|
+
@__ractor__ = RactorizedRactor.new(name: "#{args.first}<#{args.first.object_id}>".freeze)
|
|
20
18
|
|
|
21
19
|
case mode
|
|
22
20
|
when :object
|
|
23
21
|
@__ractor__ << :object
|
|
24
22
|
|
|
25
23
|
outside_object = args.first
|
|
26
|
-
|
|
24
|
+
@__target_object_id__ = ::Object.instance_method(:object_id).bind_call(outside_object)
|
|
27
25
|
@__target_class__ = outside_object.class
|
|
28
26
|
|
|
29
27
|
if ::Ractor.shareable?(outside_object)
|
|
@@ -64,6 +62,10 @@ module Ractorize
|
|
|
64
62
|
@__ractor__ << :class
|
|
65
63
|
@__ractor__ << [klass, args.freeze, opts.dup.freeze, block].freeze
|
|
66
64
|
end
|
|
65
|
+
|
|
66
|
+
return_port = ::Ractor::Port.new
|
|
67
|
+
@__ractor__ << [:__target_object_id__, return_port].freeze
|
|
68
|
+
@__target_object_id__ = return_port.receive
|
|
67
69
|
else
|
|
68
70
|
# :nocov:
|
|
69
71
|
::Kernel.raise "Invalid mode #{mode}"
|
|
@@ -192,11 +194,11 @@ module Ractorize
|
|
|
192
194
|
# def equal?(other) = method_missing(:equal?, other) || super
|
|
193
195
|
def to_s = inspect
|
|
194
196
|
|
|
197
|
+
# delegating this to the target object increases risk of a deadlock since
|
|
198
|
+
# sometimes #inspect calls #inspect on other objects and can lead to reentry and thus deadlock
|
|
195
199
|
def inspect
|
|
196
200
|
object_id = ::Object.instance_method(:object_id).bind(self).call
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
"RactorizedObject<#{object_id}>[#{moved_object_inspect}]".freeze
|
|
201
|
+
"RactorizedObject<#{object_id}>[#{@__target_class__}<#{@__target_object_id__}>]}"
|
|
200
202
|
end
|
|
201
203
|
end
|
|
202
204
|
end
|
data/src/ractorize/thunk.rb
CHANGED
|
@@ -10,13 +10,20 @@ module Ractorize
|
|
|
10
10
|
::Ractorize::GarbageCollection.track_thunk(self)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def initialize_clone(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
def initialize_clone(original_thunk)
|
|
14
|
+
if __resolved__? && original_thunk.__resolved__?
|
|
15
|
+
# Seems this could happen if we had a frozen thunk whose @__value__ is not shareable
|
|
16
|
+
# Since the thunk's ractor is already gone nothing to worry about
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
self.__object_id__ = ::Object.instance_method(:object_id).bind_call(self)
|
|
21
|
+
|
|
22
|
+
::Ractorize::GarbageCollection.thunk_cloned(original_thunk, self)
|
|
18
23
|
end
|
|
19
24
|
|
|
25
|
+
def __resolved__? = defined?(@__value__)
|
|
26
|
+
|
|
20
27
|
def method_missing(...)
|
|
21
28
|
__value__.__send__(...)
|
|
22
29
|
end
|
data/src/ractorize.rb
CHANGED
|
@@ -4,6 +4,22 @@ require_relative "ractorize/ractorized_class"
|
|
|
4
4
|
|
|
5
5
|
module Ractorize
|
|
6
6
|
class << self
|
|
7
|
+
def ractorize_object(object)
|
|
8
|
+
RactorizedObject.new(:object, object)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ractorize_class(klass)
|
|
12
|
+
RactorizedClass[klass]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def [](object)
|
|
16
|
+
if object.is_a?(Class)
|
|
17
|
+
ractorize_class(object)
|
|
18
|
+
else
|
|
19
|
+
ractorize_object(object)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
7
23
|
# TODO: figure out a way to magically get a ractor-shareable proc from a non-ractor-shareable proc
|
|
8
24
|
def auto_freeze(target, class_or_proc = nil)
|
|
9
25
|
@auto_freeze = @auto_freeze ? @auto_freeze.dup : []
|
|
@@ -214,139 +230,4 @@ module Ractorize
|
|
|
214
230
|
nil
|
|
215
231
|
end
|
|
216
232
|
end
|
|
217
|
-
|
|
218
|
-
# Putting this in a constant so we can get test coverage on it since not sure how to get coverage
|
|
219
|
-
# on something inside a ractor.
|
|
220
|
-
RACTOR_PROC = Ractor.shareable_proc do
|
|
221
|
-
mode = receive
|
|
222
|
-
|
|
223
|
-
object = case mode
|
|
224
|
-
when :class
|
|
225
|
-
klass, args, opts, block = receive
|
|
226
|
-
target_class = klass
|
|
227
|
-
klass.new(*args.freeze, **opts.freeze, &block)
|
|
228
|
-
when :object
|
|
229
|
-
o = receive
|
|
230
|
-
target_class = o.class
|
|
231
|
-
o
|
|
232
|
-
when :class_arg_by_arg
|
|
233
|
-
klass = receive
|
|
234
|
-
target_class = klass
|
|
235
|
-
|
|
236
|
-
args, opts, block = Ractorize.extract_args(self)
|
|
237
|
-
|
|
238
|
-
klass.new(*args.freeze, **opts.freeze, &block)
|
|
239
|
-
else
|
|
240
|
-
# :nocov:
|
|
241
|
-
raise "Invalid mode #{mode}"
|
|
242
|
-
# :nocov:
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
loop do
|
|
246
|
-
# rubocop:disable Lint/UselessAssignment
|
|
247
|
-
value = method_name = method_args = opts = return_port = thunk_ractor = block_given = nil
|
|
248
|
-
# rubocop:enable Lint/UselessAssignment
|
|
249
|
-
method_name, method_args, opts, return_port, thunk_ractor, block_given = receive
|
|
250
|
-
|
|
251
|
-
case method_name
|
|
252
|
-
when :__close__
|
|
253
|
-
begin
|
|
254
|
-
thunk_ractor&.send([:success, object].freeze, move: true)
|
|
255
|
-
rescue RactorizedRactor::ClosedError
|
|
256
|
-
# do nothing
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
object = nil
|
|
260
|
-
close
|
|
261
|
-
break
|
|
262
|
-
else
|
|
263
|
-
if method_name == :__invoke_arg_by_arg__
|
|
264
|
-
args_port = Ractorize::RactorizedObject::RactorizedRactor::Port.new
|
|
265
|
-
return_port << args_port
|
|
266
|
-
|
|
267
|
-
method_name = args_port.receive
|
|
268
|
-
method_args, opts = Ractorize.extract_args(args_port)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
if block_given
|
|
272
|
-
block_result_port = Ractorize::RactorizedObject::RactorizedRactor::Port.new
|
|
273
|
-
|
|
274
|
-
value = object.__send__(method_name, *method_args, **opts) do |*args, **opts, &b|
|
|
275
|
-
Ractorize.prepare_args(target_class, args, opts, skip_move: true)
|
|
276
|
-
|
|
277
|
-
return_port << [:yield, [args.dup.freeze, opts.dup.freeze, b].freeze, block_result_port].freeze
|
|
278
|
-
|
|
279
|
-
outcome_type, return_value = block_result_port.receive
|
|
280
|
-
|
|
281
|
-
case outcome_type
|
|
282
|
-
when :normal
|
|
283
|
-
return_value
|
|
284
|
-
when :break
|
|
285
|
-
# TODO: handle error situation
|
|
286
|
-
break
|
|
287
|
-
else
|
|
288
|
-
# :nocov:
|
|
289
|
-
raise "Not sure how to handle outcome_type #{outcome_type}"
|
|
290
|
-
# :nocov:
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
return_port << [:return, value].freeze
|
|
295
|
-
else
|
|
296
|
-
value = object.__send__(method_name, *method_args, **opts)
|
|
297
|
-
value = value.__value__ while Ractorize::Thunk === value
|
|
298
|
-
|
|
299
|
-
begin
|
|
300
|
-
if thunk_ractor
|
|
301
|
-
thunk_ractor.send([:success, value].freeze)
|
|
302
|
-
else
|
|
303
|
-
return_port << value
|
|
304
|
-
end
|
|
305
|
-
rescue IOError => e
|
|
306
|
-
# Unclear why this sometimes manifests as this error instead of ClosedError but
|
|
307
|
-
# need to handle them both.
|
|
308
|
-
# :nocov:
|
|
309
|
-
raise unless e.message == "closed stream"
|
|
310
|
-
# :nocov:
|
|
311
|
-
rescue Ractor::ClosedError
|
|
312
|
-
# Whoa... this error inherits from StopIteration and will kill the loop!!!
|
|
313
|
-
# Nothing really to do here but keep the loop going and handle other
|
|
314
|
-
# method calls to the ractorized object from other ractors.
|
|
315
|
-
end
|
|
316
|
-
end
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
nil
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
nil
|
|
323
|
-
# object
|
|
324
|
-
rescue => e
|
|
325
|
-
# :nocov:
|
|
326
|
-
puts
|
|
327
|
-
puts "an unhandled error!!! #{e.class} #{e.message} #{e}"
|
|
328
|
-
puts e.backtrace
|
|
329
|
-
puts
|
|
330
|
-
|
|
331
|
-
raise
|
|
332
|
-
# :nocov:
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
class << self
|
|
336
|
-
def ractorize_object(object)
|
|
337
|
-
RactorizedObject.new(:object, object)
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def ractorize_class(klass)
|
|
341
|
-
RactorizedClass[klass]
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def [](object)
|
|
345
|
-
if object.is_a?(Class)
|
|
346
|
-
ractorize_class(object)
|
|
347
|
-
else
|
|
348
|
-
ractorize_object(object)
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
233
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ractorize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miles Georgi
|
|
@@ -24,8 +24,10 @@ files:
|
|
|
24
24
|
- src/ractorize/base_ractor.rb
|
|
25
25
|
- src/ractorize/garbage_collection.rb
|
|
26
26
|
- src/ractorize/garbage_collection/tracker.rb
|
|
27
|
+
- src/ractorize/garbage_collection/tracking_ractor.rb
|
|
27
28
|
- src/ractorize/ractorized_class.rb
|
|
28
29
|
- src/ractorize/ractorized_object.rb
|
|
30
|
+
- src/ractorize/ractorized_object/ractorized_ractor.rb
|
|
29
31
|
- src/ractorize/thunk.rb
|
|
30
32
|
- src/ractorize/thunk/thunk_ractor.rb
|
|
31
33
|
homepage: https://github.com/ractor-shack/ractorize
|