atomic-1.1.101/0000755000004100000410000000000013301506703013155 5ustar www-datawww-dataatomic-1.1.101/.travis.yml0000644000004100000410000000043013301506703015263 0ustar www-datawww-datalanguage: ruby rvm: - 2.2.0 - 2.1.5 - 2.1.4 - 2.0.0 - 1.9.3 - ruby-head - jruby-1.7.18 - jruby-head - rbx-2 jdk: - oraclejdk8 sudo: false branches: only: - master matrix: allow_failures: - rvm: ruby-head - rvm: jruby-head - rvm: 1.9.3 atomic-1.1.101/test/0000755000004100000410000000000013301506703014134 5ustar www-datawww-dataatomic-1.1.101/test/test_atomic.rb0000644000004100000410000001012413301506703016772 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http:#www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'minitest/autorun' require 'atomic' class TestAtomic < Minitest::Test def test_construct atomic = Atomic.new assert_equal nil, atomic.value atomic = Atomic.new(0) assert_equal 0, atomic.value end def test_value atomic = Atomic.new(0) atomic.value = 1 assert_equal 1, atomic.value end def test_update # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = Atomic.new(1000) res = atomic.update {|v| v + 1} assert_equal 1001, atomic.value assert_equal 1001, res end def test_try_update # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = Atomic.new(1000) res = atomic.try_update {|v| v + 1} assert_equal 1001, atomic.value assert_equal 1001, res end def test_swap atomic = Atomic.new(1000) res = atomic.swap(1001) assert_equal 1001, atomic.value assert_equal 1000, res end def test_try_update_fails # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = Atomic.new(1000) assert_raises Atomic::ConcurrentUpdateError do # assigning within block exploits implementation detail for test atomic.try_update{|v| atomic.value = 1001 ; v + 1} end end def test_update_retries tries = 0 # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = Atomic.new(1000) # assigning within block exploits implementation detail for test atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1} assert_equal 2, tries end def test_numeric_cas atomic = Atomic.new(0) # 9-bit idempotent Fixnum (JRuby) max_8 = 2**256 - 1 min_8 = -(2**256) atomic.set(max_8) max_8.upto(max_8 + 2) do |i| assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_8) min_8.downto(min_8 - 2) do |i| assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" end # 64-bit idempotent Fixnum (MRI, Rubinius) max_64 = 2**62 - 1 min_64 = -(2**62) atomic.set(max_64) max_64.upto(max_64 + 2) do |i| assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_64) min_64.downto(min_64 - 2) do |i| assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" end # 64-bit overflow into Bignum (JRuby) max_64 = 2**63 - 1 min_64 = (-2**63) atomic.set(max_64) max_64.upto(max_64 + 2) do |i| assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" end atomic.set(min_64) min_64.downto(min_64 - 2) do |i| assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" end # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) atomic.set(1.0 + 0.1) assert atomic.compare_and_set(1.0 + 0.1, 1.2), "CAS failed for #{1.0 + 0.1} => 1.2" # Bignum atomic.set(2**100) assert atomic.compare_and_set(2**100, 0), "CAS failed for #{2**100} => 0" # Rational require 'rational' unless ''.respond_to? :to_r atomic.set(Rational(1,3)) assert atomic.compare_and_set(Rational(1,3), 0), "CAS failed for #{Rational(1,3)} => 0" # Complex require 'complex' unless ''.respond_to? :to_c atomic.set(Complex(1,2)) assert atomic.compare_and_set(Complex(1,2), 0), "CAS failed for #{Complex(1,2)} => 0" end end atomic-1.1.101/README.md0000644000004100000410000000713113301506703014436 0ustar www-datawww-data# Ruby Atomic [![Gem Version](https://badge.fury.io/rb/atomic.svg)](http://badge.fury.io/rb/atomic) [![Build Status](https://travis-ci.org/ruby-concurrency/atomic.svg?branch=master)](https://travis-ci.org/ruby-concurrency/atomic) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/atomic.svg)](https://codeclimate.com/github/ruby-concurrency/atomic) [![Dependency Status](https://gemnasium.com/ruby-concurrency/atomic.svg)](https://gemnasium.com/ruby-concurrency/atomic) [![License](https://img.shields.io/badge/license-Apache-green.svg)](http://opensource.org/licenses/Apache-2.0) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby) An atomic reference implementation for JRuby, Rubinius, and MRI. # Deprecated! *This gem has been deprecated in lieu of [Concurrent Ruby](http://www.concurrent-ruby.com). This gem will be retained in GitHub and Rubygems.org indefinitely but no new development will occur, including updates to support new versions of Ruby, JRuby, and Java. All users of this gem are encouraged to update their projects to use `concurrent-ruby` instead.* All code from this gem has been merged into `concurrent-ruby` and its companion gems. All abstrations in this library are available in `concurrent-ruby` but have been moved under the `Concurrent` module to avoid namespace collisions. ```ruby # old way require 'atomic' my_atomic = Atomic.new(0) # new way require 'concurrent' my_atomic = Concurrent::Atomic.new(0) ``` # Old Documentation *For historic purposes only...* ## Summary This library provides: * an Atomic class that guarantees atomic updates to its contained value The Atomic class provides accessors for the contained "value" plus two update methods: * update will run the provided block, passing the current value and replacing it with the block result if the value has not been changed in the meantime. It may run the block repeatedly if there are other concurrent updates in progress. * try_update will run the provided block, passing the current value and replacing it with the block result. If the value changes before the update can happen, it will throw an Atomic::ConcurrentUpdateError. The atomic repository is at http://github.com/ruby-concurrency/ruby-atomic. ## Usage The simplest way to use "atomic" is to call the "update" or "try_update" methods. "try_update" and "update" both call the given block, passing the current value and using the block's result as the new value. If the value is updated by another thread before the block completes, "try update" raises a ConcurrentUpdateError and "update" retries the block. Because "update" may call the block several times when multiple threads are all updating the same value, the block's logic should be kept as simple as possible. ```ruby require 'atomic' my_atomic = Atomic.new(0) my_atomic.update {|v| v + 1} begin my_atomic.try_update {|v| v + 1} rescue Atomic::ConcurrentUpdateError => cue # deal with it (retry, propagate, etc) end ``` It's also possible to use the regular get/set operations on the Atomic, if you want to avoid the exception and respond to contended changes in some other way. ```ruby my_atomic = Atomic.new(0) my_atomic.value # => 0 my_atomic.value = 1 my_atomic.swap(2) # => 1 my_atomic.compare_and_swap(2, 3) # => true, updated to 3 my_atomic.compare_and_swap(2, 3) # => false, current is not 2 ``` ## Building As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code should still work fine as far back as Java 5. atomic-1.1.101/.gitignore0000644000004100000410000000053013301506703015143 0ustar www-datawww-dataGemfile.lock *.gem lib/1.8 lib/1.9 lib/2.0 .rvmrc .ruby-version .ruby-gemset .bundle/* .yardoc/* yardoc/* tmp/* man/* *.tmproj rdoc/* *.orig *.BACKUP.* *.BASE.* *.LOCAL.* *.REMOTE.* git_pull.txt coverage critic .DS_Store TAGS tmtags *.sw? .idea .rbx/* lib/**/*.bundle lib/**/*.so lib/**/*.jar ext/**/*.bundle ext/**/*.so ext/**/*.jar pkg *.gem atomic-1.1.101/LICENSE0000644000004100000410000002201613301506703014163 0ustar www-datawww-dataApache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS atomic-1.1.101/examples/0000755000004100000410000000000013301506703014773 5ustar www-datawww-dataatomic-1.1.101/examples/atomic_example.rb0000644000004100000410000000146713301506703020317 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'atomic' my_atomic = Atomic.new(0) my_atomic.update {|v| v + 1} puts "new value: #{my_atomic.value}" begin my_atomic.try_update {|v| v + 1} rescue Atomic::ConcurrentUpdateError => cue # deal with it (retry, propagate, etc) end puts "new value: #{my_atomic.value}" atomic-1.1.101/examples/bench_atomic.rb0000644000004100000410000000460613301506703017741 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'benchmark' require 'atomic' require 'thread' Thread.abort_on_exception = true $go = false # for synchronizing parallel threads # number of updates on the value N = ARGV[1] ? ARGV[1].to_i : 100_000 # number of threads for parallel test M = ARGV[0] ? ARGV[0].to_i : 100 puts "*** Sequential updates ***" Benchmark.bm(10) do |x| value = 0 x.report "no lock" do N.times do value += 1 end end @lock = Mutex.new x.report "mutex" do value = 0 N.times do @lock.synchronize do value += 1 end end end @atom = Atomic.new(0) x.report "atomic" do N.times do @atom.update{|x| x += 1} end end end def para_setup(num_threads, count, &block) if num_threads % 2 > 0 raise ArgumentError, "num_threads must be a multiple of two" end raise ArgumentError, "need block" unless block_given? # Keep those threads together tg = ThreadGroup.new num_threads.times do |i| diff = (i % 2 == 0) ? 1 : -1 t = Thread.new do nil until $go count.times do yield diff end end tg.add(t) end # Make sure all threads are started while tg.list.find{|t| t.status != "run"} Thread.pass end # For good measure GC.start tg end def para_run(tg) $go = true tg.list.each{|t| t.join} $go = false end puts "*** Parallel updates ***" Benchmark.bm(10) do |bm| # This is not secure value = 0 tg = para_setup(M, N/M) do |diff| value += diff end bm.report("no lock"){ para_run(tg) } value = 0 @lock = Mutex.new tg = para_setup(M, N/M) do |diff| @lock.synchronize do value += diff end end bm.report("mutex"){ para_run(tg) } raise unless value == 0 @atom = Atomic.new(0) tg = para_setup(M, N/M) do |diff| @atom.update{|x| x + diff} end bm.report("atomic"){ para_run(tg) } raise unless @atom.value == 0 end atomic-1.1.101/examples/bench_atomic_1.rb0000644000004100000410000000566113301506703020163 0ustar www-datawww-data#!/usr/bin/env ruby # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. $: << File.expand_path('../../lib', __FILE__) require 'optparse' require 'thread' require 'benchmark' require 'atomic' Thread.abort_on_exception = true $conf = { :lock => "atomic", :num_threads => 100, :count => 100_000, :count_per_thread => nil, :slow => nil, } OptionParser.new do |opts| opts.on("-c", "--count NUM") do |n| $conf[:count] = n.to_i end opts.on("-p", "--count-per-thread") do |n| $conf[:count_per_thread] = n.to_i end opts.on("-t", "--num-threads NUM") do |n| $conf[:num_threads] = n.to_i end opts.on("-s", "--slow NUM") do |n| $conf[:slow] = n.to_i end opts.on("-l", "--lock atomic|mutex") do |x| $conf[:lock] = x end opts.on("-h", "--help"){ puts opts; exit } end.parse!(ARGV) unless $conf[:count_per_thread] $conf[:count_per_thread] = $conf[:count] / $conf[:num_threads] end $conf.delete(:count) if $conf[:slow].to_i > 0 require 'digest/md5' def slow_down $conf[:slow].times do |i| Digest::MD5.hexdigest(i.to_s) end end ret = [] 10.times do m = Benchmark.measure{ slow_down } ret << m.real end $conf[:slow_time] = [ret.min, ret.max] else def slow_down; end end $stderr.puts $conf.inspect def para_prepare(&block) num_threads = $conf[:num_threads] count = $conf[:count_per_thread] if num_threads % 2 > 0 raise ArgumentError, "num_threads must be a multiple of two" end # Keep those threads together tg = ThreadGroup.new num_threads.times do |i| diff = (i % 2 == 0) ? 1 : -1 t = Thread.new do nil until $go count.times do yield diff end end tg.add(t) end # Make sure all threads are started while tg.list.find{|t| t.status != "run"} Thread.pass end # For good measure GC.start $go = false tg end $tg = nil if $conf[:lock] == "atomic" $atom = Atomic.new(0) $tg = para_prepare do |diff| $atom.update do |x| slow_down x + diff end end else $lock = Mutex.new $value = 0 $tg = para_prepare do |diff| $lock.synchronize do slow_down $value += diff end end end # Run ! # # NOTE: It seems to me that this measurement method # is sensible to how the system dispatches his resources. # # More precise caluclation could be done using # getrusage's times ret = Benchmark.measure do $go = true $tg.list.each{|t| t.join} $go = false end puts ret.real atomic-1.1.101/examples/graph_atomic_bench.rb0000644000004100000410000000423113301506703021114 0ustar www-datawww-data#!/usr/bin/env ruby # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'optparse' conf = { :vary => "threads", :lock => "atomic" } OptionParser.new do |opts| opts.on("-l", "--lock atomic|mutex") do |l| conf[:lock] = l end opts.on("-v", "--vary threads|speed") do |v| conf[:vary] = v end opts.on("-h", "--help"){ puts opts; exit } end.parse!(ARGV) result = File.open("results_#{conf[:lock]}_#{conf[:vary]}.csv", "w") if conf[:vary] == "threads" # Vary the number of concurrent threads that update the value. # # There is a total count of 1mio updates that is distributed # between the number of threads. # # A pair number of threads is used so that even add and odd substract 1. # This avoid creating instances for Bignum since the number should # stay in the Fixnum range. # (1..100).each do |i| i = i * 2 ret = [] 10.times do ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -t #{i}`.to_f end line = ([i] + ret).join(', ') puts line result.puts line end elsif conf[:vary] == "speed" # Varies the execution time of the update block # by using long calulation (MD5) # # NOTE: Thread.pass and sleep() are not usable by the atomic # lock. It needs to run the whole block without hitting # another atomic update otherwise it has to retry # # The expected result is that the atomic lock's performance # will hit a certain threshold where it will be worse than mutexes. # (1..30).each do |i| ret = [] 10.times do ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -s #{i}`.to_f end line = ([i] + ret).join(', ') puts line result.puts line end end atomic-1.1.101/Rakefile0000644000004100000410000000321013301506703014616 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http:#www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'rake' require 'rake/testtask' desc "Run tests" Rake::TestTask.new :test do |t| t.libs << "lib" t.libs << "ext" t.test_files = FileList["test/**/*.rb"] end desc "Run benchmarks" task :bench do exec "ruby -Ilib -Iext test/bench_atomic.rb" end if defined?(JRUBY_VERSION) require 'ant' directory "pkg/classes" desc "Clean up build artifacts" task :clean do rm_rf "pkg/classes" rm_rf "lib/refqueue.jar" end desc "Compile the extension" task :compile_java => "pkg/classes" do |t| ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, :source => "1.5", :target => "1.5", :debug => true, :classpath => "${java.class.path}:${sun.boot.class.path}" end desc "Build the jar" task :jar => :compile_java do ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class" end task :compile => :jar else require "rake/extensiontask" Rake::ExtensionTask.new "atomic" do |ext| ext.ext_dir = 'ext' ext.name ='atomic_reference' end end task :package => :compile task :test => :compile task :default => :test atomic-1.1.101/lib/0000755000004100000410000000000013301506703013723 5ustar www-datawww-dataatomic-1.1.101/lib/atomic/0000755000004100000410000000000013301506703015177 5ustar www-datawww-dataatomic-1.1.101/lib/atomic/delegated_update.rb0000644000004100000410000000237613301506703021014 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'atomic/concurrent_update_error' # Define update methods that delegate to @ref field class Atomic # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. def update true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) new_value end def try_update old_value = @ref.get new_value = yield old_value unless @ref.compare_and_set(old_value, new_value) if $VERBOSE raise ConcurrentUpdateError, "Update failed" else raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE end end new_value end endatomic-1.1.101/lib/atomic/jruby.rb0000644000004100000410000000113213301506703016654 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'atomic_reference' require 'atomic/direct_update'atomic-1.1.101/lib/atomic/direct_update.rb0000644000004100000410000000234413301506703020343 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'atomic/concurrent_update_error' # Define update methods that use direct paths class Atomic # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. def update true until compare_and_set(old_value = get, new_value = yield(old_value)) new_value end def try_update old_value = get new_value = yield old_value unless compare_and_set(old_value, new_value) if $VERBOSE raise ConcurrentUpdateError, "Update failed" else raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE end end new_value end endatomic-1.1.101/lib/atomic/rbx.rb0000644000004100000410000000141613301506703016321 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # extend Rubinius's version adding aliases and numeric logic class Atomic < Rubinius::AtomicReference alias value get alias value= set alias swap get_and_set end require 'atomic/direct_update' require 'atomic/numeric_cas_wrapper' atomic-1.1.101/lib/atomic/concurrent_update_error.rb0000644000004100000410000000136613301506703022467 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. class Atomic class ConcurrentUpdateError < ThreadError # frozen pre-allocated backtrace to speed ConcurrentUpdateError CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze end endatomic-1.1.101/lib/atomic/numeric_cas_wrapper.rb0000644000004100000410000000176713301506703021567 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. class Atomic alias _compare_and_set compare_and_set def compare_and_set(expected, new) if expected.kind_of? Numeric while true old = get return false unless old.kind_of? Numeric return false unless old == expected result = _compare_and_set(old, new) return result if result end else _compare_and_set(expected, new) end end alias compare_and_swap compare_and_set endatomic-1.1.101/lib/atomic/fallback.rb0000644000004100000410000000252413301506703017266 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'thread' require 'atomic/direct_update' # Portable/generic (but not very memory or scheduling-efficient) fallback class Atomic #:nodoc: all def initialize(value = nil) @mutex = Mutex.new @value = value end def get @mutex.synchronize { @value } end alias value get def set(new_value) @mutex.synchronize { @value = new_value } end alias value= set def get_and_set(new_value) @mutex.synchronize do old_value = @value @value = new_value old_value end end alias swap get_and_set def compare_and_set(old_value, new_value) return false unless @mutex.try_lock begin return false unless @value.equal? old_value @value = new_value ensure @mutex.unlock end true end require 'atomic/numeric_cas_wrapper' endatomic-1.1.101/lib/atomic/ruby.rb0000644000004100000410000000117713301506703016513 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'atomic_reference' require 'atomic/direct_update' require 'atomic/numeric_cas_wrapper'atomic-1.1.101/lib/atomic.rb0000644000004100000410000000166413301506703015533 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. begin # force fallback impl with FORCE_ATOMIC_FALLBACK=1 if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK'] ruby_engine = 'fallback' else ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' end require "atomic/#{ruby_engine}" rescue LoadError warn "#{__FILE__}:#{__LINE__}: unsupported Ruby engine `#{RUBY_ENGINE}', using less-efficient Atomic impl" require 'atomic/fallback' endatomic-1.1.101/Gemfile0000644000004100000410000000031213301506703014444 0ustar www-datawww-datasource 'https://rubygems.org' gemspec group :development do gem 'rake', '~> 10.3.2' gem 'rake-compiler', '~> 0.9.2' end group :testing do gem 'minitest', '>= 5.0.0', :group => :development end atomic-1.1.101/.coveralls.yml0000644000004100000410000000005613301506703015751 0ustar www-datawww-datarepo_token: YHujQy7tqpw5P0TuWjwk6Vd5Vuw8LcGvo atomic-1.1.101/ext/0000755000004100000410000000000013301506703013755 5ustar www-datawww-dataatomic-1.1.101/ext/atomic_reference.c0000644000004100000410000000715713301506703017425 0ustar www-datawww-data// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #if defined(__sun) #include #endif #ifdef HAVE_LIBKERN_OSATOMIC_H #include #endif static void ir_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } static VALUE ir_alloc(VALUE klass) { return rb_data_object_alloc(klass, (void *) Qnil, ir_mark, NULL); } static VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { VALUE value = Qnil; if (rb_scan_args(argc, argv, "01", &value) == 1) { value = argv[0]; } DATA_PTR(self) = (void *) value; return Qnil; } static VALUE ir_get(VALUE self) { #if HAVE_GCC_SYNC __sync_synchronize(); #elif defined _MSC_VER MemoryBarrier(); #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 OSMemoryBarrier(); #endif return (VALUE) DATA_PTR(self); } static VALUE ir_set(VALUE self, VALUE new_value) { DATA_PTR(self) = (void *) new_value; #if HAVE_GCC_SYNC __sync_synchronize(); #elif defined _MSC_VER MemoryBarrier(); #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 OSMemoryBarrier(); #endif return new_value; } static VALUE ir_get_and_set(VALUE self, VALUE new_value) { VALUE old_value = ir_get(self); ir_set(self, new_value); return old_value; } static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { return Qtrue; } #elif defined(__sun) /* Assuming VALUE is uintptr_t */ /* Based on the definition of uintptr_t from /usr/include/sys/int_types.h */ #if defined(_LP64) || defined(_I32LPx) /* 64-bit: uintptr_t === unsigned long */ if (atomic_cas_ulong((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #else /* 32-bit: uintptr_t === unsigned int */ if (atomic_cas_uint((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #endif #elif defined _MSC_VER && defined _M_AMD64 if (InterlockedCompareExchange64((LONGLONG*)&DATA_PTR(self), new_value, expect_value)) { return Qtrue; } #elif defined _MSC_VER && defined _M_IX86 if (InterlockedCompareExchange((LONG*)&DATA_PTR(self), new_value, expect_value)) { return Qtrue; } #else if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; } #endif return Qfalse; } void Init_atomic_reference() { VALUE cAtomic; cAtomic = rb_define_class_under(rb_cObject, "Atomic", rb_cObject); rb_define_alloc_func(cAtomic, ir_alloc); rb_define_method(cAtomic, "initialize", ir_initialize, -1); rb_define_method(cAtomic, "get", ir_get, 0); rb_define_method(cAtomic, "value", ir_get, 0); rb_define_method(cAtomic, "set", ir_set, 1); rb_define_method(cAtomic, "value=", ir_set, 1); rb_define_method(cAtomic, "get_and_set", ir_get_and_set, 1); rb_define_method(cAtomic, "swap", ir_get_and_set, 1); rb_define_method(cAtomic, "compare_and_set", ir_compare_and_set, 2); rb_define_method(cAtomic, "compare_and_swap", ir_compare_and_set, 2); } atomic-1.1.101/ext/AtomicReferenceService.java0000644000004100000410000000162513301506703021200 0ustar www-datawww-data// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import java.io.IOException; import org.jruby.Ruby; import org.jruby.runtime.load.BasicLibraryService; public class AtomicReferenceService implements BasicLibraryService { public boolean basicLoad(final Ruby runtime) throws IOException { new org.jruby.ext.atomic.AtomicReferenceLibrary().load(runtime, false); return true; } } atomic-1.1.101/ext/extconf.rb0000644000004100000410000000225413301506703015753 0ustar www-datawww-data# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'mkmf' extension_name = 'atomic_reference' dir_config(extension_name) have_header "libkern/OSAtomic.h" def compiler_is_gcc if CONFIG["GCC"] && CONFIG["GCC"] != "" return true elsif ( # This could stand to be more generic... but I am afraid. CONFIG["CC"] =~ /\bgcc\b/ ) return true end return false end if compiler_is_gcc case CONFIG["arch"] when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" when 'i686-linux' $CFLAGS += " -march=i686" end end try_run(<