concurrent-ruby 1.1.4 → 1.1.5
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile +9 -7
- data/README.md +34 -2
- data/Rakefile +33 -52
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +9 -8
- data/lib/concurrent/array.rb +3 -3
- data/lib/concurrent/async.rb +14 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +2 -2
- data/lib/concurrent/collection/lock_free_stack.rb +1 -1
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/executor/timer_set.rb +13 -15
- data/lib/concurrent/hash.rb +3 -3
- data/lib/concurrent/promises.rb +348 -117
- data/lib/concurrent/synchronization/abstract_struct.rb +1 -0
- data/lib/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent/synchronization/jruby_object.rb +1 -0
- data/lib/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent/synchronization/mri_object.rb +1 -0
- data/lib/concurrent/synchronization/object.rb +46 -20
- data/lib/concurrent/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent/synchronization/truffleruby_object.rb +1 -0
- data/lib/concurrent/version.rb +1 -2
- metadata +5 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 96f32c31090c8a0547e4ee452739bdc993aad1256e2c89cb9a46d7f7e7b5762a
         | 
| 4 | 
            +
              data.tar.gz: 307d26bde3add56b7e2b37fb0b016c7726a3ba0755dcfec8202fb0760e4ac485
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b8cff93c6ef396aebbe5cf69734d9a91f0351e24b5c1846ae105b055254f972cd9d6bb99b90ce10d387627ed43c4e21db9ce47d1587e10278e80e33a53f8d4c4
         | 
| 7 | 
            +
              data.tar.gz: f367f097759eedb8e18b0117543176c9f30ab29552888fcedab0baaea355cee3d100d2559dd16cf54483778545097f8b3340bebe44b0e3ab2a51c1af3830f5e1
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,18 @@ | |
| 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 | 
            +
             | 
| 3 16 | 
             
            ## Release v1.1.4 (14 Dec 2018)
         | 
| 4 17 |  | 
| 5 18 | 
             
            * (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            source 'https://rubygems.org'
         | 
| 2 2 |  | 
| 3 | 
            -
            require File.join(File.dirname(__FILE__ | 
| 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. | 
| 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', : | 
| 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. | 
| 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. | 
| 33 | 
            -
              gem 'coveralls', '~> 0.8.2', : | 
| 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,7 +42,7 @@ 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  | 
| 45 | 
            +
            library, providing consistent behavior and guarantees on all four of the main Ruby interpreters 
         | 
| 46 46 | 
             
            (MRI/CRuby, JRuby, Rubinius, TruffleRuby).*
         | 
| 47 47 |  | 
| 48 48 | 
             
            Every abstraction in this library is thread safe. Specific thread safety guarantees are documented 
         | 
| @@ -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:// | 
| 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 © 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,43 +16,7 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge. | |
| 18 16 |  | 
| 19 17 | 
             
            require 'rake/javaextensiontask'
         | 
| 20 18 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
              def java_classpath_arg(*args)
         | 
| 23 | 
            -
                jruby_cpath = nil
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                if RUBY_PLATFORM =~ /java/
         | 
| 26 | 
            -
                  begin
         | 
| 27 | 
            -
                    cpath       = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR)
         | 
| 28 | 
            -
                    cpath       += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR)
         | 
| 29 | 
            -
                    jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR)
         | 
| 30 | 
            -
                  rescue => e
         | 
| 31 | 
            -
                  end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                  unless jruby_cpath
         | 
| 34 | 
            -
                    libdir = RbConfig::CONFIG['libdir']
         | 
| 35 | 
            -
                    if libdir.start_with? "classpath:"
         | 
| 36 | 
            -
                      raise 'Cannot build with jruby-complete'
         | 
| 37 | 
            -
                    end
         | 
| 38 | 
            -
                    jruby_cpath = File.join(libdir, "jruby.jar")
         | 
| 39 | 
            -
                  end
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                unless jruby_cpath
         | 
| 43 | 
            -
                  jruby_home = ENV['JRUBY_HOME']
         | 
| 44 | 
            -
                  if jruby_home
         | 
| 45 | 
            -
                    candidate = File.join(jruby_home, 'lib', 'jruby.jar')
         | 
| 46 | 
            -
                    jruby_cpath = candidate if File.exist? candidate
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                raise "jruby.jar path not found" unless jruby_cpath
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                jruby_cpath += File::PATH_SEPARATOR + args.join(File::PATH_SEPARATOR) unless args.empty?
         | 
| 53 | 
            -
                jruby_cpath ? "-cp \"#{jruby_cpath}\"" : ""
         | 
| 54 | 
            -
              end
         | 
| 55 | 
            -
            end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
            ConcurrentRubyJavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
         | 
| 19 | 
            +
            Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
         | 
| 58 20 | 
             
              ext.ext_dir = 'ext/concurrent-ruby'
         | 
| 59 21 | 
             
              ext.lib_dir = 'lib/concurrent'
         | 
| 60 22 | 
             
            end
         | 
| @@ -80,9 +42,11 @@ namespace :repackage do | |
| 80 42 | 
             
                  # store gems in vendor cache for docker
         | 
| 81 43 | 
             
                  sh 'bundle package'
         | 
| 82 44 |  | 
| 83 | 
            -
                  #  | 
| 45 | 
            +
                  # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
         | 
| 84 46 | 
             
                  Rake::Task['lib/concurrent/concurrent_ruby.jar'].invoke
         | 
| 85 | 
            -
             | 
| 47 | 
            +
             | 
| 48 | 
            +
                  # build all gem files
         | 
| 49 | 
            +
                  RakeCompilerDock.sh 'bundle install --local && bundle exec rake cross native package --trace'
         | 
| 86 50 | 
             
                end
         | 
| 87 51 | 
             
              end
         | 
| 88 52 | 
             
            end
         | 
| @@ -102,15 +66,14 @@ begin | |
| 102 66 |  | 
| 103 67 | 
             
              RSpec::Core::RakeTask.new(:spec)
         | 
| 104 68 |  | 
| 105 | 
            -
              options = %w[ --color
         | 
| 106 | 
            -
                            --backtrace
         | 
| 107 | 
            -
                            --seed 1
         | 
| 108 | 
            -
                            --format documentation
         | 
| 109 | 
            -
                            --tag ~notravis ]
         | 
| 110 | 
            -
             | 
| 111 69 | 
             
              namespace :spec do
         | 
| 112 70 | 
             
                desc '* Configured for ci'
         | 
| 113 71 | 
             
                RSpec::Core::RakeTask.new(:ci) do |t|
         | 
| 72 | 
            +
                  options      = %w[ --color
         | 
| 73 | 
            +
                                --backtrace
         | 
| 74 | 
            +
                                --order defined
         | 
| 75 | 
            +
                                --format documentation
         | 
| 76 | 
            +
                                --tag ~notravis ]
         | 
| 114 77 | 
             
                  t.rspec_opts = [*options].join(' ')
         | 
| 115 78 | 
             
                end
         | 
| 116 79 |  | 
| @@ -135,7 +98,7 @@ rescue LoadError => e | |
| 135 98 | 
             
              puts 'RSpec is not installed, skipping test task definitions: ' + e.message
         | 
| 136 99 | 
             
            end
         | 
| 137 100 |  | 
| 138 | 
            -
            current_yard_version_name =  | 
| 101 | 
            +
            current_yard_version_name = Concurrent::VERSION
         | 
| 139 102 |  | 
| 140 103 | 
             
            begin
         | 
| 141 104 | 
             
              require 'yard'
         | 
| @@ -185,10 +148,19 @@ begin | |
| 185 148 | 
             
                end
         | 
| 186 149 |  | 
| 187 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 | 
            +
             | 
| 188 160 | 
             
                  desc "* of #{name} into subdir #{name}"
         | 
| 189 161 | 
             
                  YARD::Rake::YardocTask.new(name) do |yard|
         | 
| 190 162 | 
             
                    yard.options.push(
         | 
| 191 | 
            -
                        '--output-dir',  | 
| 163 | 
            +
                        '--output-dir', output_dir,
         | 
| 192 164 | 
             
                        '--main', 'tmp/README.md',
         | 
| 193 165 | 
             
                        *common_yard_options)
         | 
| 194 166 | 
             
                    yard.files = ['./lib/**/*.rb',
         | 
| @@ -197,10 +169,11 @@ begin | |
| 197 169 | 
             
                                  '-',
         | 
| 198 170 | 
             
                                  'docs-source/thread_pools.md',
         | 
| 199 171 | 
             
                                  'docs-source/promises.out.md',
         | 
| 172 | 
            +
                                  'docs-source/medium-example.out.rb',
         | 
| 200 173 | 
             
                                  'LICENSE.md',
         | 
| 201 174 | 
             
                                  'CHANGELOG.md']
         | 
| 202 175 | 
             
                  end
         | 
| 203 | 
            -
                  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'
         | 
| 204 177 | 
             
                end
         | 
| 205 178 |  | 
| 206 179 | 
             
                define_yard_task.call current_yard_version_name
         | 
| @@ -223,7 +196,15 @@ begin | |
| 223 196 | 
             
                        begin
         | 
| 224 197 | 
             
                          FileUtils.cp_r 'docs', 'docs-copy', verbose: true
         | 
| 225 198 | 
             
                          Rake::Task["yard:#{name}"].invoke
         | 
| 226 | 
            -
                          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
         | 
| 227 208 | 
             
                        ensure
         | 
| 228 209 | 
             
                          FileUtils.rm_rf 'docs-copy', verbose: true
         | 
| 229 210 | 
             
                        end
         | 
| @@ -275,7 +256,7 @@ namespace :release do | |
| 275 256 | 
             
              end
         | 
| 276 257 |  | 
| 277 258 | 
             
              desc '* build all *.gem files necessary for release'
         | 
| 278 | 
            -
              task :build => 'repackage:all'
         | 
| 259 | 
            +
              task :build => [:clobber, 'repackage:all']
         | 
| 279 260 |  | 
| 280 261 | 
             
              desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
         | 
| 281 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  | 
| 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 (! | 
| 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  | 
| 153 | 
            -
                             | 
| 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 (! | 
| 167 | 
            +
                        if (!FULL_FENCE) {
         | 
| 167 168 | 
             
                            // piggybacking on volatile read, simulating loadFence
         | 
| 168 | 
            -
                            final  | 
| 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 (! | 
| 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 | 
            -
                             | 
| 187 | 
            +
                            volatileField = context.getLine();
         | 
| 187 188 | 
             
                            return result;
         | 
| 188 189 | 
             
                        } else {
         | 
| 189 190 | 
             
                            // JRuby uses StampedVariableAccessor which calls fullFence
         | 
    
        data/lib/concurrent/array.rb
    CHANGED
    
    | @@ -21,8 +21,9 @@ module Concurrent | |
| 21 21 | 
             
              # @!macro internal_implementation_note
         | 
| 22 22 | 
             
              ArrayImplementation = case
         | 
| 23 23 | 
             
                                    when Concurrent.on_cruby?
         | 
| 24 | 
            -
                                      #  | 
| 25 | 
            -
                                      #  | 
| 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 | 
            -
             | 
    
        data/lib/concurrent/async.rb
    CHANGED
    
    | @@ -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)
         | 
| Binary file | 
| @@ -48,11 +48,9 @@ module Concurrent | |
| 48 48 | 
             
                def post(delay, *args, &task)
         | 
| 49 49 | 
             
                  raise ArgumentError.new('no block given') unless block_given?
         | 
| 50 50 | 
             
                  return false unless running?
         | 
| 51 | 
            -
                  opts = {
         | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
                    timer_set: self
         | 
| 55 | 
            -
                  }
         | 
| 51 | 
            +
                  opts = { executor:  @task_executor,
         | 
| 52 | 
            +
                           args:      args,
         | 
| 53 | 
            +
                           timer_set: self }
         | 
| 56 54 | 
             
                  task = ScheduledTask.execute(delay, opts, &task) # may raise exception
         | 
| 57 55 | 
             
                  task.unscheduled? ? false : task
         | 
| 58 56 | 
             
                end
         | 
| @@ -74,11 +72,11 @@ module Concurrent | |
| 74 72 | 
             
                # @param [Hash] opts the options to create the object with.
         | 
| 75 73 | 
             
                # @!visibility private
         | 
| 76 74 | 
             
                def ns_initialize(opts)
         | 
| 77 | 
            -
                  @queue | 
| 78 | 
            -
                  @task_executor | 
| 79 | 
            -
                  @timer_executor | 
| 80 | 
            -
                  @condition | 
| 81 | 
            -
                  @ruby_pid | 
| 75 | 
            +
                  @queue              = Collection::NonConcurrentPriorityQueue.new(order: :min)
         | 
| 76 | 
            +
                  @task_executor      = Options.executor_from_options(opts) || Concurrent.global_io_executor
         | 
| 77 | 
            +
                  @timer_executor     = SingleThreadExecutor.new
         | 
| 78 | 
            +
                  @condition          = Event.new
         | 
| 79 | 
            +
                  @ruby_pid           = $$ # detects if Ruby has forked
         | 
| 82 80 | 
             
                  self.auto_terminate = opts.fetch(:auto_terminate, true)
         | 
| 83 81 | 
             
                end
         | 
| 84 82 |  | 
| @@ -90,7 +88,7 @@ module Concurrent | |
| 90 88 | 
             
                #
         | 
| 91 89 | 
             
                # @!visibility private
         | 
| 92 90 | 
             
                def post_task(task)
         | 
| 93 | 
            -
                  synchronize{ ns_post_task(task) }
         | 
| 91 | 
            +
                  synchronize { ns_post_task(task) }
         | 
| 94 92 | 
             
                end
         | 
| 95 93 |  | 
| 96 94 | 
             
                # @!visibility private
         | 
| @@ -98,7 +96,7 @@ module Concurrent | |
| 98 96 | 
             
                  return false unless ns_running?
         | 
| 99 97 | 
             
                  ns_reset_if_forked
         | 
| 100 98 | 
             
                  if (task.initial_delay) <= 0.01
         | 
| 101 | 
            -
                    task.executor.post{ task.process_task }
         | 
| 99 | 
            +
                    task.executor.post { task.process_task }
         | 
| 102 100 | 
             
                  else
         | 
| 103 101 | 
             
                    @queue.push(task)
         | 
| 104 102 | 
             
                    # only post the process method when the queue is empty
         | 
| @@ -116,7 +114,7 @@ module Concurrent | |
| 116 114 | 
             
                #
         | 
| 117 115 | 
             
                # @!visibility private
         | 
| 118 116 | 
             
                def remove_task(task)
         | 
| 119 | 
            -
                  synchronize{ @queue.delete(task) }
         | 
| 117 | 
            +
                  synchronize { @queue.delete(task) }
         | 
| 120 118 | 
             
                end
         | 
| 121 119 |  | 
| 122 120 | 
             
                # `ExecutorService` callback called during shutdown.
         | 
| @@ -148,7 +146,7 @@ module Concurrent | |
| 148 146 | 
             
                    task = synchronize { @condition.reset; @queue.peek }
         | 
| 149 147 | 
             
                    break unless task
         | 
| 150 148 |  | 
| 151 | 
            -
                    now | 
| 149 | 
            +
                    now  = Concurrent.monotonic_time
         | 
| 152 150 | 
             
                    diff = task.schedule_time - now
         | 
| 153 151 |  | 
| 154 152 | 
             
                    if diff <= 0
         | 
| @@ -165,7 +163,7 @@ module Concurrent | |
| 165 163 | 
             
                      # queue now must have the same pop time, or a closer one, as
         | 
| 166 164 | 
             
                      # when we peeked).
         | 
| 167 165 | 
             
                      task = synchronize { @queue.pop }
         | 
| 168 | 
            -
                      task.executor.post{ task.process_task }
         | 
| 166 | 
            +
                      task.executor.post { task.process_task }
         | 
| 169 167 | 
             
                    else
         | 
| 170 168 | 
             
                      @condition.wait([diff, 60].min)
         | 
| 171 169 | 
             
                    end
         |