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
data/Rakefile ADDED
@@ -0,0 +1,329 @@
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'
4
+
5
+ core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
6
+ ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
7
+ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.gemspec')
8
+
9
+ require 'rake/javaextensiontask'
10
+
11
+ ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && !Concurrent.on_jruby?
12
+
13
+ Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
14
+ ext.ext_dir = 'ext/concurrent-ruby'
15
+ ext.lib_dir = 'lib/concurrent-ruby/concurrent'
16
+ end
17
+
18
+ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
19
+ require 'rake/extensiontask'
20
+
21
+ Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
22
+ ext.ext_dir = 'ext/concurrent-ruby-ext'
23
+ ext.lib_dir = 'lib/concurrent-ruby/concurrent'
24
+ ext.source_pattern = '*.{c,h}'
25
+
26
+ ext.cross_compile = true
27
+ ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
28
+ end
29
+ end
30
+
31
+ require 'rake_compiler_dock'
32
+ namespace :repackage do
33
+ desc '* with Windows fat distributions'
34
+ task :all do
35
+ Dir.chdir(__dir__) do
36
+ # store gems in vendor cache for docker
37
+ sh 'bundle package'
38
+
39
+ # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
40
+ Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke
41
+
42
+ # build all gem files
43
+ %w[x86-mingw32 x64-mingw32].each do |plat|
44
+ RakeCompilerDock.sh "bundle install --local && bundle exec rake native:#{plat} gem --trace", platform: plat
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ require 'rubygems'
51
+ require 'rubygems/package_task'
52
+
53
+ Gem::PackageTask.new(core_gemspec) {} if core_gemspec
54
+ Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
55
+ Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
56
+
57
+ CLEAN.include('lib/concurrent-ruby/concurrent/2.*', 'lib/concurrent-ruby/concurrent/*.jar')
58
+
59
+ begin
60
+ require 'rspec'
61
+ require 'rspec/core/rake_task'
62
+
63
+ RSpec::Core::RakeTask.new(:spec)
64
+
65
+ namespace :spec do
66
+ desc '* Configured for ci'
67
+ RSpec::Core::RakeTask.new(:ci) do |t|
68
+ options = %w[ --color
69
+ --backtrace
70
+ --order defined
71
+ --format documentation ]
72
+ t.rspec_opts = [*options].join(' ')
73
+ end
74
+
75
+ desc '* test packaged and installed gems instead of local files'
76
+ task :installed do
77
+ Dir.chdir(__dir__) do
78
+ sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
79
+ sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
80
+ sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
81
+ ENV['NO_PATH'] = 'true'
82
+ sh 'bundle update'
83
+ sh 'bundle exec rake spec:ci'
84
+ end
85
+ end
86
+ end
87
+
88
+ desc 'executed in CI'
89
+ task :ci => [:compile, 'spec:ci']
90
+
91
+ task :default => [:clobber, :compile, :spec]
92
+ rescue LoadError => e
93
+ puts 'RSpec is not installed, skipping test task definitions: ' + e.message
94
+ end
95
+
96
+ current_yard_version_name = Concurrent::VERSION
97
+
98
+ begin
99
+ require 'yard'
100
+ require 'md_ruby_eval'
101
+ require_relative 'support/yard_full_types'
102
+
103
+ common_yard_options = ['--no-yardopts',
104
+ '--no-document',
105
+ '--no-private',
106
+ '--embed-mixins',
107
+ '--markup', 'markdown',
108
+ '--title', 'Concurrent Ruby',
109
+ '--template', 'default',
110
+ '--template-path', 'yard-template',
111
+ '--default-return', 'undocumented']
112
+
113
+ desc 'Generate YARD Documentation (signpost, master)'
114
+ task :yard => ['yard:signpost', 'yard:master']
115
+
116
+ namespace :yard do
117
+
118
+ desc '* eval markdown files'
119
+ task :eval_md do
120
+ Dir.chdir File.join(__dir__, 'docs-source') do
121
+ sh 'bundle exec md-ruby-eval --auto'
122
+ end
123
+ end
124
+
125
+ task :update_readme do
126
+ Dir.chdir __dir__ do
127
+ content = File.read(File.join('README.md')).
128
+ gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
129
+ case $1
130
+ when 'LockFreeLinkedSet'
131
+ "{Concurrent::Edge::#{$1} #{$1}}"
132
+ when '.dataflow'
133
+ '{Concurrent.dataflow Concurrent.dataflow}'
134
+ when 'thread pool'
135
+ '{file:thread_pools.md thread pool}'
136
+ else
137
+ "{Concurrent::#{$1} #{$1}}"
138
+ end
139
+ end
140
+ FileUtils.mkpath 'tmp'
141
+ File.write 'tmp/README.md', content
142
+ end
143
+ end
144
+
145
+ define_yard_task = -> name do
146
+ output_dir = "docs/#{name}"
147
+
148
+ removal_name = "remove.#{name}"
149
+ task removal_name do
150
+ Dir.chdir __dir__ do
151
+ FileUtils.rm_rf output_dir
152
+ end
153
+ end
154
+
155
+ desc "* of #{name} into subdir #{name}"
156
+ YARD::Rake::YardocTask.new(name) do |yard|
157
+ yard.options.push(
158
+ '--output-dir', output_dir,
159
+ '--main', 'tmp/README.md',
160
+ *common_yard_options)
161
+ yard.files = ['./lib/concurrent-ruby/**/*.rb',
162
+ './lib/concurrent-ruby-edge/**/*.rb',
163
+ './ext/concurrent_ruby_ext/**/*.c',
164
+ '-',
165
+ 'docs-source/thread_pools.md',
166
+ 'docs-source/promises.out.md',
167
+ 'docs-source/medium-example.out.rb',
168
+ 'LICENSE.txt',
169
+ 'CHANGELOG.md']
170
+ end
171
+ Rake::Task[name].prerequisites.push removal_name,
172
+ # 'yard:eval_md',
173
+ 'yard:update_readme'
174
+ end
175
+
176
+ define_yard_task.call current_yard_version_name
177
+ define_yard_task.call 'master'
178
+
179
+ desc "* signpost for versions"
180
+ YARD::Rake::YardocTask.new(:signpost) do |yard|
181
+ yard.options.push(
182
+ '--output-dir', 'docs',
183
+ '--main', 'docs-source/signpost.md',
184
+ *common_yard_options)
185
+ yard.files = ['no-lib']
186
+ end
187
+
188
+ define_uptodate_task = -> name do
189
+ namespace name do
190
+ desc "** ensure that #{name} generated documentation is matching the source code"
191
+ task :uptodate do
192
+ Dir.chdir(__dir__) do
193
+ begin
194
+ FileUtils.cp_r 'docs', 'docs-copy', verbose: true
195
+ Rake::Task["yard:#{name}"].invoke
196
+ sh 'diff -r docs/ docs-copy/' do |ok, res|
197
+ unless ok
198
+ begin
199
+ STDOUT.puts "yard:#{name} is not properly generated and committed.", "Continue? (y/n)"
200
+ input = STDIN.gets.strip.downcase
201
+ end until %w(y n).include?(input)
202
+ exit 1 if input == 'n'
203
+ end
204
+ end
205
+ ensure
206
+ FileUtils.rm_rf 'docs-copy', verbose: true
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ define_uptodate_task.call current_yard_version_name
214
+ define_uptodate_task.call 'master'
215
+ end
216
+
217
+ rescue LoadError => e
218
+ puts 'YARD is not installed, skipping documentation task definitions: ' + e.message
219
+ end
220
+
221
+ desc 'build, test, and publish the gem'
222
+ task :release => ['release:checks', 'release:build', 'release:test', 'release:publish']
223
+
224
+ namespace :release do
225
+ # Depends on environment of @pitr-ch
226
+
227
+ task :checks => "yard:#{current_yard_version_name}:uptodate" do
228
+ Dir.chdir(__dir__) do
229
+ sh 'test -z "$(git status --porcelain)"' do |ok, res|
230
+ unless ok
231
+ begin
232
+ status = `git status --porcelain`
233
+ STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)'
234
+ input = STDIN.gets.strip.downcase
235
+ end until %w(y n).include?(input)
236
+ exit 1 if input == 'n'
237
+ end
238
+ end
239
+ sh 'git fetch'
240
+ sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
241
+ '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
242
+ unless ok
243
+ begin
244
+ STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)'
245
+ input = STDIN.gets.strip.downcase
246
+ end until %w(y n).include?(input)
247
+ exit 1 if input == 'n'
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ desc '* build all *.gem files necessary for release'
254
+ task :build => [:clobber, 'repackage:all']
255
+
256
+ desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
257
+ task :test do
258
+ Dir.chdir(__dir__) do
259
+ old = ENV['RBENV_VERSION']
260
+
261
+ mri_version = `ruby -e 'puts RUBY_VERSION'`.chomp
262
+ jruby_version = File.basename(ENV['CONCURRENT_JRUBY_HOME'])
263
+
264
+ puts "Using following version:"
265
+ pp mri_version: mri_version, jruby_version: jruby_version
266
+
267
+ ENV['RBENV_VERSION'] = mri_version
268
+ sh 'rbenv version'
269
+ sh 'bundle exec rake spec:installed'
270
+
271
+ ENV['RBENV_VERSION'] = jruby_version
272
+ sh 'rbenv version'
273
+ sh 'bundle exec rake spec:installed'
274
+
275
+ puts 'Windows build is untested'
276
+
277
+ ENV['RBENV_VERSION'] = old
278
+ end
279
+ end
280
+
281
+ desc '* do all nested steps'
282
+ task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps']
283
+
284
+ namespace :publish do
285
+ publish_edge = false
286
+
287
+ task :ask do
288
+ begin
289
+ STDOUT.puts 'Do you want to publish anything now? (y/n)'
290
+ input = STDIN.gets.strip.downcase
291
+ end until %w(y n).include?(input)
292
+ exit 1 if input == 'n'
293
+ begin
294
+ STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
295
+ input = STDIN.gets.strip.downcase
296
+ end until %w(y n).include?(input)
297
+ publish_edge = input == 'y'
298
+ end
299
+
300
+ desc '** tag HEAD with current version and push to github'
301
+ task :tag => :ask do
302
+ Dir.chdir(__dir__) do
303
+ sh "git tag v#{Concurrent::VERSION}"
304
+ sh "git push origin v#{Concurrent::VERSION}"
305
+ sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
306
+ sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
307
+ end
308
+ end
309
+
310
+ desc '** push all *.gem files to rubygems'
311
+ task :rubygems => :ask do
312
+ Dir.chdir(__dir__) do
313
+ sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
314
+ sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
315
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem"
316
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem"
317
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem"
318
+ end
319
+ end
320
+
321
+ desc '** print post release steps'
322
+ task :post_steps do
323
+ # TODO: (petr 05-Jun-2021) automate and renew the process
324
+ # puts 'Manually: create a release on GitHub with relevant changelog part'
325
+ # puts 'Manually: send email same as release with relevant changelog part'
326
+ # puts 'Manually: tweet'
327
+ end
328
+ end
329
+ end
@@ -0,0 +1,17 @@
1
+ import org.jruby.Ruby;
2
+ import org.jruby.runtime.load.BasicLibraryService;
3
+
4
+ import java.io.IOException;
5
+
6
+ public class ConcurrentRubyService implements BasicLibraryService {
7
+
8
+ public boolean basicLoad(final Ruby runtime) throws IOException {
9
+ new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false);
10
+ new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false);
11
+ new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false);
12
+ new com.concurrent_ruby.ext.JavaSemaphoreLibrary().load(runtime, false);
13
+ new com.concurrent_ruby.ext.SynchronizationLibrary().load(runtime, false);
14
+ new com.concurrent_ruby.ext.JRubyMapBackendLibrary().load(runtime, false);
15
+ return true;
16
+ }
17
+ }
@@ -0,0 +1,175 @@
1
+ package com.concurrent_ruby.ext;
2
+
3
+ import java.lang.reflect.Field;
4
+ import java.io.IOException;
5
+ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
6
+ import org.jruby.Ruby;
7
+ import org.jruby.RubyClass;
8
+ import org.jruby.RubyModule;
9
+ import org.jruby.RubyNumeric;
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.anno.JRubyClass;
12
+ import org.jruby.anno.JRubyMethod;
13
+ import org.jruby.runtime.ObjectAllocator;
14
+ import org.jruby.runtime.ThreadContext;
15
+ import org.jruby.runtime.builtin.IRubyObject;
16
+ import org.jruby.runtime.load.Library;
17
+
18
+ /**
19
+ * This library adds an atomic reference type to JRuby for use in the atomic
20
+ * library. We do a native version to avoid the implicit value coercion that
21
+ * normally happens through JI.
22
+ *
23
+ * @author headius
24
+ */
25
+ public class AtomicReferenceLibrary implements Library {
26
+ public void load(Ruby runtime, boolean wrap) throws IOException {
27
+ RubyModule concurrentMod = runtime.defineModule("Concurrent");
28
+ RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR);
29
+ try {
30
+ sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class);
31
+ atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR);
32
+ } catch (Exception e) {
33
+ // leave it as Java 6/7 version
34
+ }
35
+ atomicCls.defineAnnotatedMethods(JRubyReference.class);
36
+ }
37
+
38
+ private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
39
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
40
+ return new JRubyReference(runtime, klazz);
41
+ }
42
+ };
43
+
44
+ private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() {
45
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
46
+ return new JRubyReference8(runtime, klazz);
47
+ }
48
+ };
49
+
50
+ @JRubyClass(name="JRubyReference", parent="Object")
51
+ public static class JRubyReference extends RubyObject {
52
+ volatile IRubyObject reference;
53
+
54
+ static final sun.misc.Unsafe UNSAFE;
55
+ static final long referenceOffset;
56
+
57
+ static {
58
+ try {
59
+ UNSAFE = UnsafeHolder.U;
60
+ Class k = JRubyReference.class;
61
+ referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference"));
62
+ } catch (Exception e) {
63
+ throw new RuntimeException(e);
64
+ }
65
+ }
66
+
67
+ public JRubyReference(Ruby runtime, RubyClass klass) {
68
+ super(runtime, klass);
69
+ }
70
+
71
+ @JRubyMethod
72
+ public IRubyObject initialize(ThreadContext context) {
73
+ UNSAFE.putObject(this, referenceOffset, context.nil);
74
+ return context.nil;
75
+ }
76
+
77
+ @JRubyMethod
78
+ public IRubyObject initialize(ThreadContext context, IRubyObject value) {
79
+ UNSAFE.putObject(this, referenceOffset, value);
80
+ return context.nil;
81
+ }
82
+
83
+ @JRubyMethod(name = {"get", "value"})
84
+ public IRubyObject get() {
85
+ return reference;
86
+ }
87
+
88
+ @JRubyMethod(name = {"set", "value="})
89
+ public IRubyObject set(IRubyObject newValue) {
90
+ UNSAFE.putObjectVolatile(this, referenceOffset, newValue);
91
+ return newValue;
92
+ }
93
+
94
+ @JRubyMethod(name = {"compare_and_set", "compare_and_swap"})
95
+ public IRubyObject compare_and_set(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) {
96
+ Ruby runtime = context.runtime;
97
+
98
+ if (expectedValue instanceof RubyNumeric) {
99
+ // numerics are not always idempotent in Ruby, so we need to do slower logic
100
+ return compareAndSetNumeric(context, expectedValue, newValue);
101
+ }
102
+
103
+ return runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, expectedValue, newValue));
104
+ }
105
+
106
+ @JRubyMethod(name = {"get_and_set", "swap"})
107
+ public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) {
108
+ // less-efficient version for Java 6 and 7
109
+ while (true) {
110
+ IRubyObject oldValue = get();
111
+ if (UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)) {
112
+ return oldValue;
113
+ }
114
+ }
115
+ }
116
+
117
+ private IRubyObject compareAndSetNumeric(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) {
118
+ Ruby runtime = context.runtime;
119
+
120
+ // loop until:
121
+ // * reference CAS would succeed for same-valued objects
122
+ // * current and expected have different values as determined by #equals
123
+ while (true) {
124
+ IRubyObject current = reference;
125
+
126
+ if (!(current instanceof RubyNumeric)) {
127
+ // old value is not numeric, CAS fails
128
+ return runtime.getFalse();
129
+ }
130
+
131
+ RubyNumeric currentNumber = (RubyNumeric)current;
132
+ if (!currentNumber.equals(expectedValue)) {
133
+ // current number does not equal expected, fail CAS
134
+ return runtime.getFalse();
135
+ }
136
+
137
+ // check that current has not changed, or else allow loop to repeat
138
+ boolean success = UNSAFE.compareAndSwapObject(this, referenceOffset, current, newValue);
139
+ if (success) {
140
+ // value is same and did not change in interim...success
141
+ return runtime.getTrue();
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ private static final class UnsafeHolder {
148
+ private UnsafeHolder(){}
149
+
150
+ public static final sun.misc.Unsafe U = loadUnsafe();
151
+
152
+ private static sun.misc.Unsafe loadUnsafe() {
153
+ try {
154
+ Class unsafeClass = Class.forName("sun.misc.Unsafe");
155
+ Field f = unsafeClass.getDeclaredField("theUnsafe");
156
+ f.setAccessible(true);
157
+ return (sun.misc.Unsafe) f.get(null);
158
+ } catch (Exception e) {
159
+ return null;
160
+ }
161
+ }
162
+ }
163
+
164
+ public static class JRubyReference8 extends JRubyReference {
165
+ public JRubyReference8(Ruby runtime, RubyClass klass) {
166
+ super(runtime, klass);
167
+ }
168
+
169
+ @Override
170
+ public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) {
171
+ // efficient version for Java 8
172
+ return (IRubyObject)UNSAFE.getAndSetObject(this, referenceOffset, newValue);
173
+ }
174
+ }
175
+ }