Skip to content

Commit 9300497

Browse files
Tidy up implementation.
1 parent 59280c9 commit 9300497

File tree

8 files changed

+28
-71
lines changed

8 files changed

+28
-71
lines changed

examples/basic.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def read
4242
puts "\n2. Async-safe class (no violation):"
4343

4444
class SafeQueue
45-
include Async::Safe::Concurrent
45+
async_safe!
4646

4747
def initialize
4848
@items = []

guides/getting-started/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Mark entire classes as safe for concurrent access:
6969

7070
~~~ ruby
7171
class MyQueue
72-
include Async::Safe::Concurrent
72+
async_safe!
7373

7474
def initialize
7575
@queue = Thread::Queue.new

lib/async/safe.rb

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
require_relative "safe/version"
77
require_relative "safe/class"
8-
require_relative "safe/concurrent"
98
require_relative "safe/monitor"
109
require_relative "safe/builtins"
1110

@@ -52,12 +51,7 @@ def async_safe?(method = nil)
5251
end
5352
end
5453

55-
# Global monitor instance
56-
@monitor = Monitor.new
57-
5854
class << self
59-
ASYNC_SAFE = true
60-
6155
# @attribute [Monitor] The global monitoring instance.
6256
attr_reader :monitor
6357

@@ -66,19 +60,14 @@ class << self
6660
# This activates a TracePoint that tracks object access across fibers and threads.
6761
# There is no performance overhead when monitoring is disabled.
6862
def enable!
63+
@monitor ||= Monitor.new
6964
@monitor.enable!
7065
end
7166

7267
# Disable thread safety monitoring.
7368
def disable!
74-
@monitor.disable!
75-
end
76-
77-
# Reset all tracked ownership.
78-
#
79-
# Useful for resetting state between test runs.
80-
def reset!
81-
@monitor.reset!
69+
@monitor&.disable!
70+
@monitor = nil
8271
end
8372

8473
# Explicitly transfer ownership of objects to the current fiber.
@@ -97,7 +86,7 @@ def reset!
9786
# end
9887
# ~~~
9988
def transfer(*objects)
100-
@monitor.transfer(*objects)
89+
@monitor&.transfer(*objects)
10190
end
10291
end
10392
end

lib/async/safe/class.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,12 @@ def async_safe?(method = nil)
1717

1818
false
1919
end
20+
21+
# Mark the class as async-safe or not.
22+
#
23+
# @parameter value [Boolean] Whether the class is async-safe.
24+
# @returns [Boolean] Whether the class is async-safe.
25+
def async_safe!(value = true)
26+
self.const_set(:ASYNC_SAFE, value)
27+
end
2028
end
21-

lib/async/safe/concurrent.rb

Lines changed: 0 additions & 42 deletions
This file was deleted.

lib/async/safe/monitor.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,6 @@ def disable!
8585
end
8686
end
8787

88-
# Reset all tracked ownership.
89-
def reset!
90-
@mutex.synchronize do
91-
@owners = ObjectSpace::WeakMap.new
92-
end
93-
end
94-
9588
# Explicitly transfer ownership of objects to the current fiber.
9689
#
9790
# @parameter objects [Array(Object)] The objects to transfer.

test/async/safe.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ def read
2424
end
2525

2626
before do
27-
subject.reset!
27+
# Reset monitoring state:
28+
subject.disable!
2829
subject.enable!
2930
end
3031

@@ -54,7 +55,7 @@ def read
5455

5556
it "allows concurrent access to async-safe classes" do
5657
queue_class = Class.new do
57-
include Async::Safe::Concurrent
58+
async_safe!
5859

5960
def push(item)
6061
@items ||= []

test/async/safe/monitor.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,16 @@ def read
2323
end
2424
end
2525

26-
let(:monitor) {Async::Safe.monitor}
26+
let(:monitor) do
27+
# Ensure monitor exists (created lazily):
28+
monitor = Async::Safe.instance_variable_get(:@monitor)
29+
unless monitor
30+
Async::Safe.enable!
31+
Async::Safe.disable!
32+
monitor = Async::Safe.instance_variable_get(:@monitor) || Async::Safe::Monitor.new
33+
end
34+
monitor
35+
end
2736

2837
with "#check_access" do
2938
it "records ownership on first access" do
@@ -87,7 +96,7 @@ def read
8796

8897
it "allows access to objects with ASYNC_SAFE constant" do
8998
safe_class = Class.new do
90-
include Async::Safe::Concurrent
99+
async_safe!
91100

92101
def read
93102
"data"

0 commit comments

Comments
 (0)