o-concurrent-ruby 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +542 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +404 -0
  6. data/Rakefile +307 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby/concurrent/agent.rb +587 -0
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/concurrent-ruby/concurrent/async.rb +449 -0
  25. data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
  26. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  27. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  30. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  31. data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
  33. data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
  34. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
  35. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
  36. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  37. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  38. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  39. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
  40. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
  41. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
  42. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
  43. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
  44. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
  45. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  46. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  47. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  48. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  49. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  50. data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  51. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  52. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  53. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
  54. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  55. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  56. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  57. data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  58. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
  59. data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
  60. data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
  61. data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
  62. data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
  63. data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
  64. data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
  65. data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
  66. data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
  67. data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
  68. data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
  69. data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
  70. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
  71. data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
  72. data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
  73. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
  74. data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
  75. data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
  76. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
  77. data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
  78. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
  79. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
  80. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
  81. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
  82. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
  83. data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
  84. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
  85. data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
  86. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
  87. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
  88. data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
  89. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
  90. data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
  91. data/lib/concurrent-ruby/concurrent/future.rb +141 -0
  92. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  93. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
  94. data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
  95. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  96. data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
  97. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
  98. data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
  99. data/lib/concurrent-ruby/concurrent/options.rb +42 -0
  100. data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
  101. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  102. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  103. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
  104. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  105. data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
  106. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  107. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
  108. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
  109. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
  110. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  111. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
  112. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
  113. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
  114. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
  115. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  116. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
  117. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
  118. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
  119. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  120. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
  121. data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
  122. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  123. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
  124. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  125. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  126. data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  127. data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
  129. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  130. data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
  131. data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
  132. data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
  133. data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
  134. data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
  135. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  136. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  137. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
  138. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
  139. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  140. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  141. data/lib/concurrent-ruby/concurrent.rb +134 -0
  142. metadata +192 -0
data/Rakefile ADDED
@@ -0,0 +1,307 @@
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
+ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
10
+ require 'rake/extensiontask'
11
+
12
+ Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
13
+ ext.ext_dir = 'ext/concurrent-ruby-ext'
14
+ ext.lib_dir = 'lib/concurrent-ruby/concurrent'
15
+ ext.source_pattern = '*.{c,h}'
16
+
17
+ ext.cross_compile = true
18
+ ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
19
+ end
20
+ end
21
+
22
+ require 'rake_compiler_dock'
23
+ namespace :repackage do
24
+ desc '* with Windows fat distributions'
25
+ task :all do
26
+ Dir.chdir(__dir__) do
27
+ # store gems in vendor cache for docker
28
+ sh 'bundle package'
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'rubygems'
34
+ require 'rubygems/package_task'
35
+
36
+ Gem::PackageTask.new(core_gemspec) {} if core_gemspec
37
+ Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
38
+ Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
39
+
40
+ CLEAN.include('lib/concurrent-ruby/concurrent/2.*')
41
+
42
+ begin
43
+ require 'rspec'
44
+ require 'rspec/core/rake_task'
45
+
46
+ RSpec::Core::RakeTask.new(:spec)
47
+
48
+ namespace :spec do
49
+ desc '* Configured for ci'
50
+ RSpec::Core::RakeTask.new(:ci) do |t|
51
+ options = %w[ --color
52
+ --backtrace
53
+ --order defined
54
+ --format documentation ]
55
+ t.rspec_opts = [*options].join(' ')
56
+ end
57
+
58
+ desc '* test packaged and installed gems instead of local files'
59
+ task :installed do
60
+ Dir.chdir(__dir__) do
61
+ sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
62
+ sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
63
+ sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
64
+ ENV['NO_PATH'] = 'true'
65
+ sh 'bundle update'
66
+ sh 'bundle exec rake spec:ci'
67
+ end
68
+ end
69
+ end
70
+
71
+ desc 'executed in CI'
72
+ task :ci => [:compile, 'spec:ci']
73
+
74
+ task :default => [:clobber, :compile, :spec]
75
+ rescue LoadError => e
76
+ puts 'RSpec is not installed, skipping test task definitions: ' + e.message
77
+ end
78
+
79
+ current_yard_version_name = Concurrent::VERSION
80
+
81
+ begin
82
+ require 'yard'
83
+ require 'md_ruby_eval'
84
+ require_relative 'support/yard_full_types'
85
+
86
+ common_yard_options = ['--no-yardopts',
87
+ '--no-document',
88
+ '--no-private',
89
+ '--embed-mixins',
90
+ '--markup', 'markdown',
91
+ '--title', 'Concurrent Ruby',
92
+ '--template', 'default',
93
+ '--template-path', 'yard-template',
94
+ '--default-return', 'undocumented']
95
+
96
+ desc 'Generate YARD Documentation (signpost, master)'
97
+ task :yard => ['yard:signpost', 'yard:master']
98
+
99
+ namespace :yard do
100
+
101
+ desc '* eval markdown files'
102
+ task :eval_md do
103
+ Dir.chdir File.join(__dir__, 'docs-source') do
104
+ sh 'bundle exec md-ruby-eval --auto'
105
+ end
106
+ end
107
+
108
+ task :update_readme do
109
+ Dir.chdir __dir__ do
110
+ content = File.read(File.join('README.md')).
111
+ gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
112
+ case $1
113
+ when 'LockFreeLinkedSet'
114
+ "{Concurrent::Edge::#{$1} #{$1}}"
115
+ when '.dataflow'
116
+ '{Concurrent.dataflow Concurrent.dataflow}'
117
+ when 'thread pool'
118
+ '{file:thread_pools.md thread pool}'
119
+ else
120
+ "{Concurrent::#{$1} #{$1}}"
121
+ end
122
+ end
123
+ FileUtils.mkpath 'tmp'
124
+ File.write 'tmp/README.md', content
125
+ end
126
+ end
127
+
128
+ define_yard_task = -> name do
129
+ output_dir = "docs/#{name}"
130
+
131
+ removal_name = "remove.#{name}"
132
+ task removal_name do
133
+ Dir.chdir __dir__ do
134
+ FileUtils.rm_rf output_dir
135
+ end
136
+ end
137
+
138
+ desc "* of #{name} into subdir #{name}"
139
+ YARD::Rake::YardocTask.new(name) do |yard|
140
+ yard.options.push(
141
+ '--output-dir', output_dir,
142
+ '--main', 'tmp/README.md',
143
+ *common_yard_options)
144
+ yard.files = ['./lib/concurrent-ruby/**/*.rb',
145
+ './lib/concurrent-ruby-edge/**/*.rb',
146
+ './ext/concurrent_ruby_ext/**/*.c',
147
+ '-',
148
+ 'docs-source/thread_pools.md',
149
+ 'docs-source/promises.out.md',
150
+ 'docs-source/medium-example.out.rb',
151
+ 'LICENSE.txt',
152
+ 'CHANGELOG.md']
153
+ end
154
+ Rake::Task[name].prerequisites.push removal_name,
155
+ # 'yard:eval_md',
156
+ 'yard:update_readme'
157
+ end
158
+
159
+ define_yard_task.call current_yard_version_name
160
+ define_yard_task.call 'master'
161
+
162
+ desc "* signpost for versions"
163
+ YARD::Rake::YardocTask.new(:signpost) do |yard|
164
+ yard.options.push(
165
+ '--output-dir', 'docs',
166
+ '--main', 'docs-source/signpost.md',
167
+ *common_yard_options)
168
+ yard.files = ['no-lib']
169
+ end
170
+
171
+ define_uptodate_task = -> name do
172
+ namespace name do
173
+ desc "** ensure that #{name} generated documentation is matching the source code"
174
+ task :uptodate do
175
+ Dir.chdir(__dir__) do
176
+ begin
177
+ FileUtils.cp_r 'docs', 'docs-copy', verbose: true
178
+ Rake::Task["yard:#{name}"].invoke
179
+ sh 'diff -r docs/ docs-copy/' do |ok, res|
180
+ unless ok
181
+ begin
182
+ STDOUT.puts "yard:#{name} is not properly generated and committed.", "Continue? (y/n)"
183
+ input = STDIN.gets.strip.downcase
184
+ end until %w(y n).include?(input)
185
+ exit 1 if input == 'n'
186
+ end
187
+ end
188
+ ensure
189
+ FileUtils.rm_rf 'docs-copy', verbose: true
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ define_uptodate_task.call current_yard_version_name
197
+ define_uptodate_task.call 'master'
198
+ end
199
+
200
+ rescue LoadError => e
201
+ puts 'YARD is not installed, skipping documentation task definitions: ' + e.message
202
+ end
203
+
204
+ desc 'build, test, and publish the gem'
205
+ task :release => ['release:checks', 'release:build', 'release:test', 'release:publish']
206
+
207
+ namespace :release do
208
+ # Depends on environment of @pitr-ch
209
+
210
+ task :checks => "yard:#{current_yard_version_name}:uptodate" do
211
+ Dir.chdir(__dir__) do
212
+ sh 'test -z "$(git status --porcelain)"' do |ok, res|
213
+ unless ok
214
+ begin
215
+ status = `git status --porcelain`
216
+ STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)'
217
+ input = STDIN.gets.strip.downcase
218
+ end until %w(y n).include?(input)
219
+ exit 1 if input == 'n'
220
+ end
221
+ end
222
+ sh 'git fetch'
223
+ sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
224
+ '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
225
+ unless ok
226
+ begin
227
+ STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)'
228
+ input = STDIN.gets.strip.downcase
229
+ end until %w(y n).include?(input)
230
+ exit 1 if input == 'n'
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ desc '* build all *.gem files necessary for release'
237
+ task :build => [:clobber, 'repackage:all']
238
+
239
+ desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
240
+ task :test do
241
+ Dir.chdir(__dir__) do
242
+ old = ENV['RBENV_VERSION']
243
+
244
+ mri_version = `ruby -e 'puts RUBY_VERSION'`.chomp
245
+
246
+ puts "Using following version:"
247
+ pp mri_version: mri_version
248
+
249
+ ENV['RBENV_VERSION'] = mri_version
250
+ sh 'rbenv version'
251
+ sh 'bundle exec rake spec:installed'
252
+
253
+ puts 'Windows build is untested'
254
+
255
+ ENV['RBENV_VERSION'] = old
256
+ end
257
+ end
258
+
259
+ desc '* do all nested steps'
260
+ task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps']
261
+
262
+ namespace :publish do
263
+ publish_edge = false
264
+
265
+ task :ask do
266
+ begin
267
+ STDOUT.puts 'Do you want to publish anything now? (y/n)'
268
+ input = STDIN.gets.strip.downcase
269
+ end until %w(y n).include?(input)
270
+ exit 1 if input == 'n'
271
+ begin
272
+ STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
273
+ input = STDIN.gets.strip.downcase
274
+ end until %w(y n).include?(input)
275
+ publish_edge = input == 'y'
276
+ end
277
+
278
+ desc '** tag HEAD with current version and push to github'
279
+ task :tag => :ask do
280
+ Dir.chdir(__dir__) do
281
+ sh "git tag v#{Concurrent::VERSION}"
282
+ sh "git push origin v#{Concurrent::VERSION}"
283
+ sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
284
+ sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
285
+ end
286
+ end
287
+
288
+ desc '** push all *.gem files to rubygems'
289
+ task :rubygems => :ask do
290
+ Dir.chdir(__dir__) do
291
+ sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
292
+ sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
293
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem"
294
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem"
295
+ sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem"
296
+ end
297
+ end
298
+
299
+ desc '** print post release steps'
300
+ task :post_steps do
301
+ # TODO: (petr 05-Jun-2021) automate and renew the process
302
+ # puts 'Manually: create a release on GitHub with relevant changelog part'
303
+ # puts 'Manually: send email same as release with relevant changelog part'
304
+ # puts 'Manually: tweet'
305
+ end
306
+ end
307
+ 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
+ }