async-safe 0.4.0 → 0.4.1
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
- checksums.yaml.gz.sig +0 -0
- data/lib/async/safe/builtins.rb +12 -0
- data/lib/async/safe/monitor.rb +22 -13
- data/lib/async/safe/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +1 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72500ee1207a863df7f749896936bf9edce7e06f2f7d7a519329c0ada72951eb
|
4
|
+
data.tar.gz: 584c0393294503ea01cf1e1858f88f3c2faf5e2cd6fdf1b2f632af0708e4d787
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 305ea4886f6b9fa0452de045244623806ed824ba24791ed0d2d1e6bf96a14f536f31fccbd54f099e5cc10ee1dc39067609be9b646daac413c47126a86f0306a2
|
7
|
+
data.tar.gz: 78dd7ab4aab4893c2824788e03522905698d6f400557976677253fbcc53643b4a0dbaaa8a8157249415f9380a317ffddc126948bb484fa2b6c795513abf4fc2d
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/async/safe/builtins.rb
CHANGED
@@ -12,6 +12,10 @@
|
|
12
12
|
class Array
|
13
13
|
ASYNC_SAFE = false
|
14
14
|
|
15
|
+
# Traverse array elements during ownership transfer.
|
16
|
+
#
|
17
|
+
# @parameter instance [Array] The array instance to traverse.
|
18
|
+
# @parameter block [Proc] Block to call for each element.
|
15
19
|
def self.async_safe_traverse(instance, &block)
|
16
20
|
instance.each(&block)
|
17
21
|
end
|
@@ -21,6 +25,10 @@ end
|
|
21
25
|
class Hash
|
22
26
|
ASYNC_SAFE = false
|
23
27
|
|
28
|
+
# Traverse hash keys and values during ownership transfer.
|
29
|
+
#
|
30
|
+
# @parameter instance [Hash] The hash instance to traverse.
|
31
|
+
# @parameter block [Proc] Block to call for each key and value.
|
24
32
|
def self.async_safe_traverse(instance, &block)
|
25
33
|
instance.each_key(&block)
|
26
34
|
instance.each_value(&block)
|
@@ -31,6 +39,10 @@ end
|
|
31
39
|
class Set
|
32
40
|
ASYNC_SAFE = false
|
33
41
|
|
42
|
+
# Traverse set elements during ownership transfer.
|
43
|
+
#
|
44
|
+
# @parameter instance [Set] The set instance to traverse.
|
45
|
+
# @parameter block [Proc] Block to call for each element.
|
34
46
|
def self.async_safe_traverse(instance, &block)
|
35
47
|
instance.each(&block)
|
36
48
|
end
|
data/lib/async/safe/monitor.rb
CHANGED
@@ -6,6 +6,9 @@
|
|
6
6
|
require "set"
|
7
7
|
require "weakref"
|
8
8
|
|
9
|
+
# Fiber-local variable to track when we're in a transfer operation:
|
10
|
+
Fiber.attr_accessor :async_safe_transfer
|
11
|
+
|
9
12
|
module Async
|
10
13
|
module Safe
|
11
14
|
# Raised when an object is accessed from a different fiber than the one that owns it.
|
@@ -95,28 +98,31 @@ module Async
|
|
95
98
|
current = Fiber.current
|
96
99
|
visited = Set.new
|
97
100
|
|
98
|
-
#
|
99
|
-
|
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
|
105
103
|
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
begin
|
105
|
+
# Traverse object graph:
|
106
|
+
objects.each do |object|
|
107
|
+
traverse_objects(object, visited)
|
109
108
|
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
|
110
118
|
end
|
111
119
|
end
|
112
120
|
|
113
|
-
private
|
114
|
-
|
115
121
|
# Traverse the object graph and collect all reachable objects.
|
116
122
|
#
|
117
123
|
# @parameter object [Object] The object to traverse.
|
118
124
|
# @parameter visited [Set] Set of visited objects (object references, not IDs).
|
119
|
-
def traverse_objects(object, visited)
|
125
|
+
private def traverse_objects(object, visited)
|
120
126
|
# Avoid circular references:
|
121
127
|
return if visited.include?(object)
|
122
128
|
|
@@ -140,6 +146,9 @@ module Async
|
|
140
146
|
#
|
141
147
|
# @parameter trace_point [TracePoint] The trace point containing access information.
|
142
148
|
def check_access(trace_point)
|
149
|
+
# Skip if we're in a transfer operation:
|
150
|
+
return if Fiber.current.async_safe_transfer
|
151
|
+
|
143
152
|
object = trace_point.self
|
144
153
|
|
145
154
|
# Skip tracking class/module methods:
|
data/lib/async/safe/version.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
Binary file
|