concurrent-ruby 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +478 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +381 -0
  6. data/Rakefile +327 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby.rb +1 -0
  23. data/lib/concurrent.rb +134 -0
  24. data/lib/concurrent/agent.rb +587 -0
  25. data/lib/concurrent/array.rb +66 -0
  26. data/lib/concurrent/async.rb +459 -0
  27. data/lib/concurrent/atom.rb +222 -0
  28. data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  29. data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
  30. data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
  31. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/concurrent/atomic/count_down_latch.rb +100 -0
  34. data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
  35. data/lib/concurrent/atomic/event.rb +109 -0
  36. data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
  37. data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
  38. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  39. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  40. data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  41. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  42. data/lib/concurrent/atomic/read_write_lock.rb +254 -0
  43. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
  44. data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
  45. data/lib/concurrent/atomic/semaphore.rb +145 -0
  46. data/lib/concurrent/atomic/thread_local_var.rb +104 -0
  47. data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  48. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  49. data/lib/concurrent/atomics.rb +10 -0
  50. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  51. data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  52. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  53. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  55. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  56. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  57. data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  58. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  59. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  60. data/lib/concurrent/concern/deprecation.rb +34 -0
  61. data/lib/concurrent/concern/dereferenceable.rb +73 -0
  62. data/lib/concurrent/concern/logging.rb +32 -0
  63. data/lib/concurrent/concern/obligation.rb +220 -0
  64. data/lib/concurrent/concern/observable.rb +110 -0
  65. data/lib/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/concurrent/configuration.rb +184 -0
  67. data/lib/concurrent/constants.rb +8 -0
  68. data/lib/concurrent/dataflow.rb +81 -0
  69. data/lib/concurrent/delay.rb +199 -0
  70. data/lib/concurrent/errors.rb +69 -0
  71. data/lib/concurrent/exchanger.rb +352 -0
  72. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  73. data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
  74. data/lib/concurrent/executor/executor_service.rb +185 -0
  75. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
  76. data/lib/concurrent/executor/immediate_executor.rb +66 -0
  77. data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
  78. data/lib/concurrent/executor/java_executor_service.rb +91 -0
  79. data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
  80. data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
  81. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
  84. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  85. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +107 -0
  87. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  88. data/lib/concurrent/executor/simple_executor_service.rb +100 -0
  89. data/lib/concurrent/executor/single_thread_executor.rb +56 -0
  90. data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
  91. data/lib/concurrent/executor/timer_set.rb +173 -0
  92. data/lib/concurrent/executors.rb +20 -0
  93. data/lib/concurrent/future.rb +141 -0
  94. data/lib/concurrent/hash.rb +59 -0
  95. data/lib/concurrent/immutable_struct.rb +93 -0
  96. data/lib/concurrent/ivar.rb +207 -0
  97. data/lib/concurrent/map.rb +337 -0
  98. data/lib/concurrent/maybe.rb +229 -0
  99. data/lib/concurrent/mutable_struct.rb +229 -0
  100. data/lib/concurrent/mvar.rb +242 -0
  101. data/lib/concurrent/options.rb +42 -0
  102. data/lib/concurrent/promise.rb +579 -0
  103. data/lib/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent/re_include.rb +58 -0
  105. data/lib/concurrent/scheduled_task.rb +318 -0
  106. data/lib/concurrent/set.rb +66 -0
  107. data/lib/concurrent/settable_struct.rb +129 -0
  108. data/lib/concurrent/synchronization.rb +30 -0
  109. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  110. data/lib/concurrent/synchronization/abstract_object.rb +24 -0
  111. data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
  112. data/lib/concurrent/synchronization/condition.rb +60 -0
  113. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  114. data/lib/concurrent/synchronization/jruby_object.rb +45 -0
  115. data/lib/concurrent/synchronization/lock.rb +36 -0
  116. data/lib/concurrent/synchronization/lockable_object.rb +74 -0
  117. data/lib/concurrent/synchronization/mri_object.rb +44 -0
  118. data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
  119. data/lib/concurrent/synchronization/object.rb +183 -0
  120. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  121. data/lib/concurrent/synchronization/rbx_object.rb +49 -0
  122. data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/concurrent/synchronization/volatile.rb +36 -0
  124. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  125. data/lib/concurrent/thread_safe/util.rb +16 -0
  126. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  127. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  128. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  130. data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
  131. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  132. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  133. data/lib/concurrent/timer_task.rb +334 -0
  134. data/lib/concurrent/tuple.rb +86 -0
  135. data/lib/concurrent/tvar.rb +258 -0
  136. data/lib/concurrent/utility/at_exit.rb +97 -0
  137. data/lib/concurrent/utility/engine.rb +56 -0
  138. data/lib/concurrent/utility/monotonic_time.rb +58 -0
  139. data/lib/concurrent/utility/native_extension_loader.rb +79 -0
  140. data/lib/concurrent/utility/native_integer.rb +53 -0
  141. data/lib/concurrent/utility/processor_counter.rb +158 -0
  142. data/lib/concurrent/version.rb +3 -0
  143. metadata +193 -0
@@ -0,0 +1,74 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ LockableObjectImplementation = case
7
+ when Concurrent.on_cruby? && Concurrent.ruby_version(:<=, 1, 9, 3)
8
+ MonitorLockableObject
9
+ when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
10
+ MutexLockableObject
11
+ when Concurrent.on_jruby?
12
+ JRubyLockableObject
13
+ when Concurrent.on_rbx?
14
+ RbxLockableObject
15
+ when Concurrent.on_truffleruby?
16
+ MutexLockableObject
17
+ else
18
+ warn 'Possibly unsupported Ruby implementation'
19
+ MonitorLockableObject
20
+ end
21
+ private_constant :LockableObjectImplementation
22
+
23
+ # Safe synchronization under any Ruby implementation.
24
+ # It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}.
25
+ # Provides a single layer which can improve its implementation over time without changes needed to
26
+ # the classes using it. Use {Synchronization::Object} not this abstract class.
27
+ #
28
+ # @note this object does not support usage together with
29
+ # [`Thread#wakeup`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-wakeup)
30
+ # and [`Thread#raise`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-raise).
31
+ # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
32
+ # `Thread#wakeup` will not work on all platforms.
33
+ #
34
+ # @see Event implementation as an example of this class use
35
+ #
36
+ # @example simple
37
+ # class AnClass < Synchronization::Object
38
+ # def initialize
39
+ # super
40
+ # synchronize { @value = 'asd' }
41
+ # end
42
+ #
43
+ # def value
44
+ # synchronize { @value }
45
+ # end
46
+ # end
47
+ #
48
+ # @!visibility private
49
+ class LockableObject < LockableObjectImplementation
50
+
51
+ # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing
52
+ # TODO (pitr 12-Sep-2015): we inherit too much ourselves :/
53
+
54
+ # @!method initialize(*args, &block)
55
+ # @!macro synchronization_object_method_initialize
56
+
57
+ # @!method synchronize
58
+ # @!macro synchronization_object_method_synchronize
59
+
60
+ # @!method wait_until(timeout = nil, &condition)
61
+ # @!macro synchronization_object_method_ns_wait_until
62
+
63
+ # @!method wait(timeout = nil)
64
+ # @!macro synchronization_object_method_ns_wait
65
+
66
+ # @!method signal
67
+ # @!macro synchronization_object_method_ns_signal
68
+
69
+ # @!method broadcast
70
+ # @!macro synchronization_object_method_ns_broadcast
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,44 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ module MriAttrVolatile
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def attr_volatile(*names)
12
+ names.each do |name|
13
+ ivar = :"@volatile_#{name}"
14
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
+ def #{name}
16
+ #{ivar}
17
+ end
18
+
19
+ def #{name}=(value)
20
+ #{ivar} = value
21
+ end
22
+ RUBY
23
+ end
24
+ names.map { |n| [n, :"#{n}="] }.flatten
25
+ end
26
+ end
27
+
28
+ def full_memory_barrier
29
+ # relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
30
+ # https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
31
+ end
32
+ end
33
+
34
+ # @!visibility private
35
+ # @!macro internal_implementation_note
36
+ class MriObject < AbstractObject
37
+ include MriAttrVolatile
38
+
39
+ def initialize
40
+ # nothing to do
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ module Concurrent
2
+ # noinspection RubyInstanceVariableNamingConvention
3
+ module Synchronization
4
+
5
+ # @!visibility private
6
+ # @!macro internal_implementation_note
7
+ module ConditionSignalling
8
+ protected
9
+
10
+ def ns_signal
11
+ @__Condition__.signal
12
+ self
13
+ end
14
+
15
+ def ns_broadcast
16
+ @__Condition__.broadcast
17
+ self
18
+ end
19
+ end
20
+
21
+
22
+ # @!visibility private
23
+ # @!macro internal_implementation_note
24
+ class MutexLockableObject < AbstractLockableObject
25
+ include ConditionSignalling
26
+
27
+ safe_initialization!
28
+
29
+ def initialize(*defaults)
30
+ super(*defaults)
31
+ @__Lock__ = ::Mutex.new
32
+ @__Condition__ = ::ConditionVariable.new
33
+ end
34
+
35
+ protected
36
+
37
+ def synchronize
38
+ if @__Lock__.owned?
39
+ yield
40
+ else
41
+ @__Lock__.synchronize { yield }
42
+ end
43
+ end
44
+
45
+ def ns_wait(timeout = nil)
46
+ @__Condition__.wait @__Lock__, timeout
47
+ self
48
+ end
49
+ end
50
+
51
+ # @!visibility private
52
+ # @!macro internal_implementation_note
53
+ class MonitorLockableObject < AbstractLockableObject
54
+ include ConditionSignalling
55
+
56
+ safe_initialization!
57
+
58
+ def initialize(*defaults)
59
+ super(*defaults)
60
+ @__Lock__ = ::Monitor.new
61
+ @__Condition__ = @__Lock__.new_cond
62
+ end
63
+
64
+ protected
65
+
66
+ def synchronize # TODO may be a problem with lock.synchronize { lock.wait }
67
+ @__Lock__.synchronize { yield }
68
+ end
69
+
70
+ def ns_wait(timeout = nil)
71
+ @__Condition__.wait timeout
72
+ self
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,183 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ ObjectImplementation = case
7
+ when Concurrent.on_cruby?
8
+ MriObject
9
+ when Concurrent.on_jruby?
10
+ JRubyObject
11
+ when Concurrent.on_rbx?
12
+ RbxObject
13
+ when Concurrent.on_truffleruby?
14
+ TruffleRubyObject
15
+ else
16
+ warn 'Possibly unsupported Ruby implementation'
17
+ MriObject
18
+ end
19
+ private_constant :ObjectImplementation
20
+
21
+ # Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.
22
+ # - final instance variables see {Object.safe_initialization!}
23
+ # - volatile instance variables see {Object.attr_volatile}
24
+ # - volatile instance variables see {Object.attr_atomic}
25
+ class Object < ObjectImplementation
26
+ # TODO make it a module if possible
27
+
28
+ # @!method self.attr_volatile(*names)
29
+ # Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with
30
+ # volatile (Java) semantic. The instance variable should be accessed only through generated methods.
31
+ #
32
+ # @param [::Array<Symbol>] names of the instance variables to be volatile
33
+ # @return [::Array<Symbol>] names of defined method names
34
+
35
+ # Has to be called by children.
36
+ def initialize
37
+ super
38
+ __initialize_atomic_fields__
39
+ end
40
+
41
+ # By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that
42
+ # all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures
43
+ # same behaviour as Java's final fields.
44
+ # @example
45
+ # class AClass < Concurrent::Synchronization::Object
46
+ # safe_initialization!
47
+ #
48
+ # def initialize
49
+ # @AFinalValue = 'value' # published safely, does not have to be synchronized
50
+ # end
51
+ # end
52
+ # @return [true]
53
+ def self.safe_initialization!
54
+ # define only once, and not again in children
55
+ return if safe_initialization?
56
+
57
+ # @!visibility private
58
+ def self.new(*args, &block)
59
+ object = super(*args, &block)
60
+ ensure
61
+ object.full_memory_barrier if object
62
+ end
63
+
64
+ @safe_initialization = true
65
+ end
66
+
67
+ # @return [true, false] if this class is safely initialized.
68
+ def self.safe_initialization?
69
+ @safe_initialization = false unless defined? @safe_initialization
70
+ @safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?)
71
+ end
72
+
73
+ # For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains
74
+ # any instance variables with CamelCase names and isn't {.safe_initialization?}.
75
+ # @raise when offend found
76
+ # @return [true]
77
+ def self.ensure_safe_initialization_when_final_fields_are_present
78
+ Object.class_eval do
79
+ def self.new(*args, &block)
80
+ object = super(*args, &block)
81
+ ensure
82
+ has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ }
83
+ if has_final_field && !safe_initialization?
84
+ raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!"
85
+ end
86
+ end
87
+ end
88
+ true
89
+ end
90
+
91
+ # Creates methods for reading and writing to a instance variable with
92
+ # volatile (Java) semantic as {.attr_volatile} does.
93
+ # The instance variable should be accessed oly through generated methods.
94
+ # This method generates following methods: `value`, `value=(new_value) #=> new_value`,
95
+ # `swap_value(new_value) #=> old_value`,
96
+ # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
97
+ # @param [::Array<Symbol>] names of the instance variables to be volatile with CAS.
98
+ # @return [::Array<Symbol>] names of defined method names.
99
+ # @!macro attr_atomic
100
+ # @!method $1
101
+ # @return [Object] The $1.
102
+ # @!method $1=(new_$1)
103
+ # Set the $1.
104
+ # @return [Object] new_$1.
105
+ # @!method swap_$1(new_$1)
106
+ # Set the $1 to new_$1 and return the old $1.
107
+ # @return [Object] old $1
108
+ # @!method compare_and_set_$1(expected_$1, new_$1)
109
+ # Sets the $1 to new_$1 if the current $1 is expected_$1
110
+ # @return [true, false]
111
+ # @!method update_$1(&block)
112
+ # Updates the $1 using the block.
113
+ # @yield [Object] Calculate a new $1 using given (old) $1
114
+ # @yieldparam [Object] old $1
115
+ # @return [Object] new $1
116
+ def self.attr_atomic(*names)
117
+ @__atomic_fields__ ||= []
118
+ @__atomic_fields__ += names
119
+ safe_initialization!
120
+ define_initialize_atomic_fields
121
+
122
+ names.each do |name|
123
+ ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}"
124
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
125
+ def #{name}
126
+ #{ivar}.get
127
+ end
128
+
129
+ def #{name}=(value)
130
+ #{ivar}.set value
131
+ end
132
+
133
+ def swap_#{name}(value)
134
+ #{ivar}.swap value
135
+ end
136
+
137
+ def compare_and_set_#{name}(expected, value)
138
+ #{ivar}.compare_and_set expected, value
139
+ end
140
+
141
+ def update_#{name}(&block)
142
+ #{ivar}.update(&block)
143
+ end
144
+ RUBY
145
+ end
146
+ names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] }
147
+ end
148
+
149
+ # @param [true, false] inherited should inherited volatile with CAS fields be returned?
150
+ # @return [::Array<Symbol>] Returns defined volatile with CAS fields on this class.
151
+ def self.atomic_attributes(inherited = true)
152
+ @__atomic_fields__ ||= []
153
+ ((superclass.atomic_attributes if superclass.respond_to?(:atomic_attributes) && inherited) || []) + @__atomic_fields__
154
+ end
155
+
156
+ # @return [true, false] is the attribute with name atomic?
157
+ def self.atomic_attribute?(name)
158
+ atomic_attributes.include? name
159
+ end
160
+
161
+ private
162
+
163
+ def self.define_initialize_atomic_fields
164
+ assignments = @__atomic_fields__.map do |name|
165
+ "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = Concurrent::AtomicReference.new(nil)"
166
+ end.join("\n")
167
+
168
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
169
+ def __initialize_atomic_fields__
170
+ super
171
+ #{assignments}
172
+ end
173
+ RUBY
174
+ end
175
+
176
+ private_class_method :define_initialize_atomic_fields
177
+
178
+ def __initialize_atomic_fields__
179
+ end
180
+
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,65 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ class RbxLockableObject < AbstractLockableObject
7
+ safe_initialization!
8
+
9
+ def initialize(*defaults)
10
+ super(*defaults)
11
+ @__Waiters__ = []
12
+ @__owner__ = nil
13
+ end
14
+
15
+ protected
16
+
17
+ def synchronize(&block)
18
+ if @__owner__ == Thread.current
19
+ yield
20
+ else
21
+ result = nil
22
+ Rubinius.synchronize(self) do
23
+ begin
24
+ @__owner__ = Thread.current
25
+ result = yield
26
+ ensure
27
+ @__owner__ = nil
28
+ end
29
+ end
30
+ result
31
+ end
32
+ end
33
+
34
+ def ns_wait(timeout = nil)
35
+ wchan = Rubinius::Channel.new
36
+
37
+ begin
38
+ @__Waiters__.push wchan
39
+ Rubinius.unlock(self)
40
+ signaled = wchan.receive_timeout timeout
41
+ ensure
42
+ Rubinius.lock(self)
43
+
44
+ if !signaled && !@__Waiters__.delete(wchan)
45
+ # we timed out, but got signaled afterwards,
46
+ # so pass that signal on to the next waiter
47
+ @__Waiters__.shift << true unless @__Waiters__.empty?
48
+ end
49
+ end
50
+
51
+ self
52
+ end
53
+
54
+ def ns_signal
55
+ @__Waiters__.shift << true unless @__Waiters__.empty?
56
+ self
57
+ end
58
+
59
+ def ns_broadcast
60
+ @__Waiters__.shift << true until @__Waiters__.empty?
61
+ self
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ module RbxAttrVolatile
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ def attr_volatile(*names)
13
+ names.each do |name|
14
+ ivar = :"@volatile_#{name}"
15
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
+ def #{name}
17
+ Rubinius.memory_barrier
18
+ #{ivar}
19
+ end
20
+
21
+ def #{name}=(value)
22
+ #{ivar} = value
23
+ Rubinius.memory_barrier
24
+ end
25
+ RUBY
26
+ end
27
+ names.map { |n| [n, :"#{n}="] }.flatten
28
+ end
29
+
30
+ end
31
+
32
+ def full_memory_barrier
33
+ # Rubinius instance variables are not volatile so we need to insert barrier
34
+ # TODO (pitr 26-Nov-2015): check comments like ^
35
+ Rubinius.memory_barrier
36
+ end
37
+ end
38
+
39
+ # @!visibility private
40
+ # @!macro internal_implementation_note
41
+ class RbxObject < AbstractObject
42
+ include RbxAttrVolatile
43
+
44
+ def initialize
45
+ # nothing to do
46
+ end
47
+ end
48
+ end
49
+ end