concurrent-ruby 1.0.5 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
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)