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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +542 -0
- data/Gemfile +37 -0
- data/LICENSE.txt +21 -0
- data/README.md +404 -0
- data/Rakefile +307 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby/concurrent/agent.rb +587 -0
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/concurrent-ruby/concurrent/async.rb +449 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
- data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
- data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
- data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
- data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
- data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
- data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
- data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
- data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
- data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
- data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
- data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
- data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
- data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
- data/lib/concurrent-ruby/concurrent/future.rb +141 -0
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
- data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
- data/lib/concurrent-ruby/concurrent/map.rb +346 -0
- data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
- data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
- data/lib/concurrent-ruby/concurrent/options.rb +42 -0
- data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
- data/lib/concurrent-ruby/concurrent/set.rb +74 -0
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
- data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
- data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/concurrent-ruby/concurrent.rb +134 -0
- 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
|
+
}
|