concurrent-ruby 1.1.5 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -1
  3. data/Gemfile +5 -10
  4. data/{LICENSE.md → LICENSE.txt} +18 -20
  5. data/README.md +55 -31
  6. data/Rakefile +84 -92
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  10. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +2 -1
  11. data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +6 -16
  12. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +10 -20
  13. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +2 -2
  14. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +7 -6
  15. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +5 -4
  16. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +3 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +135 -0
  18. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  19. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  20. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  21. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +1 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +11 -5
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +11 -5
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -1
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +19 -3
  28. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  29. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +9 -9
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +32 -14
  31. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +111 -0
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +15 -4
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +1 -1
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +1 -1
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +2 -0
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +3 -3
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +16 -8
  39. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
  42. data/lib/concurrent-ruby/concurrent/concern/logging.rb +116 -0
  43. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  44. data/lib/concurrent-ruby/concurrent/configuration.rb +105 -0
  45. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +2 -2
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +5 -0
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +1 -0
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +34 -37
  49. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +29 -15
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +21 -9
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +19 -2
  55. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +6 -6
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +1 -1
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +5 -2
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +0 -1
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +1 -10
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +10 -2
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +2 -1
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +44 -31
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +13 -3
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +1 -1
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +2 -1
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +7 -6
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +2 -0
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +30 -17
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +17 -19
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +13 -3
  77. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -1
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +1 -3
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +11 -0
  80. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  81. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +3 -1
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -7
  85. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +18 -5
  86. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +12 -44
  87. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  88. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +101 -0
  89. data/lib/concurrent-ruby/concurrent/synchronization.rb +13 -0
  90. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +47 -0
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +2 -39
  92. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +52 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +11 -34
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -5
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -57
  97. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +5 -16
  98. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +19 -0
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +8 -10
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +110 -0
  102. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  103. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  104. metadata +127 -129
  105. data/lib/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  106. data/lib/concurrent/atomic/atomic_reference.rb +0 -204
  107. data/lib/concurrent/atomic/java_thread_local_var.rb +0 -37
  108. data/lib/concurrent/atomic/ruby_thread_local_var.rb +0 -161
  109. data/lib/concurrent/atomic/thread_local_var.rb +0 -104
  110. data/lib/concurrent/concern/logging.rb +0 -32
  111. data/lib/concurrent/concurrent_ruby.jar +0 -0
  112. data/lib/concurrent/configuration.rb +0 -184
  113. data/lib/concurrent/synchronization/jruby_object.rb +0 -45
  114. data/lib/concurrent/synchronization/mri_object.rb +0 -44
  115. data/lib/concurrent/synchronization/rbx_lockable_object.rb +0 -65
  116. data/lib/concurrent/synchronization/rbx_object.rb +0 -49
  117. data/lib/concurrent/synchronization/truffleruby_object.rb +0 -47
  118. data/lib/concurrent/synchronization/volatile.rb +0 -36
  119. data/lib/concurrent/synchronization.rb +0 -30
  120. data/lib/concurrent/thread_safe/synchronized_delegator.rb +0 -50
  121. data/lib/concurrent/thread_safe/util/data_structures.rb +0 -63
  122. data/lib/concurrent/utility/at_exit.rb +0 -97
  123. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  124. data/lib/concurrent/utility/processor_counter.rb +0 -158
  125. data/lib/concurrent/version.rb +0 -3
  126. data/lib/concurrent-ruby.rb +0 -1
  127. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
  128. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
  129. data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
  130. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  131. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
  132. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  133. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
  134. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  135. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  136. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
  137. /data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  151. /data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
data/Rakefile CHANGED
@@ -1,14 +1,6 @@
1
- require_relative 'lib/concurrent/version'
2
- require_relative 'lib/concurrent/utility/engine'
3
-
4
- if Concurrent.ruby_version :<, 2, 0, 0
5
- # @!visibility private
6
- module Kernel
7
- def __dir__
8
- File.dirname __FILE__
9
- end
10
- end
11
- end
1
+ require_relative 'lib/concurrent-ruby/concurrent/version'
2
+ require_relative 'lib/concurrent-ruby-edge/concurrent/edge/version'
3
+ require_relative 'lib/concurrent-ruby/concurrent/utility/engine'
12
4
 
13
5
  core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
14
6
  ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
@@ -16,17 +8,19 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
16
8
 
17
9
  require 'rake/javaextensiontask'
18
10
 
11
+ ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && !Concurrent.on_jruby?
12
+
19
13
  Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
20
14
  ext.ext_dir = 'ext/concurrent-ruby'
21
- ext.lib_dir = 'lib/concurrent'
15
+ ext.lib_dir = 'lib/concurrent-ruby/concurrent'
22
16
  end
23
17
 
24
- unless Concurrent.on_jruby?
18
+ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
25
19
  require 'rake/extensiontask'
26
20
 
27
21
  Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
28
22
  ext.ext_dir = 'ext/concurrent-ruby-ext'
29
- ext.lib_dir = 'lib/concurrent'
23
+ ext.lib_dir = 'lib/concurrent-ruby/concurrent'
30
24
  ext.source_pattern = '*.{c,h}'
31
25
 
32
26
  ext.cross_compile = true
@@ -40,13 +34,21 @@ namespace :repackage do
40
34
  task :all do
41
35
  Dir.chdir(__dir__) do
42
36
  # store gems in vendor cache for docker
43
- sh 'bundle package'
37
+ Bundler.with_original_env do
38
+ sh 'bundle package'
39
+ end
44
40
 
45
41
  # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
46
- Rake::Task['lib/concurrent/concurrent_ruby.jar'].invoke
42
+ Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke
47
43
 
48
44
  # build all gem files
49
- RakeCompilerDock.sh 'bundle install --local && bundle exec rake cross native package --trace'
45
+ %w[x86-mingw32 x64-mingw32].each do |plat|
46
+ RakeCompilerDock.sh(
47
+ "bundle install --local && bundle exec rake native:#{plat} gem --trace",
48
+ platform: plat,
49
+ options: ['--privileged'], # otherwise the directory in the image is empty
50
+ runas: false)
51
+ end
50
52
  end
51
53
  end
52
54
  end
@@ -58,7 +60,10 @@ Gem::PackageTask.new(core_gemspec) {} if core_gemspec
58
60
  Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
59
61
  Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
60
62
 
61
- CLEAN.include('lib/concurrent/2.*', 'lib/concurrent/*.jar')
63
+ CLEAN.include(
64
+ 'lib/concurrent-ruby/concurrent/concurrent_ruby_ext.*',
65
+ 'lib/concurrent-ruby/concurrent/2.*',
66
+ 'lib/concurrent-ruby/concurrent/*.jar')
62
67
 
63
68
  begin
64
69
  require 'rspec'
@@ -72,20 +77,21 @@ begin
72
77
  options = %w[ --color
73
78
  --backtrace
74
79
  --order defined
75
- --format documentation
76
- --tag ~notravis ]
80
+ --format documentation ]
77
81
  t.rspec_opts = [*options].join(' ')
78
82
  end
79
83
 
80
84
  desc '* test packaged and installed gems instead of local files'
81
85
  task :installed do
82
- Dir.chdir(__dir__) do
83
- sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
84
- sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
85
- sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
86
- ENV['NO_PATH'] = 'true'
87
- sh 'bundle update'
88
- sh 'bundle exec rake spec:ci'
86
+ Bundler.with_original_env do
87
+ Dir.chdir(__dir__) do
88
+ sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
89
+ sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
90
+ sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
91
+ ENV['NO_PATH'] = 'true'
92
+ sh 'bundle update'
93
+ sh 'bundle exec rake spec:ci'
94
+ end
89
95
  end
90
96
  end
91
97
  end
@@ -93,6 +99,19 @@ begin
93
99
  desc 'executed in CI'
94
100
  task :ci => [:compile, 'spec:ci']
95
101
 
102
+ desc 'run each spec file in a separate process to help find missing requires'
103
+ task 'spec:isolated' do
104
+ glob = "#{ENV['DIR'] || 'spec'}/**/*_spec.rb"
105
+ from = ENV['FROM']
106
+ env = { 'ISOLATED' => 'true' }
107
+ Dir[glob].each do |spec|
108
+ next if from and from != spec
109
+ from = nil if from == spec
110
+
111
+ sh env, 'rspec', spec
112
+ end
113
+ end
114
+
96
115
  task :default => [:clobber, :compile, :spec]
97
116
  rescue LoadError => e
98
117
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
@@ -130,7 +149,7 @@ begin
130
149
  task :update_readme do
131
150
  Dir.chdir __dir__ do
132
151
  content = File.read(File.join('README.md')).
133
- gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
152
+ gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
134
153
  case $1
135
154
  when 'LockFreeLinkedSet'
136
155
  "{Concurrent::Edge::#{$1} #{$1}}"
@@ -160,20 +179,22 @@ begin
160
179
  desc "* of #{name} into subdir #{name}"
161
180
  YARD::Rake::YardocTask.new(name) do |yard|
162
181
  yard.options.push(
163
- '--output-dir', output_dir,
164
- '--main', 'tmp/README.md',
165
- *common_yard_options)
166
- yard.files = ['./lib/**/*.rb',
167
- './lib-edge/**/*.rb',
182
+ '--output-dir', output_dir,
183
+ '--main', 'tmp/README.md',
184
+ *common_yard_options)
185
+ yard.files = ['./lib/concurrent-ruby/**/*.rb',
186
+ './lib/concurrent-ruby-edge/**/*.rb',
168
187
  './ext/concurrent_ruby_ext/**/*.c',
169
188
  '-',
170
189
  'docs-source/thread_pools.md',
171
190
  'docs-source/promises.out.md',
172
191
  'docs-source/medium-example.out.rb',
173
- 'LICENSE.md',
192
+ 'LICENSE.txt',
174
193
  'CHANGELOG.md']
175
194
  end
176
- Rake::Task[name].prerequisites.push removal_name, 'yard:eval_md', 'yard:update_readme'
195
+ Rake::Task[name].prerequisites.push removal_name,
196
+ # 'yard:eval_md',
197
+ 'yard:update_readme'
177
198
  end
178
199
 
179
200
  define_yard_task.call current_yard_version_name
@@ -182,39 +203,11 @@ begin
182
203
  desc "* signpost for versions"
183
204
  YARD::Rake::YardocTask.new(:signpost) do |yard|
184
205
  yard.options.push(
185
- '--output-dir', 'docs',
186
- '--main', 'docs-source/signpost.md',
187
- *common_yard_options)
206
+ '--output-dir', 'docs',
207
+ '--main', 'docs-source/signpost.md',
208
+ *common_yard_options)
188
209
  yard.files = ['no-lib']
189
210
  end
190
-
191
- define_uptodate_task = -> name do
192
- namespace name do
193
- desc "** ensure that #{name} generated documentation is matching the source code"
194
- task :uptodate do
195
- Dir.chdir(__dir__) do
196
- begin
197
- FileUtils.cp_r 'docs', 'docs-copy', verbose: true
198
- Rake::Task["yard:#{name}"].invoke
199
- sh 'diff -r docs/ docs-copy/' do |ok, res|
200
- unless ok
201
- begin
202
- STDOUT.puts 'Command failed. Continue? (y/n)'
203
- input = STDIN.gets.strip.downcase
204
- end until %w(y n).include?(input)
205
- exit 1 if input == 'n'
206
- end
207
- end
208
- ensure
209
- FileUtils.rm_rf 'docs-copy', verbose: true
210
- end
211
- end
212
- end
213
- end
214
- end
215
-
216
- define_uptodate_task.call current_yard_version_name
217
- define_uptodate_task.call 'master'
218
211
  end
219
212
 
220
213
  rescue LoadError => e
@@ -227,15 +220,13 @@ task :release => ['release:checks', 'release:build', 'release:test', 'release:pu
227
220
  namespace :release do
228
221
  # Depends on environment of @pitr-ch
229
222
 
230
- mri_version = '2.5.1'
231
- jruby_version = 'jruby-9.1.17.1'
232
-
233
- task :checks => "yard:#{current_yard_version_name}:uptodate" do
223
+ task :checks do
234
224
  Dir.chdir(__dir__) do
235
225
  sh 'test -z "$(git status --porcelain)"' do |ok, res|
236
226
  unless ok
237
227
  begin
238
- STDOUT.puts 'Command failed. Continue? (y/n)'
228
+ status = `git status --porcelain`
229
+ STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)'
239
230
  input = STDIN.gets.strip.downcase
240
231
  end until %w(y n).include?(input)
241
232
  exit 1 if input == 'n'
@@ -243,10 +234,10 @@ namespace :release do
243
234
  end
244
235
  sh 'git fetch'
245
236
  sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
246
- '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
237
+ '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
247
238
  unless ok
248
239
  begin
249
- STDOUT.puts 'Command failed. Continue? (y/n)'
240
+ STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)'
250
241
  input = STDIN.gets.strip.downcase
251
242
  end until %w(y n).include?(input)
252
243
  exit 1 if input == 'n'
@@ -261,19 +252,18 @@ namespace :release do
261
252
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
262
253
  task :test do
263
254
  Dir.chdir(__dir__) do
264
- old = ENV['RBENV_VERSION']
255
+ puts "Testing with the installed gem"
265
256
 
266
- ENV['RBENV_VERSION'] = mri_version
267
- sh 'rbenv version'
268
- sh 'bundle exec rake spec:installed'
257
+ Bundler.with_original_env do
258
+ sh 'ruby -v'
259
+ sh 'bundle exec rake spec:installed'
269
260
 
270
- ENV['RBENV_VERSION'] = jruby_version
271
- sh 'rbenv version'
272
- sh 'bundle exec rake spec:installed'
261
+ env = { "PATH" => "#{ENV['CONCURRENT_JRUBY_HOME']}/bin:#{ENV['PATH']}" }
262
+ sh env, 'ruby -v'
263
+ sh env, 'bundle exec rake spec:installed'
264
+ end
273
265
 
274
266
  puts 'Windows build is untested'
275
-
276
- ENV['RBENV_VERSION'] = old
277
267
  end
278
268
  end
279
269
 
@@ -281,44 +271,46 @@ namespace :release do
281
271
  task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps']
282
272
 
283
273
  namespace :publish do
274
+ publish_base = true
284
275
  publish_edge = false
285
276
 
286
277
  task :ask do
287
278
  begin
288
- STDOUT.puts 'Do you want to publish anything? (y/n)'
279
+ STDOUT.puts 'Do you want to publish anything now? (y/n)'
289
280
  input = STDIN.gets.strip.downcase
290
281
  end until %w(y n).include?(input)
291
282
  exit 1 if input == 'n'
292
283
  begin
293
- STDOUT.puts 'Do you want to publish edge? (y/n)'
284
+ STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
294
285
  input = STDIN.gets.strip.downcase
295
286
  end until %w(y n).include?(input)
296
287
  publish_edge = input == 'y'
297
288
  end
298
289
 
299
290
  desc '** tag HEAD with current version and push to github'
300
- task :tag do
291
+ task :tag => :ask do
301
292
  Dir.chdir(__dir__) do
302
- sh "git tag v#{Concurrent::VERSION}"
303
- sh "git push origin v#{Concurrent::VERSION}"
293
+ sh "git tag v#{Concurrent::VERSION}" if publish_base
294
+ sh "git push origin v#{Concurrent::VERSION}" if publish_base
304
295
  sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
305
296
  sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
306
297
  end
307
298
  end
308
299
 
309
300
  desc '** push all *.gem files to rubygems'
310
- task :rubygems do
301
+ task :rubygems => :ask do
311
302
  Dir.chdir(__dir__) do
312
- sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
303
+ sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem" if publish_base
313
304
  sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
314
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem"
315
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem"
316
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem"
305
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if publish_base
306
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem" if publish_base
307
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem" if publish_base
317
308
  end
318
309
  end
319
310
 
320
311
  desc '** print post release steps'
321
312
  task :post_steps do
313
+ # TODO: (petr 05-Jun-2021) automate and renew the process
322
314
  puts 'Manually: create a release on GitHub with relevant changelog part'
323
315
  puts 'Manually: send email same as release with relevant changelog part'
324
316
  puts 'Manually: tweet'
@@ -10,6 +10,7 @@ import org.jruby.RubyNumeric;
10
10
  import org.jruby.RubyObject;
11
11
  import org.jruby.anno.JRubyClass;
12
12
  import org.jruby.anno.JRubyMethod;
13
+ import org.jruby.runtime.Block;
13
14
  import org.jruby.runtime.ObjectAllocator;
14
15
  import org.jruby.runtime.ThreadContext;
15
16
  import org.jruby.runtime.builtin.IRubyObject;
@@ -45,9 +46,13 @@ public class JavaSemaphoreLibrary {
45
46
  }
46
47
 
47
48
  @JRubyMethod
48
- public IRubyObject acquire(ThreadContext context, IRubyObject value) throws InterruptedException {
49
- this.semaphore.acquire(rubyFixnumToPositiveInt(value, "permits"));
50
- return context.nil;
49
+ public IRubyObject acquire(ThreadContext context, final Block block) throws InterruptedException {
50
+ return this.acquire(context, 1, block);
51
+ }
52
+
53
+ @JRubyMethod
54
+ public IRubyObject acquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException {
55
+ return this.acquire(context, rubyFixnumToPositiveInt(permits, "permits"), block);
51
56
  }
52
57
 
53
58
  @JRubyMethod(name = "available_permits")
@@ -60,30 +65,32 @@ public class JavaSemaphoreLibrary {
60
65
  return getRuntime().newFixnum(this.semaphore.drainPermits());
61
66
  }
62
67
 
63
- @JRubyMethod
64
- public IRubyObject acquire(ThreadContext context) throws InterruptedException {
65
- this.semaphore.acquire(1);
66
- return context.nil;
67
- }
68
-
69
68
  @JRubyMethod(name = "try_acquire")
70
- public IRubyObject tryAcquire(ThreadContext context) throws InterruptedException {
71
- return getRuntime().newBoolean(semaphore.tryAcquire(1));
69
+ public IRubyObject tryAcquire(ThreadContext context, final Block block) throws InterruptedException {
70
+ int permitsInt = 1;
71
+ boolean acquired = semaphore.tryAcquire(permitsInt);
72
+
73
+ return triedAcquire(context, permitsInt, acquired, block);
72
74
  }
73
75
 
74
76
  @JRubyMethod(name = "try_acquire")
75
- public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits) throws InterruptedException {
76
- return getRuntime().newBoolean(semaphore.tryAcquire(rubyFixnumToPositiveInt(permits, "permits")));
77
+ public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException {
78
+ int permitsInt = rubyFixnumToPositiveInt(permits, "permits");
79
+ boolean acquired = semaphore.tryAcquire(permitsInt);
80
+
81
+ return triedAcquire(context, permitsInt, acquired, block);
77
82
  }
78
83
 
79
84
  @JRubyMethod(name = "try_acquire")
80
- public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout) throws InterruptedException {
81
- return getRuntime().newBoolean(
82
- semaphore.tryAcquire(
83
- rubyFixnumToPositiveInt(permits, "permits"),
84
- rubyNumericToLong(timeout, "timeout"),
85
- java.util.concurrent.TimeUnit.SECONDS)
86
- );
85
+ public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout, final Block block) throws InterruptedException {
86
+ int permitsInt = rubyFixnumToPositiveInt(permits, "permits");
87
+ boolean acquired = semaphore.tryAcquire(
88
+ permitsInt,
89
+ rubyNumericToLong(timeout, "timeout"),
90
+ java.util.concurrent.TimeUnit.SECONDS
91
+ );
92
+
93
+ return triedAcquire(context, permitsInt, acquired, block);
87
94
  }
88
95
 
89
96
  @JRubyMethod
@@ -93,8 +100,8 @@ public class JavaSemaphoreLibrary {
93
100
  }
94
101
 
95
102
  @JRubyMethod
96
- public IRubyObject release(ThreadContext context, IRubyObject value) {
97
- this.semaphore.release(rubyFixnumToPositiveInt(value, "permits"));
103
+ public IRubyObject release(ThreadContext context, IRubyObject permits) {
104
+ this.semaphore.release(rubyFixnumToPositiveInt(permits, "permits"));
98
105
  return getRuntime().newBoolean(true);
99
106
  }
100
107
 
@@ -104,6 +111,29 @@ public class JavaSemaphoreLibrary {
104
111
  return context.nil;
105
112
  }
106
113
 
114
+ private IRubyObject acquire(ThreadContext context, int permits, final Block block) throws InterruptedException {
115
+ this.semaphore.acquire(permits);
116
+
117
+ if (!block.isGiven()) return context.nil;
118
+
119
+ try {
120
+ return block.yieldSpecific(context);
121
+ } finally {
122
+ this.semaphore.release(permits);
123
+ }
124
+ }
125
+
126
+ private IRubyObject triedAcquire(ThreadContext context, int permits, boolean acquired, final Block block) {
127
+ if (!block.isGiven()) return getRuntime().newBoolean(acquired);
128
+ if (!acquired) return context.nil;
129
+
130
+ try {
131
+ return block.yieldSpecific(context);
132
+ } finally {
133
+ this.semaphore.release(permits);
134
+ }
135
+ }
136
+
107
137
  private int rubyFixnumInt(IRubyObject value, String paramName) {
108
138
  if (value instanceof RubyFixnum) {
109
139
  RubyFixnum fixNum = (RubyFixnum) value;
@@ -55,12 +55,6 @@ public class SynchronizationLibrary implements Library {
55
55
  }
56
56
  }
57
57
 
58
- private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator() {
59
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
60
- return new JRubyObject(runtime, klazz);
61
- }
62
- };
63
-
64
58
  private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() {
65
59
  public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
66
60
  return new Object(runtime, klazz);
@@ -87,10 +81,7 @@ public class SynchronizationLibrary implements Library {
87
81
  RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile");
88
82
  jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class);
89
83
 
90
- defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject",
91
- JRubyObject.class, JRUBY_OBJECT_ALLOCATOR);
92
-
93
- defineClass(runtime, synchronizationModule, "JRubyObject", "Object",
84
+ defineClass(runtime, synchronizationModule, "AbstractObject", "Object",
94
85
  Object.class, OBJECT_ALLOCATOR);
95
86
 
96
87
  defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject",
@@ -143,8 +134,8 @@ public class SynchronizationLibrary implements Library {
143
134
  // attempt to avoid code elimination.
144
135
  private static volatile int volatileField;
145
136
 
146
- @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
147
- public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
137
+ @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC, module = true)
138
+ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject module) {
148
139
  // Prevent reordering of ivar writes with publication of this instance
149
140
  if (!FULL_FENCE) {
150
141
  // Assuming that following volatile read and write is not eliminated it simulates fullFence.
@@ -158,9 +149,10 @@ public class SynchronizationLibrary implements Library {
158
149
  return context.nil;
159
150
  }
160
151
 
161
- @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC)
152
+ @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC, module = true)
162
153
  public static IRubyObject instanceVariableGetVolatile(
163
154
  ThreadContext context,
155
+ IRubyObject module,
164
156
  IRubyObject self,
165
157
  IRubyObject name) {
166
158
  // Ensure we ses latest value with loadFence
@@ -174,9 +166,10 @@ public class SynchronizationLibrary implements Library {
174
166
  }
175
167
  }
176
168
 
177
- @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC)
169
+ @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC, module = true)
178
170
  public static IRubyObject InstanceVariableSetVolatile(
179
171
  ThreadContext context,
172
+ IRubyObject module,
180
173
  IRubyObject self,
181
174
  IRubyObject name,
182
175
  IRubyObject value) {
@@ -195,16 +188,8 @@ public class SynchronizationLibrary implements Library {
195
188
  }
196
189
  }
197
190
 
198
- @JRubyClass(name = "JRubyObject", parent = "AbstractObject")
199
- public static class JRubyObject extends RubyObject {
200
-
201
- public JRubyObject(Ruby runtime, RubyClass metaClass) {
202
- super(runtime, metaClass);
203
- }
204
- }
205
-
206
- @JRubyClass(name = "Object", parent = "JRubyObject")
207
- public static class Object extends JRubyObject {
191
+ @JRubyClass(name = "Object", parent = "AbstractObject")
192
+ public static class Object extends RubyObject {
208
193
 
209
194
  public Object(Ruby runtime, RubyClass metaClass) {
210
195
  super(runtime, metaClass);
@@ -220,7 +205,7 @@ public class SynchronizationLibrary implements Library {
220
205
  }
221
206
 
222
207
  @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject")
223
- public static class JRubyLockableObject extends JRubyObject {
208
+ public static class JRubyLockableObject extends AbstractLockableObject {
224
209
 
225
210
  public JRubyLockableObject(Ruby runtime, RubyClass metaClass) {
226
211
  super(runtime, metaClass);
@@ -1,9 +1,10 @@
1
1
  require 'concurrent/configuration'
2
2
  require 'concurrent/atomic/atomic_reference'
3
+ require 'concurrent/atomic/count_down_latch'
3
4
  require 'concurrent/atomic/thread_local_var'
4
5
  require 'concurrent/collection/copy_on_write_observer_set'
5
6
  require 'concurrent/concern/observable'
6
- require 'concurrent/synchronization'
7
+ require 'concurrent/synchronization/lockable_object'
7
8
 
8
9
  module Concurrent
9
10
 
@@ -10,13 +10,13 @@ module Concurrent
10
10
  # or writing at a time. This includes iteration methods like `#each`.
11
11
  #
12
12
  # @note `a += b` is **not** a **thread-safe** operation on
13
- # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array`
14
- # which is concatenation of `a` and `b`, then it writes the concatenation to `a`.
15
- # The read and write are independent operations they do not form a single atomic
16
- # operation therefore when two `+=` operations are executed concurrently updates
17
- # may be lost. Use `#concat` instead.
13
+ # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array`
14
+ # which is concatenation of `a` and `b`, then it writes the concatenation to `a`.
15
+ # The read and write are independent operations they do not form a single atomic
16
+ # operation therefore when two `+=` operations are executed concurrently updates
17
+ # may be lost. Use `#concat` instead.
18
18
  #
19
- # @see http://ruby-doc.org/core-2.2.0/Array.html Ruby standard library `Array`
19
+ # @see http://ruby-doc.org/core/Array.html Ruby standard library `Array`
20
20
 
21
21
  # @!macro internal_implementation_note
22
22
  ArrayImplementation = case
@@ -34,16 +34,6 @@ module Concurrent
34
34
  end
35
35
  JRubyArray
36
36
 
37
- when Concurrent.on_rbx?
38
- require 'monitor'
39
- require 'concurrent/thread_safe/util/data_structures'
40
-
41
- class RbxArray < ::Array
42
- end
43
-
44
- ThreadSafe::Util.make_synchronized_on_rbx RbxArray
45
- RbxArray
46
-
47
37
  when Concurrent.on_truffleruby?
48
38
  require 'concurrent/thread_safe/util/data_structures'
49
39
 
@@ -58,26 +58,6 @@ module Concurrent
58
58
  # end
59
59
  # ```
60
60
  #
61
- # When defining a constructor it is critical that the first line be a call to
62
- # `super` with no arguments. The `super` method initializes the background
63
- # thread and other asynchronous components.
64
- #
65
- # ```
66
- # class BackgroundLogger
67
- # include Concurrent::Async
68
- #
69
- # def initialize(level)
70
- # super()
71
- # @logger = Logger.new(STDOUT)
72
- # @logger.level = level
73
- # end
74
- #
75
- # def info(msg)
76
- # @logger.info(msg)
77
- # end
78
- # end
79
- # ```
80
- #
81
61
  # Mixing this module into a class provides each object two proxy methods:
82
62
  # `async` and `await`. These methods are thread safe with respect to the
83
63
  # enclosing object. The former proxy allows methods to be called
@@ -292,6 +272,7 @@ module Concurrent
292
272
  obj.send(:init_synchronization)
293
273
  obj
294
274
  end
275
+ ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
295
276
  end
296
277
  private_constant :ClassMethods
297
278
 
@@ -309,6 +290,7 @@ module Concurrent
309
290
  @delegate = delegate
310
291
  @queue = []
311
292
  @executor = Concurrent.global_io_executor
293
+ @ruby_pid = $$
312
294
  end
313
295
 
314
296
  # Delegates method calls to the wrapped object.
@@ -326,6 +308,7 @@ module Concurrent
326
308
 
327
309
  ivar = Concurrent::IVar.new
328
310
  synchronize do
311
+ reset_if_forked
329
312
  @queue.push [ivar, method, args, block]
330
313
  @executor.post { perform } if @queue.length == 1
331
314
  end
@@ -361,6 +344,13 @@ module Concurrent
361
344
  end
362
345
  end
363
346
  end
347
+
348
+ def reset_if_forked
349
+ if $$ != @ruby_pid
350
+ @queue.clear
351
+ @ruby_pid = $$
352
+ end
353
+ end
364
354
  end
365
355
  private_constant :AsyncDelegator
366
356
 
@@ -1,7 +1,7 @@
1
1
  require 'concurrent/atomic/atomic_reference'
2
2
  require 'concurrent/collection/copy_on_notify_observer_set'
3
3
  require 'concurrent/concern/observable'
4
- require 'concurrent/synchronization'
4
+ require 'concurrent/synchronization/object'
5
5
 
6
6
  # @!macro thread_safe_variable_comparison
7
7
  #
@@ -18,7 +18,7 @@ require 'concurrent/synchronization'
18
18
  # uncoordinated, *synchronous* change of individual values. Best used when
19
19
  # the value will undergo frequent reads but only occasional, though complex,
20
20
  # updates. Suitable when the result of an update must be known immediately.
21
- # * *{Concurrent::AtomicReference}:* A simple object reference that can be
21
+ # * *{Concurrent::AtomicReference}:* A simple object reference that can be updated
22
22
  # atomically. Updates are synchronous but fast. Best used when updates a
23
23
  # simple set operations. Not suitable when updates are complex.
24
24
  # {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar