o-concurrent-ruby 1.1.11

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 (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +542 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +404 -0
  6. data/Rakefile +307 -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 +189 -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/concurrent/agent.rb +587 -0
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/concurrent-ruby/concurrent/async.rb +449 -0
  25. data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
  26. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  27. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  30. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  31. data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
  33. data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
  34. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
  35. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
  36. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  37. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  38. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  39. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
  40. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
  41. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
  42. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
  43. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
  44. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
  45. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  46. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  47. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  48. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  49. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  50. data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  51. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  52. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  53. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
  54. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  55. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  56. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  57. data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  58. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
  59. data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
  60. data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
  61. data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
  62. data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
  63. data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
  64. data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
  65. data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
  66. data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
  67. data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
  68. data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
  69. data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
  70. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
  71. data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
  72. data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
  73. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
  74. data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
  75. data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
  76. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
  77. data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
  78. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
  79. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
  80. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
  81. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
  82. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
  83. data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
  84. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
  85. data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
  86. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
  87. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
  88. data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
  89. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
  90. data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
  91. data/lib/concurrent-ruby/concurrent/future.rb +141 -0
  92. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  93. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
  94. data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
  95. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  96. data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
  97. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
  98. data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
  99. data/lib/concurrent-ruby/concurrent/options.rb +42 -0
  100. data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
  101. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  102. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  103. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
  104. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  105. data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
  106. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  107. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
  108. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
  109. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
  110. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  111. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
  112. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
  113. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
  114. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
  115. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  116. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
  117. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
  118. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
  119. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  120. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
  121. data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
  122. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  123. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
  124. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  125. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  126. data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  127. data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
  129. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  130. data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
  131. data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
  132. data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
  133. data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
  134. data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
  135. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  136. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  137. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
  138. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
  139. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  140. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  141. data/lib/concurrent-ruby/concurrent.rb +134 -0
  142. metadata +192 -0
@@ -0,0 +1,24 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ class AbstractObject
7
+
8
+ # @abstract has to be implemented based on Ruby runtime
9
+ def initialize
10
+ raise NotImplementedError
11
+ end
12
+
13
+ # @!visibility private
14
+ # @abstract
15
+ def full_memory_barrier
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def self.attr_volatile(*names)
20
+ raise NotImplementedError
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,171 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ module AbstractStruct
7
+
8
+ # @!visibility private
9
+ def initialize(*values)
10
+ super()
11
+ ns_initialize(*values)
12
+ end
13
+
14
+ # @!macro struct_length
15
+ #
16
+ # Returns the number of struct members.
17
+ #
18
+ # @return [Fixnum] the number of struct members
19
+ def length
20
+ self.class::MEMBERS.length
21
+ end
22
+ alias_method :size, :length
23
+
24
+ # @!macro struct_members
25
+ #
26
+ # Returns the struct members as an array of symbols.
27
+ #
28
+ # @return [Array] the struct members as an array of symbols
29
+ def members
30
+ self.class::MEMBERS.dup
31
+ end
32
+
33
+ protected
34
+
35
+ # @!macro struct_values
36
+ #
37
+ # @!visibility private
38
+ def ns_values
39
+ @values.dup
40
+ end
41
+
42
+ # @!macro struct_values_at
43
+ #
44
+ # @!visibility private
45
+ def ns_values_at(indexes)
46
+ @values.values_at(*indexes)
47
+ end
48
+
49
+ # @!macro struct_to_h
50
+ #
51
+ # @!visibility private
52
+ def ns_to_h
53
+ length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo}
54
+ end
55
+
56
+ # @!macro struct_get
57
+ #
58
+ # @!visibility private
59
+ def ns_get(member)
60
+ if member.is_a? Integer
61
+ if member >= @values.length
62
+ raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})")
63
+ end
64
+ @values[member]
65
+ else
66
+ send(member)
67
+ end
68
+ rescue NoMethodError
69
+ raise NameError.new("no member '#{member}' in struct")
70
+ end
71
+
72
+ # @!macro struct_equality
73
+ #
74
+ # @!visibility private
75
+ def ns_equality(other)
76
+ self.class == other.class && self.values == other.values
77
+ end
78
+
79
+ # @!macro struct_each
80
+ #
81
+ # @!visibility private
82
+ def ns_each
83
+ values.each{|value| yield value }
84
+ end
85
+
86
+ # @!macro struct_each_pair
87
+ #
88
+ # @!visibility private
89
+ def ns_each_pair
90
+ @values.length.times do |index|
91
+ yield self.class::MEMBERS[index], @values[index]
92
+ end
93
+ end
94
+
95
+ # @!macro struct_select
96
+ #
97
+ # @!visibility private
98
+ def ns_select
99
+ values.select{|value| yield value }
100
+ end
101
+
102
+ # @!macro struct_inspect
103
+ #
104
+ # @!visibility private
105
+ def ns_inspect
106
+ struct = pr_underscore(self.class.ancestors[1])
107
+ clazz = ((self.class.to_s =~ /^#<Class:/) == 0) ? '' : " #{self.class}"
108
+ "#<#{struct}#{clazz} #{ns_to_h}>"
109
+ end
110
+
111
+ # @!macro struct_merge
112
+ #
113
+ # @!visibility private
114
+ def ns_merge(other, &block)
115
+ self.class.new(*self.to_h.merge(other, &block).values)
116
+ end
117
+
118
+ # @!visibility private
119
+ def ns_initialize_copy
120
+ @values = @values.map do |val|
121
+ begin
122
+ val.clone
123
+ rescue TypeError
124
+ val
125
+ end
126
+ end
127
+ end
128
+
129
+ # @!visibility private
130
+ def pr_underscore(clazz)
131
+ word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229
132
+ word.gsub!(/::/, '/')
133
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
134
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
135
+ word.tr!("-", "_")
136
+ word.downcase!
137
+ word
138
+ end
139
+
140
+ # @!visibility private
141
+ def self.define_struct_class(parent, base, name, members, &block)
142
+ clazz = Class.new(base || Object) do
143
+ include parent
144
+ self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze)
145
+ def ns_initialize(*values)
146
+ raise ArgumentError.new('struct size differs') if values.length > length
147
+ @values = values.fill(nil, values.length..length-1)
148
+ end
149
+ end
150
+ unless name.nil?
151
+ begin
152
+ parent.send :remove_const, name if parent.const_defined?(name, false)
153
+ parent.const_set(name, clazz)
154
+ clazz
155
+ rescue NameError
156
+ raise NameError.new("identifier #{name} needs to be constant")
157
+ end
158
+ end
159
+ members.each_with_index do |member, index|
160
+ clazz.send :remove_method, member if clazz.instance_methods.include? member
161
+ clazz.send(:define_method, member) do
162
+ @values[index]
163
+ end
164
+ end
165
+ clazz.class_exec(&block) unless block.nil?
166
+ clazz.singleton_class.send :alias_method, :[], :new
167
+ clazz
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,60 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # TODO (pitr-ch 04-Dec-2016): should be in edge
6
+ class Condition < LockableObject
7
+ safe_initialization!
8
+
9
+ # TODO (pitr 12-Sep-2015): locks two objects, improve
10
+ # TODO (pitr 26-Sep-2015): study
11
+ # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/concurrent/locks/AbstractQueuedSynchronizer.java#AbstractQueuedSynchronizer.Node
12
+
13
+ singleton_class.send :alias_method, :private_new, :new
14
+ private_class_method :new
15
+
16
+ def initialize(lock)
17
+ super()
18
+ @Lock = lock
19
+ end
20
+
21
+ def wait(timeout = nil)
22
+ @Lock.synchronize { ns_wait(timeout) }
23
+ end
24
+
25
+ def ns_wait(timeout = nil)
26
+ synchronize { super(timeout) }
27
+ end
28
+
29
+ def wait_until(timeout = nil, &condition)
30
+ @Lock.synchronize { ns_wait_until(timeout, &condition) }
31
+ end
32
+
33
+ def ns_wait_until(timeout = nil, &condition)
34
+ synchronize { super(timeout, &condition) }
35
+ end
36
+
37
+ def signal
38
+ @Lock.synchronize { ns_signal }
39
+ end
40
+
41
+ def ns_signal
42
+ synchronize { super }
43
+ end
44
+
45
+ def broadcast
46
+ @Lock.synchronize { ns_broadcast }
47
+ end
48
+
49
+ def ns_broadcast
50
+ synchronize { super }
51
+ end
52
+ end
53
+
54
+ class LockableObject < LockableObjectImplementation
55
+ def new_condition
56
+ Condition.private_new(self)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
5
+
6
+ # @!visibility private
7
+ # @!macro internal_implementation_note
8
+ class JRubyLockableObject < AbstractLockableObject
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
5
+
6
+ # @!visibility private
7
+ module JRubyAttrVolatile
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def attr_volatile(*names)
14
+ names.each do |name|
15
+
16
+ ivar = :"@volatile_#{name}"
17
+
18
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
19
+ def #{name}
20
+ instance_variable_get_volatile(:#{ivar})
21
+ end
22
+
23
+ def #{name}=(value)
24
+ instance_variable_set_volatile(:#{ivar}, value)
25
+ end
26
+ RUBY
27
+
28
+ end
29
+ names.map { |n| [n, :"#{n}="] }.flatten
30
+ end
31
+ end
32
+ end
33
+
34
+ # @!visibility private
35
+ # @!macro internal_implementation_note
36
+ class JRubyObject < AbstractObject
37
+ include JRubyAttrVolatile
38
+
39
+ def initialize
40
+ # nothing to do
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # TODO (pitr-ch 04-Dec-2016): should be in edge
6
+ class Lock < LockableObject
7
+ # TODO use JavaReentrantLock on JRuby
8
+
9
+ public :synchronize
10
+
11
+ def wait(timeout = nil)
12
+ synchronize { ns_wait(timeout) }
13
+ end
14
+
15
+ public :ns_wait
16
+
17
+ def wait_until(timeout = nil, &condition)
18
+ synchronize { ns_wait_until(timeout, &condition) }
19
+ end
20
+
21
+ public :ns_wait_until
22
+
23
+ def signal
24
+ synchronize { ns_signal }
25
+ end
26
+
27
+ public :ns_signal
28
+
29
+ def broadcast
30
+ synchronize { ns_broadcast }
31
+ end
32
+
33
+ public :ns_broadcast
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,72 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ LockableObjectImplementation = case
7
+ when Concurrent.on_cruby?
8
+ MutexLockableObject
9
+ when Concurrent.on_jruby?
10
+ JRubyLockableObject
11
+ when Concurrent.on_rbx?
12
+ RbxLockableObject
13
+ when Concurrent.on_truffleruby?
14
+ MutexLockableObject
15
+ else
16
+ warn 'Possibly unsupported Ruby implementation'
17
+ MonitorLockableObject
18
+ end
19
+ private_constant :LockableObjectImplementation
20
+
21
+ # Safe synchronization under any Ruby implementation.
22
+ # It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}.
23
+ # Provides a single layer which can improve its implementation over time without changes needed to
24
+ # the classes using it. Use {Synchronization::Object} not this abstract class.
25
+ #
26
+ # @note this object does not support usage together with
27
+ # [`Thread#wakeup`](http://ruby-doc.org/core/Thread.html#method-i-wakeup)
28
+ # and [`Thread#raise`](http://ruby-doc.org/core/Thread.html#method-i-raise).
29
+ # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
30
+ # `Thread#wakeup` will not work on all platforms.
31
+ #
32
+ # @see Event implementation as an example of this class use
33
+ #
34
+ # @example simple
35
+ # class AnClass < Synchronization::Object
36
+ # def initialize
37
+ # super
38
+ # synchronize { @value = 'asd' }
39
+ # end
40
+ #
41
+ # def value
42
+ # synchronize { @value }
43
+ # end
44
+ # end
45
+ #
46
+ # @!visibility private
47
+ class LockableObject < LockableObjectImplementation
48
+
49
+ # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing
50
+ # TODO (pitr 12-Sep-2015): we inherit too much ourselves :/
51
+
52
+ # @!method initialize(*args, &block)
53
+ # @!macro synchronization_object_method_initialize
54
+
55
+ # @!method synchronize
56
+ # @!macro synchronization_object_method_synchronize
57
+
58
+ # @!method wait_until(timeout = nil, &condition)
59
+ # @!macro synchronization_object_method_ns_wait_until
60
+
61
+ # @!method wait(timeout = nil)
62
+ # @!macro synchronization_object_method_ns_wait
63
+
64
+ # @!method signal
65
+ # @!macro synchronization_object_method_ns_signal
66
+
67
+ # @!method broadcast
68
+ # @!macro synchronization_object_method_ns_broadcast
69
+
70
+ end
71
+ end
72
+ 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,88 @@
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
+ def initialize_copy(other)
36
+ super
37
+ @__Lock__ = ::Mutex.new
38
+ @__Condition__ = ::ConditionVariable.new
39
+ end
40
+
41
+ protected
42
+
43
+ def synchronize
44
+ if @__Lock__.owned?
45
+ yield
46
+ else
47
+ @__Lock__.synchronize { yield }
48
+ end
49
+ end
50
+
51
+ def ns_wait(timeout = nil)
52
+ @__Condition__.wait @__Lock__, timeout
53
+ self
54
+ end
55
+ end
56
+
57
+ # @!visibility private
58
+ # @!macro internal_implementation_note
59
+ class MonitorLockableObject < AbstractLockableObject
60
+ include ConditionSignalling
61
+
62
+ safe_initialization!
63
+
64
+ def initialize(*defaults)
65
+ super(*defaults)
66
+ @__Lock__ = ::Monitor.new
67
+ @__Condition__ = @__Lock__.new_cond
68
+ end
69
+
70
+ def initialize_copy(other)
71
+ super
72
+ @__Lock__ = ::Monitor.new
73
+ @__Condition__ = @__Lock__.new_cond
74
+ end
75
+
76
+ protected
77
+
78
+ def synchronize # TODO may be a problem with lock.synchronize { lock.wait }
79
+ @__Lock__.synchronize { yield }
80
+ end
81
+
82
+ def ns_wait(timeout = nil)
83
+ @__Condition__.wait timeout
84
+ self
85
+ end
86
+ end
87
+ end
88
+ end