concurrent-ruby 1.1.2 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b989ff504545fbd515aa9623e18515993f30d758768702fd48775efbf1eb68da
4
- data.tar.gz: 6de4e1598114ce722b56eb2ca567d75dd8828afb998252bdb46906e2578f943d
3
+ metadata.gz: 96f32c31090c8a0547e4ee452739bdc993aad1256e2c89cb9a46d7f7e7b5762a
4
+ data.tar.gz: 307d26bde3add56b7e2b37fb0b016c7726a3ba0755dcfec8202fb0760e4ac485
5
5
  SHA512:
6
- metadata.gz: b81c2d2d16e02a03ef0e77c8d633280c02946472e7a762de733da0ee7203c2227ccb09ce5f03835446db42f0bef78df55a2158a787eea3620b1c228a234836df
7
- data.tar.gz: f5ca5bacf3edbc0cf9894d94b8a3c3bc4aef173e4122c6a9cae84d257a3d3df5ada3280431c14f8e33b328348ce039af9a278975954daccb5aea916bad18a1fa
6
+ metadata.gz: b8cff93c6ef396aebbe5cf69734d9a91f0351e24b5c1846ae105b055254f972cd9d6bb99b90ce10d387627ed43c4e21db9ce47d1587e10278e80e33a53f8d4c4
7
+ data.tar.gz: f367f097759eedb8e18b0117543176c9f30ab29552888fcedab0baaea355cee3d100d2559dd16cf54483778545097f8b3340bebe44b0e3ab2a51c1af3830f5e1
@@ -1,5 +1,31 @@
1
1
  ## Current
2
2
 
3
+ ## Release v1.1.5, edge v0.5.0 (10 mar 2019)
4
+
5
+ concurrent-ruby:
6
+
7
+ * fix potential leak of context on JRuby and Java 7
8
+
9
+ concurrent-ruby-edge:
10
+
11
+ * Add finalized Concurrent::Cancellation
12
+ * Add finalized Concurrent::Throttle
13
+ * Add finalized Concurrent::Promises::Channel
14
+ * Add new Concurrent::ErlangActor
15
+
16
+ ## Release v1.1.4 (14 Dec 2018)
17
+
18
+ * (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11
19
+ * (#776) Fix NameError on defining a struct with a name which is already taken in an ancestor
20
+
21
+ ## Release v1.1.3 (7 Nov 2018)
22
+
23
+ * (#775) fix partial require of the gem (although not officially supported)
24
+
25
+ ## Release v1.1.2 (6 Nov 2018)
26
+
27
+ * (#773) more defensive 1.9.3 support
28
+
3
29
  ## Release v1.1.1, edge v0.4.1 (1 Nov 2018)
4
30
 
5
31
  * (#768) add support for 1.9.3 back
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- require File.join(File.dirname(__FILE__ ), 'lib/concurrent/version')
3
+ require File.join(File.dirname(__FILE__), 'lib/concurrent/version')
4
+ require File.join(File.dirname(__FILE__ ), 'lib-edge/concurrent/edge/version')
4
5
 
5
6
  no_path = ENV['NO_PATH']
6
7
  options = no_path ? {} : { path: '.' }
@@ -11,26 +12,27 @@ gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
11
12
 
12
13
  group :development do
13
14
  gem 'rake', '~> 12.0'
14
- gem 'rake-compiler', '~> 1.0'
15
- gem 'rake-compiler-dock', '~> 0.6.0'
15
+ gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
16
+ gem 'rake-compiler-dock', '~> 0.7.0'
16
17
  gem 'pry', '~> 0.11', platforms: :mri
17
18
  end
18
19
 
19
20
  group :documentation, optional: true do
20
- gem 'yard', '~> 0.9.0', :require => false
21
+ gem 'yard', '~> 0.9.0', require: false
21
22
  gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown
22
- gem 'md-ruby-eval', '~> 0.3'
23
+ gem 'md-ruby-eval', '~> 0.6'
23
24
  end
24
25
 
25
26
  group :testing do
26
27
  gem 'rspec', '~> 3.7'
27
28
  gem 'timecop', '~> 0.7.4'
29
+ gem 'sigdump', require: false
28
30
  end
29
31
 
30
32
  # made opt-in since it will not install on jruby 1.7
31
33
  group :coverage, optional: !ENV['COVERAGE'] do
32
- gem 'simplecov', '~> 0.10.0', :require => false
33
- gem 'coveralls', '~> 0.8.2', :require => false
34
+ gem 'simplecov', '~> 0.16.0', require: false
35
+ gem 'coveralls', '~> 0.8.2', require: false
34
36
  end
35
37
 
36
38
  group :benchmarks, optional: true do
data/README.md CHANGED
@@ -42,8 +42,8 @@ appreciate your help. Would you like to contribute? Great! Have a look at
42
42
  ## Thread Safety
43
43
 
44
44
  *Concurrent Ruby makes one of the strongest thread safety guarantees of any Ruby concurrency
45
- library, providing consistent behavior and guarantees on all three of the main Ruby interpreters
46
- (MRI/CRuby, JRuby, and Rubinius).*
45
+ library, providing consistent behavior and guarantees on all four of the main Ruby interpreters
46
+ (MRI/CRuby, JRuby, Rubinius, TruffleRuby).*
47
47
 
48
48
  Every abstraction in this library is thread safe. Specific thread safety guarantees are documented
49
49
  with each abstraction.
@@ -59,7 +59,7 @@ Concurrent Ruby is also the only Ruby library which provides a full suite of thr
59
59
  immutable variable types and data structures.
60
60
 
61
61
  We've also initiated discussion to document [memory model](docs-source/synchronization.md) of Ruby which
62
- would provide consistent behaviour and guarantees on all three of the main Ruby interpreters
62
+ would provide consistent behaviour and guarantees on all four of the main Ruby interpreters
63
63
  (MRI/CRuby, JRuby, Rubinius, TruffleRuby).
64
64
 
65
65
  ## Features & Documentation
@@ -224,6 +224,35 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
224
224
  *Status: will be moved to core soon.*
225
225
  * [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LockFreeStack.html)
226
226
  *Status: missing documentation and tests.*
227
+ * [Promises::Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises/Channel.html)
228
+ A first in first out channel that accepts messages with push family of methods and returns
229
+ messages with pop family of methods.
230
+ Pop and push operations can be represented as futures, see `#pop_op` and `#push_op`.
231
+ The capacity of the channel can be limited to support back pressure, use capacity option in `#initialize`.
232
+ `#pop` method blocks ans `#pop_op` returns pending future if there is no message in the channel.
233
+ If the capacity is limited the `#push` method blocks and `#push_op` returns pending future.
234
+ * [Cancellation](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Cancellation.html)
235
+ The Cancellation abstraction provides cooperative cancellation.
236
+
237
+ The standard methods `Thread#raise` of `Thread#kill` available in Ruby
238
+ are very dangerous (see linked the blog posts bellow).
239
+ Therefore concurrent-ruby provides an alternative.
240
+
241
+ * <https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/>
242
+ * <http://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/>
243
+ * <http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html>
244
+
245
+ It provides an object which represents a task which can be executed,
246
+ the task has to get the reference to the object and periodically cooperatively check that it is not cancelled.
247
+ Good practices to make tasks cancellable:
248
+ * check cancellation every cycle of a loop which does significant work,
249
+ * do all blocking actions in a loop with a timeout then on timeout check cancellation
250
+ and if ok block again with the timeout
251
+ * [Throttle](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Throttle.html)
252
+ A tool managing concurrency level of tasks.
253
+ * [ErlangActor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ErlangActor.html)
254
+ Actor implementation which precisely matches Erlang actor behaviour.
255
+ Requires at least Ruby 2.1 otherwise it's not loaded.
227
256
 
228
257
  ## Supported Ruby versions
229
258
 
@@ -339,11 +368,14 @@ and to the past maintainers
339
368
  * [Paweł Obrok](https://github.com/obrok)
340
369
  * [Lucas Allan](https://github.com/lucasallan)
341
370
 
371
+ and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project
372
+ ["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018.
373
+
342
374
  ## License and Copyright
343
375
 
344
376
  *Concurrent Ruby* is free software released under the
345
377
  [MIT License](http://www.opensource.org/licenses/MIT).
346
378
 
347
- The *Concurrent Ruby* [logo](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Logo) was
379
+ The *Concurrent Ruby* [logo](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/docs-source/logo/concurrent-ruby-logo-300x300.png) was
348
380
  designed by [David Jones](https://twitter.com/zombyboy). It is Copyright &copy; 2014
349
381
  [Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved.
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env rake
2
-
3
1
  require_relative 'lib/concurrent/version'
4
2
  require_relative 'lib/concurrent/utility/engine'
5
3
 
@@ -18,29 +16,7 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
18
16
 
19
17
  require 'rake/javaextensiontask'
20
18
 
21
- JRUBY_JAR_PATH = '/usr/local/opt/rbenv/versions/jruby-9.1.17.0/lib/jruby.jar'
22
-
23
- class ConcurrentRubyJavaExtensionTask < Rake::JavaExtensionTask
24
- def java_classpath_arg(*args)
25
- jruby_cpath = nil
26
- if RUBY_PLATFORM =~ /java/
27
- begin
28
- cpath = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR)
29
- cpath += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR)
30
- jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR)
31
- rescue => e
32
- end
33
- end
34
- unless jruby_cpath
35
- jruby_cpath = JRUBY_JAR_PATH
36
- raise "#{jruby_cpath} does not exist" unless File.exist? jruby_cpath
37
- end
38
- jruby_cpath += File::PATH_SEPARATOR + args.join(File::PATH_SEPARATOR) unless args.empty?
39
- jruby_cpath ? "-cp \"#{jruby_cpath}\"" : ""
40
- end
41
- end
42
-
43
- ConcurrentRubyJavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
19
+ Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
44
20
  ext.ext_dir = 'ext/concurrent-ruby'
45
21
  ext.lib_dir = 'lib/concurrent'
46
22
  end
@@ -63,10 +39,14 @@ namespace :repackage do
63
39
  desc '* with Windows fat distributions'
64
40
  task :all do
65
41
  Dir.chdir(__dir__) do
42
+ # store gems in vendor cache for docker
66
43
  sh 'bundle package'
67
- # needed only if the jar is built outside of docker
44
+
45
+ # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
68
46
  Rake::Task['lib/concurrent/concurrent_ruby.jar'].invoke
69
- RakeCompilerDock.exec 'support/cross_building.sh'
47
+
48
+ # build all gem files
49
+ RakeCompilerDock.sh 'bundle install --local && bundle exec rake cross native package --trace'
70
50
  end
71
51
  end
72
52
  end
@@ -86,15 +66,14 @@ begin
86
66
 
87
67
  RSpec::Core::RakeTask.new(:spec)
88
68
 
89
- options = %w[ --color
90
- --backtrace
91
- --seed 1
92
- --format documentation
93
- --tag ~notravis ]
94
-
95
69
  namespace :spec do
96
70
  desc '* Configured for ci'
97
71
  RSpec::Core::RakeTask.new(:ci) do |t|
72
+ options = %w[ --color
73
+ --backtrace
74
+ --order defined
75
+ --format documentation
76
+ --tag ~notravis ]
98
77
  t.rspec_opts = [*options].join(' ')
99
78
  end
100
79
 
@@ -119,7 +98,7 @@ rescue LoadError => e
119
98
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
120
99
  end
121
100
 
122
- current_yard_version_name = Concurrent::VERSION.split('.')[0..2].join('.')
101
+ current_yard_version_name = Concurrent::VERSION
123
102
 
124
103
  begin
125
104
  require 'yard'
@@ -163,15 +142,25 @@ begin
163
142
  "{Concurrent::#{$1} #{$1}}"
164
143
  end
165
144
  end
145
+ FileUtils.mkpath 'tmp'
166
146
  File.write 'tmp/README.md', content
167
147
  end
168
148
  end
169
149
 
170
150
  define_yard_task = -> name do
151
+ output_dir = "docs/#{name}"
152
+
153
+ removal_name = "remove.#{name}"
154
+ task removal_name do
155
+ Dir.chdir __dir__ do
156
+ FileUtils.rm_rf output_dir
157
+ end
158
+ end
159
+
171
160
  desc "* of #{name} into subdir #{name}"
172
161
  YARD::Rake::YardocTask.new(name) do |yard|
173
162
  yard.options.push(
174
- '--output-dir', "docs/#{name}",
163
+ '--output-dir', output_dir,
175
164
  '--main', 'tmp/README.md',
176
165
  *common_yard_options)
177
166
  yard.files = ['./lib/**/*.rb',
@@ -180,10 +169,11 @@ begin
180
169
  '-',
181
170
  'docs-source/thread_pools.md',
182
171
  'docs-source/promises.out.md',
172
+ 'docs-source/medium-example.out.rb',
183
173
  'LICENSE.md',
184
174
  'CHANGELOG.md']
185
175
  end
186
- Rake::Task[name].prerequisites.push 'yard:eval_md', 'yard:update_readme'
176
+ Rake::Task[name].prerequisites.push removal_name, 'yard:eval_md', 'yard:update_readme'
187
177
  end
188
178
 
189
179
  define_yard_task.call current_yard_version_name
@@ -206,7 +196,15 @@ begin
206
196
  begin
207
197
  FileUtils.cp_r 'docs', 'docs-copy', verbose: true
208
198
  Rake::Task["yard:#{name}"].invoke
209
- sh 'diff -r docs/ docs-copy/'
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
210
208
  ensure
211
209
  FileUtils.rm_rf 'docs-copy', verbose: true
212
210
  end
@@ -258,7 +256,7 @@ namespace :release do
258
256
  end
259
257
 
260
258
  desc '* build all *.gem files necessary for release'
261
- task :build => 'repackage:all'
259
+ task :build => [:clobber, 'repackage:all']
262
260
 
263
261
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
264
262
  task :test do
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
23
23
  public class SynchronizationLibrary implements Library {
24
24
 
25
25
  private static final Unsafe UNSAFE = loadUnsafe();
26
+ private static final boolean FULL_FENCE = supportsFences();
26
27
 
27
28
  private static Unsafe loadUnsafe() {
28
29
  try {
@@ -140,17 +141,17 @@ public class SynchronizationLibrary implements Library {
140
141
  // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic
141
142
  // on volatile fields. any volatile field could have been used but using the thread context is an
142
143
  // attempt to avoid code elimination.
143
- private static volatile ThreadContext threadContext = null;
144
+ private static volatile int volatileField;
144
145
 
145
146
  @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
146
147
  public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
147
148
  // Prevent reordering of ivar writes with publication of this instance
148
- if (!supportsFences()) {
149
+ if (!FULL_FENCE) {
149
150
  // Assuming that following volatile read and write is not eliminated it simulates fullFence.
150
151
  // If it's eliminated it'll cause problems only on non-x86 platforms.
151
152
  // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding
152
- final ThreadContext oldContext = threadContext;
153
- threadContext = context;
153
+ final int volatileRead = volatileField;
154
+ volatileField = context.getLine();
154
155
  } else {
155
156
  UNSAFE.fullFence();
156
157
  }
@@ -163,9 +164,9 @@ public class SynchronizationLibrary implements Library {
163
164
  IRubyObject self,
164
165
  IRubyObject name) {
165
166
  // Ensure we ses latest value with loadFence
166
- if (!supportsFences()) {
167
+ if (!FULL_FENCE) {
167
168
  // piggybacking on volatile read, simulating loadFence
168
- final ThreadContext oldContext = threadContext;
169
+ final int volatileRead = volatileField;
169
170
  return ((RubyBasicObject) self).instance_variable_get(context, name);
170
171
  } else {
171
172
  UNSAFE.loadFence();
@@ -180,10 +181,10 @@ public class SynchronizationLibrary implements Library {
180
181
  IRubyObject name,
181
182
  IRubyObject value) {
182
183
  // Ensure we make last update visible
183
- if (!supportsFences()) {
184
+ if (!FULL_FENCE) {
184
185
  // piggybacking on volatile write, simulating storeFence
185
186
  final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value);
186
- threadContext = context;
187
+ volatileField = context.getLine();
187
188
  return result;
188
189
  } else {
189
190
  // JRuby uses StampedVariableAccessor which calls fullFence
@@ -21,8 +21,9 @@ module Concurrent
21
21
  # @!macro internal_implementation_note
22
22
  ArrayImplementation = case
23
23
  when Concurrent.on_cruby?
24
- # Because MRI never runs code in parallel, the existing
25
- # non-thread-safe structures should usually work fine.
24
+ # Array is thread-safe in practice because CRuby runs
25
+ # threads one at a time and does not do context
26
+ # switching during the execution of C functions.
26
27
  ::Array
27
28
 
28
29
  when Concurrent.on_jruby?
@@ -63,4 +64,3 @@ module Concurrent
63
64
  end
64
65
 
65
66
  end
66
-
@@ -333,6 +333,13 @@ module Concurrent
333
333
  ivar
334
334
  end
335
335
 
336
+ # Check whether the method is responsive
337
+ #
338
+ # @param [Symbol] method the method being called
339
+ def respond_to_missing?(method, include_private = false)
340
+ @delegate.respond_to?(method) || super
341
+ end
342
+
336
343
  # Perform all enqueued tasks.
337
344
  #
338
345
  # This method must be called from within the executor. It must not be
@@ -383,6 +390,13 @@ module Concurrent
383
390
  ivar.wait
384
391
  ivar
385
392
  end
393
+
394
+ # Check whether the method is responsive
395
+ #
396
+ # @param [Symbol] method the method being called
397
+ def respond_to_missing?(method, include_private = false)
398
+ @delegate.respond_to?(method) || super
399
+ end
386
400
  end
387
401
  private_constant :AwaitDelegator
388
402
 
@@ -79,10 +79,10 @@ module Concurrent
79
79
  # @!method value=(value)
80
80
  # @!macro atomic_fixnum_method_value_set
81
81
  #
82
- # @!method increment(delta)
82
+ # @!method increment(delta = 1)
83
83
  # @!macro atomic_fixnum_method_increment
84
84
  #
85
- # @!method decrement(delta)
85
+ # @!method decrement(delta = 1)
86
86
  # @!macro atomic_fixnum_method_decrement
87
87
  #
88
88
  # @!method compare_and_set(expect, update)
@@ -53,7 +53,7 @@ module Concurrent
53
53
 
54
54
  # @param [Node] head
55
55
  # @return [true, false]
56
- def empty?(head = self.head)
56
+ def empty?(head = head())
57
57
  head.equal? EMPTY
58
58
  end
59
59
 
@@ -4,6 +4,7 @@ require 'concurrent/errors'
4
4
  require 'concurrent/atomic/atomic_reference'
5
5
  require 'concurrent/concern/logging'
6
6
  require 'concurrent/executor/immediate_executor'
7
+ require 'concurrent/executor/cached_thread_pool'
7
8
  require 'concurrent/utility/at_exit'
8
9
  require 'concurrent/utility/processor_counter'
9
10
 
@@ -20,13 +20,12 @@ if Concurrent.on_jruby?
20
20
 
21
21
  def initialize(*args, &block)
22
22
  super
23
- ns_make_executor_runnable
24
23
  end
25
24
 
26
25
  def post(*args, &task)
27
26
  raise ArgumentError.new('no block given') unless block_given?
28
27
  return handle_fallback(*args, &task) unless running?
29
- @executor.submit_runnable Job.new(args, task)
28
+ @executor.submit Job.new(args, task)
30
29
  true
31
30
  rescue Java::JavaUtilConcurrent::RejectedExecutionException
32
31
  raise RejectedExecutionError
@@ -75,14 +74,6 @@ if Concurrent.on_jruby?
75
74
  @executor.isShutdown || @executor.isTerminated
76
75
  end
77
76
 
78
- def ns_make_executor_runnable
79
- if !defined?(@executor.submit_runnable)
80
- @executor.class.class_eval do
81
- java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
82
- end
83
- end
84
- end
85
-
86
77
  class Job
87
78
  include Runnable
88
79
  def initialize(args, block)