concurrent-ruby 1.1.5

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.
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