concurrent-ruby 1.0.5 → 1.1.10

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 (164) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +155 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +18 -18
  5. data/README.md +260 -103
  6. data/Rakefile +329 -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 → concurrent-ruby/concurrent}/agent.rb +7 -7
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +28 -24
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  31. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +7 -7
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +34 -13
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  44. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  45. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  49. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  55. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +35 -38
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +47 -33
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +20 -17
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +29 -9
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +7 -6
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  77. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  80. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +27 -16
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +54 -21
  85. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  86. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
  88. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +12 -1
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -10
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  97. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  103. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  104. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  106. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +15 -35
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -58
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  110. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  111. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -35
  113. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  114. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  115. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  116. metadata +149 -134
  117. data/lib/concurrent/array.rb +0 -39
  118. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  119. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  120. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  121. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  122. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  123. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  124. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  125. data/lib/concurrent/atomics.rb +0 -53
  126. data/lib/concurrent/edge.rb +0 -26
  127. data/lib/concurrent/hash.rb +0 -36
  128. data/lib/concurrent/lazy_register.rb +0 -81
  129. data/lib/concurrent/map.rb +0 -240
  130. data/lib/concurrent/synchronization/mri_lockable_object.rb +0 -71
  131. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  132. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  133. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  134. data/lib/concurrent/utility/at_exit.rb +0 -97
  135. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  136. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  137. data/lib/concurrent/version.rb +0 -4
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  151. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  152. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  153. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  154. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  155. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  156. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  157. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  158. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  159. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  160. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  161. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  162. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  163. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  164. /data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
@@ -0,0 +1,58 @@
1
+ module Concurrent
2
+
3
+ # Methods form module A included to a module B, which is already included into class C,
4
+ # will not be visible in the C class. If this module is extended to B then A's methods
5
+ # are correctly made visible to C.
6
+ #
7
+ # @example
8
+ # module A
9
+ # def a
10
+ # :a
11
+ # end
12
+ # end
13
+ #
14
+ # module B1
15
+ # end
16
+ #
17
+ # class C1
18
+ # include B1
19
+ # end
20
+ #
21
+ # module B2
22
+ # extend Concurrent::ReInclude
23
+ # end
24
+ #
25
+ # class C2
26
+ # include B2
27
+ # end
28
+ #
29
+ # B1.send :include, A
30
+ # B2.send :include, A
31
+ #
32
+ # C1.new.respond_to? :a # => false
33
+ # C2.new.respond_to? :a # => true
34
+ module ReInclude
35
+ # @!visibility private
36
+ def included(base)
37
+ (@re_include_to_bases ||= []) << [:include, base]
38
+ super(base)
39
+ end
40
+
41
+ # @!visibility private
42
+ def extended(base)
43
+ (@re_include_to_bases ||= []) << [:extend, base]
44
+ super(base)
45
+ end
46
+
47
+ # @!visibility private
48
+ def include(*modules)
49
+ result = super(*modules)
50
+ modules.reverse.each do |module_being_included|
51
+ (@re_include_to_bases ||= []).each do |method, mod|
52
+ mod.send method, module_being_included
53
+ end
54
+ end
55
+ result
56
+ end
57
+ end
58
+ end
@@ -58,29 +58,42 @@ module Concurrent
58
58
  # @example Basic usage
59
59
  #
60
60
  # require 'concurrent'
61
- # require 'thread' # for Queue
62
- # require 'open-uri' # for open(uri)
61
+ # require 'csv'
62
+ # require 'open-uri'
63
63
  #
64
64
  # class Ticker
65
- # def get_year_end_closing(symbol, year)
66
- # uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m"
67
- # data = open(uri) {|f| f.collect{|line| line.strip } }
68
- # data[1].split(',')[4].to_f
69
- # end
65
+ # def get_year_end_closing(symbol, year, api_key)
66
+ # uri = "https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=#{symbol}&apikey=#{api_key}&datatype=csv"
67
+ # data = []
68
+ # csv = URI.parse(uri).read
69
+ # if csv.include?('call frequency')
70
+ # return :rate_limit_exceeded
71
+ # end
72
+ # CSV.parse(csv, headers: true) do |row|
73
+ # data << row['close'].to_f if row['timestamp'].include?(year.to_s)
74
+ # end
75
+ # year_end = data.first
76
+ # year_end
77
+ # rescue => e
78
+ # p e
79
+ # end
70
80
  # end
71
81
  #
82
+ # api_key = ENV['ALPHAVANTAGE_KEY']
83
+ # abort(error_message) unless api_key
84
+ #
72
85
  # # Future
73
- # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) }
86
+ # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013, api_key) }
74
87
  # price.state #=> :pending
75
- # sleep(1) # do other stuff
76
- # price.value #=> 63.65
77
- # price.state #=> :fulfilled
88
+ # price.pending? #=> true
89
+ # price.value(0) #=> nil (does not block)
78
90
  #
79
- # # ScheduledTask
80
- # task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('INTC', 2013) }
81
- # task.state #=> :pending
82
- # sleep(3) # do other stuff
83
- # task.value #=> 25.96
91
+ # sleep(1) # do other stuff
92
+ #
93
+ # price.value #=> 63.65 (after blocking if necessary)
94
+ # price.state #=> :fulfilled
95
+ # price.fulfilled? #=> true
96
+ # price.value #=> 63.65
84
97
  #
85
98
  # @example Successful task execution
86
99
  #
@@ -0,0 +1,74 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/thread_safe/util'
3
+ require 'set'
4
+
5
+ module Concurrent
6
+
7
+ # @!macro concurrent_set
8
+ #
9
+ # A thread-safe subclass of Set. This version locks against the object
10
+ # itself for every method call, ensuring only one thread can be reading
11
+ # or writing at a time. This includes iteration methods like `#each`.
12
+ #
13
+ # @note `a += b` is **not** a **thread-safe** operation on
14
+ # `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set`
15
+ # which is union of `a` and `b`, then it writes the union to `a`.
16
+ # The read and write are independent operations they do not form a single atomic
17
+ # operation therefore when two `+=` operations are executed concurrently updates
18
+ # may be lost. Use `#merge` instead.
19
+ #
20
+ # @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set`
21
+
22
+ # @!macro internal_implementation_note
23
+ SetImplementation = case
24
+ when Concurrent.on_cruby?
25
+ # The CRuby implementation of Set is written in Ruby itself and is
26
+ # not thread safe for certain methods.
27
+ require 'monitor'
28
+ require 'concurrent/thread_safe/util/data_structures'
29
+
30
+ class CRubySet < ::Set
31
+ end
32
+
33
+ ThreadSafe::Util.make_synchronized_on_cruby CRubySet
34
+ CRubySet
35
+
36
+ when Concurrent.on_jruby?
37
+ require 'jruby/synchronized'
38
+
39
+ class JRubySet < ::Set
40
+ include JRuby::Synchronized
41
+ end
42
+
43
+ JRubySet
44
+
45
+ when Concurrent.on_rbx?
46
+ require 'monitor'
47
+ require 'concurrent/thread_safe/util/data_structures'
48
+
49
+ class RbxSet < ::Set
50
+ end
51
+
52
+ ThreadSafe::Util.make_synchronized_on_rbx RbxSet
53
+ RbxSet
54
+
55
+ when Concurrent.on_truffleruby?
56
+ require 'concurrent/thread_safe/util/data_structures'
57
+
58
+ class TruffleRubySet < ::Set
59
+ end
60
+
61
+ ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubySet
62
+ TruffleRubySet
63
+
64
+ else
65
+ warn 'Possibly unsupported Ruby implementation'
66
+ ::Set
67
+ end
68
+ private_constant :SetImplementation
69
+
70
+ # @!macro concurrent_set
71
+ class Set < SetImplementation
72
+ end
73
+ end
74
+
@@ -9,7 +9,7 @@ module Concurrent
9
9
  # or any time thereafter. Attempting to assign a value to a member
10
10
  # that has already been set will result in a `Concurrent::ImmutabilityError`.
11
11
  #
12
- # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct`
12
+ # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct`
13
13
  # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword
14
14
  module SettableStruct
15
15
  include Synchronization::AbstractStruct
@@ -91,6 +91,16 @@ module Concurrent
91
91
  raise NameError.new("no member '#{member}' in struct")
92
92
  end
93
93
 
94
+ private
95
+
96
+ # @!visibility private
97
+ def initialize_copy(original)
98
+ synchronize do
99
+ super(original)
100
+ ns_initialize_copy
101
+ end
102
+ end
103
+
94
104
  # @!macro struct_new
95
105
  def self.new(*args, &block)
96
106
  clazz_name = nil
@@ -107,6 +117,7 @@ module Concurrent
107
117
  synchronize do
108
118
  clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block)
109
119
  members.each_with_index do |member, index|
120
+ clazz.send :remove_method, member if clazz.instance_methods.include? member
110
121
  clazz.send(:define_method, member) do
111
122
  synchronize { @values[index] }
112
123
  end
@@ -6,7 +6,7 @@ module Concurrent
6
6
 
7
7
  protected
8
8
 
9
- # @!macro [attach] synchronization_object_method_synchronize
9
+ # @!macro synchronization_object_method_synchronize
10
10
  #
11
11
  # @yield runs the block synchronized against this object,
12
12
  # equivalent of java's `synchronize(this) {}`
@@ -15,7 +15,7 @@ module Concurrent
15
15
  raise NotImplementedError
16
16
  end
17
17
 
18
- # @!macro [attach] synchronization_object_method_ns_wait_until
18
+ # @!macro synchronization_object_method_ns_wait_until
19
19
  #
20
20
  # Wait until condition is met or timeout passes,
21
21
  # protects against spurious wake-ups.
@@ -45,7 +45,7 @@ module Concurrent
45
45
  end
46
46
  end
47
47
 
48
- # @!macro [attach] synchronization_object_method_ns_wait
48
+ # @!macro synchronization_object_method_ns_wait
49
49
  #
50
50
  # Wait until another thread calls #signal or #broadcast,
51
51
  # spurious wake-ups can happen.
@@ -63,7 +63,7 @@ module Concurrent
63
63
  raise NotImplementedError
64
64
  end
65
65
 
66
- # @!macro [attach] synchronization_object_method_ns_signal
66
+ # @!macro synchronization_object_method_ns_signal
67
67
  #
68
68
  # Signal one waiting thread.
69
69
  # @return [self]
@@ -78,7 +78,7 @@ module Concurrent
78
78
  raise NotImplementedError
79
79
  end
80
80
 
81
- # @!macro [attach] synchronization_object_method_ns_broadcast
81
+ # @!macro synchronization_object_method_ns_broadcast
82
82
  #
83
83
  # Broadcast to all waiting threads.
84
84
  # @return [self]
@@ -11,7 +11,7 @@ module Concurrent
11
11
  ns_initialize(*values)
12
12
  end
13
13
 
14
- # @!macro [attach] struct_length
14
+ # @!macro struct_length
15
15
  #
16
16
  # Returns the number of struct members.
17
17
  #
@@ -21,7 +21,7 @@ module Concurrent
21
21
  end
22
22
  alias_method :size, :length
23
23
 
24
- # @!macro [attach] struct_members
24
+ # @!macro struct_members
25
25
  #
26
26
  # Returns the struct members as an array of symbols.
27
27
  #
@@ -115,9 +115,20 @@ module Concurrent
115
115
  self.class.new(*self.to_h.merge(other, &block).values)
116
116
  end
117
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
+
118
129
  # @!visibility private
119
130
  def pr_underscore(clazz)
120
- word = clazz.to_s
131
+ word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229
121
132
  word.gsub!(/::/, '/')
122
133
  word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
123
134
  word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
@@ -138,18 +149,21 @@ module Concurrent
138
149
  end
139
150
  unless name.nil?
140
151
  begin
152
+ parent.send :remove_const, name if parent.const_defined?(name, false)
141
153
  parent.const_set(name, clazz)
142
- parent.const_get(name)
154
+ clazz
143
155
  rescue NameError
144
156
  raise NameError.new("identifier #{name} needs to be constant")
145
157
  end
146
158
  end
147
159
  members.each_with_index do |member, index|
160
+ clazz.send :remove_method, member if clazz.instance_methods.include? member
148
161
  clazz.send(:define_method, member) do
149
162
  @values[index]
150
163
  end
151
164
  end
152
165
  clazz.class_exec(&block) unless block.nil?
166
+ clazz.singleton_class.send :alias_method, :[], :new
153
167
  clazz
154
168
  end
155
169
  end
@@ -1,5 +1,7 @@
1
1
  module Concurrent
2
2
  module Synchronization
3
+
4
+ # @!visibility private
3
5
  # TODO (pitr-ch 04-Dec-2016): should be in edge
4
6
  class Condition < LockableObject
5
7
  safe_initialization!
@@ -3,6 +3,7 @@ module Concurrent
3
3
 
4
4
  if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
5
5
 
6
+ # @!visibility private
6
7
  module JRubyAttrVolatile
7
8
  def self.included(base)
8
9
  base.extend(ClassMethods)
@@ -1,5 +1,7 @@
1
1
  module Concurrent
2
2
  module Synchronization
3
+
4
+ # @!visibility private
3
5
  # TODO (pitr-ch 04-Dec-2016): should be in edge
4
6
  class Lock < LockableObject
5
7
  # TODO use JavaReentrantLock on JRuby
@@ -4,19 +4,17 @@ module Concurrent
4
4
  # @!visibility private
5
5
  # @!macro internal_implementation_note
6
6
  LockableObjectImplementation = case
7
- when Concurrent.on_cruby? && Concurrent.ruby_version(:<=, 1, 9, 3)
8
- MriMonitorLockableObject
9
- when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
10
- MriMutexLockableObject
7
+ when Concurrent.on_cruby?
8
+ MutexLockableObject
11
9
  when Concurrent.on_jruby?
12
10
  JRubyLockableObject
13
11
  when Concurrent.on_rbx?
14
12
  RbxLockableObject
15
- when Concurrent.on_truffle?
16
- MriMutexLockableObject
13
+ when Concurrent.on_truffleruby?
14
+ MutexLockableObject
17
15
  else
18
16
  warn 'Possibly unsupported Ruby implementation'
19
- MriMonitorLockableObject
17
+ MonitorLockableObject
20
18
  end
21
19
  private_constant :LockableObjectImplementation
22
20
 
@@ -26,12 +24,12 @@ module Concurrent
26
24
  # the classes using it. Use {Synchronization::Object} not this abstract class.
27
25
  #
28
26
  # @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).
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).
31
29
  # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
32
30
  # `Thread#wakeup` will not work on all platforms.
33
31
  #
34
- # @see {Event} implementation as an example of this class use
32
+ # @see Event implementation as an example of this class use
35
33
  #
36
34
  # @example simple
37
35
  # class AnClass < Synchronization::Object
@@ -1,6 +1,7 @@
1
1
  module Concurrent
2
2
  module Synchronization
3
3
 
4
+ # @!visibility private
4
5
  module MriAttrVolatile
5
6
  def self.included(base)
6
7
  base.extend(ClassMethods)
@@ -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
@@ -10,9 +10,10 @@ module Concurrent
10
10
  JRubyObject
11
11
  when Concurrent.on_rbx?
12
12
  RbxObject
13
- when Concurrent.on_truffle?
14
- TruffleObject
13
+ when Concurrent.on_truffleruby?
14
+ TruffleRubyObject
15
15
  else
16
+ warn 'Possibly unsupported Ruby implementation'
16
17
  MriObject
17
18
  end
18
19
  private_constant :ObjectImplementation
@@ -26,15 +27,15 @@ module Concurrent
26
27
 
27
28
  # @!method self.attr_volatile(*names)
28
29
  # Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with
29
- # volatile (Java) semantic. The instance variable should be accessed oly through generated methods.
30
+ # volatile (Java) semantic. The instance variable should be accessed only through generated methods.
30
31
  #
31
- # @param [Array<Symbol>] names of the instance variables to be volatile
32
- # @return [Array<Symbol>] names of defined method names
32
+ # @param [::Array<Symbol>] names of the instance variables to be volatile
33
+ # @return [::Array<Symbol>] names of defined method names
33
34
 
34
35
  # Has to be called by children.
35
36
  def initialize
36
37
  super
37
- initialize_volatile_with_cas
38
+ __initialize_atomic_fields__
38
39
  end
39
40
 
40
41
  # By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that
@@ -48,10 +49,12 @@ module Concurrent
48
49
  # @AFinalValue = 'value' # published safely, does not have to be synchronized
49
50
  # end
50
51
  # end
52
+ # @return [true]
51
53
  def self.safe_initialization!
52
54
  # define only once, and not again in children
53
55
  return if safe_initialization?
54
56
 
57
+ # @!visibility private
55
58
  def self.new(*args, &block)
56
59
  object = super(*args, &block)
57
60
  ensure
@@ -69,6 +72,8 @@ module Concurrent
69
72
 
70
73
  # For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains
71
74
  # any instance variables with CamelCase names and isn't {.safe_initialization?}.
75
+ # @raise when offend found
76
+ # @return [true]
72
77
  def self.ensure_safe_initialization_when_final_fields_are_present
73
78
  Object.class_eval do
74
79
  def self.new(*args, &block)
@@ -80,6 +85,7 @@ module Concurrent
80
85
  end
81
86
  end
82
87
  end
88
+ true
83
89
  end
84
90
 
85
91
  # Creates methods for reading and writing to a instance variable with
@@ -88,13 +94,30 @@ module Concurrent
88
94
  # This method generates following methods: `value`, `value=(new_value) #=> new_value`,
89
95
  # `swap_value(new_value) #=> old_value`,
90
96
  # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
91
- # @param [Array<Symbol>] names of the instance variables to be volatile with CAS.
92
- # @return [Array<Symbol>] names of defined method names.
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
93
116
  def self.attr_atomic(*names)
94
- @volatile_cas_fields ||= []
95
- @volatile_cas_fields += names
117
+ @__atomic_fields__ ||= []
118
+ @__atomic_fields__ += names
96
119
  safe_initialization!
97
- define_initialize_volatile_with_cas
120
+ define_initialize_atomic_fields
98
121
 
99
122
  names.each do |name|
100
123
  ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}"
@@ -123,29 +146,36 @@ module Concurrent
123
146
  names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] }
124
147
  end
125
148
 
126
- # @param [true,false] inherited should inherited volatile with CAS fields be returned?
127
- # @return [Array<Symbol>] Returns defined volatile with CAS fields on this class.
128
- def self.volatile_cas_fields(inherited = true)
129
- @volatile_cas_fields ||= []
130
- ((superclass.volatile_cas_fields if superclass.respond_to?(:volatile_cas_fields) && inherited) || []) +
131
- @volatile_cas_fields
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
132
159
  end
133
160
 
134
161
  private
135
162
 
136
- def self.define_initialize_volatile_with_cas
137
- assignments = @volatile_cas_fields.map { |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n")
138
- class_eval <<-RUBY
139
- def initialize_volatile_with_cas
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__
140
170
  super
141
171
  #{assignments}
142
172
  end
143
173
  RUBY
144
174
  end
145
175
 
146
- private_class_method :define_initialize_volatile_with_cas
176
+ private_class_method :define_initialize_atomic_fields
147
177
 
148
- def initialize_volatile_with_cas
178
+ def __initialize_atomic_fields__
149
179
  end
150
180
 
151
181
  end
@@ -12,6 +12,12 @@ module Concurrent
12
12
  @__owner__ = nil
13
13
  end
14
14
 
15
+ def initialize_copy(other)
16
+ super
17
+ @__Waiters__ = []
18
+ @__owner__ = nil
19
+ end
20
+
15
21
  protected
16
22
 
17
23
  def synchronize(&block)
@@ -1,6 +1,7 @@
1
1
  module Concurrent
2
2
  module Synchronization
3
3
 
4
+ # @!visibility private
4
5
  module RbxAttrVolatile
5
6
  def self.included(base)
6
7
  base.extend(ClassMethods)