Skip to content

Commit 6317d69

Browse files
Better handling of check_access during transfer.
1 parent 30de620 commit 6317d69

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

lib/async/safe/monitor.rb

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
require "set"
77
require "weakref"
88

9+
# Fiber-local variable to track when we're in a transfer operation:
10+
Fiber.attr_accessor :async_safe_transfer
11+
912
module Async
1013
module Safe
1114
# Raised when an object is accessed from a different fiber than the one that owns it.
@@ -95,18 +98,23 @@ def transfer(*objects)
9598
current = Fiber.current
9699
visited = Set.new
97100

98-
# Traverse object graph (outside mutex to avoid deadlock):
99-
objects.each do |object|
100-
traverse_objects(object, visited)
101-
end
102-
103-
# Transfer all visited objects (convert to array to avoid triggering TracePoint in sync block):
104-
objects_to_transfer = visited.to_a
101+
# Disable tracking during traversal to avoid deadlock:
102+
current.async_safe_transfer = true
105103

106-
@mutex.synchronize do
107-
objects_to_transfer.each do |object|
108-
@owners[object] = current if @owners.key?(object)
104+
begin
105+
# Traverse object graph:
106+
objects.each do |object|
107+
traverse_objects(object, visited)
109108
end
109+
110+
# Transfer all visited objects:
111+
@mutex.synchronize do
112+
visited.each do |object|
113+
@owners[object] = current if @owners.key?(object)
114+
end
115+
end
116+
ensure
117+
current.async_safe_transfer = false
110118
end
111119
end
112120

@@ -138,6 +146,9 @@ def transfer(*objects)
138146
#
139147
# @parameter trace_point [TracePoint] The trace point containing access information.
140148
def check_access(trace_point)
149+
# Skip if we're in a transfer operation:
150+
return if Fiber.current.async_safe_transfer
151+
141152
object = trace_point.self
142153

143154
# Skip tracking class/module methods:

0 commit comments

Comments
 (0)