diff options
author | Matthew Draper <matthew@trebex.net> | 2016-02-01 23:41:07 +1030 |
---|---|---|
committer | Matthew Draper <matthew@trebex.net> | 2016-02-02 03:21:03 +1030 |
commit | aeb58ab70470b7f395a1e77b10c9b7a73955dad8 (patch) | |
tree | 6ecf496f8abe16c56716f590087d9a8fdaeb8337 /activesupport/test/share_lock_test.rb | |
parent | 92203edbe6546f84921b6ccb6e79c3a01857a8b3 (diff) | |
download | rails-aeb58ab70470b7f395a1e77b10c9b7a73955dad8.tar.gz rails-aeb58ab70470b7f395a1e77b10c9b7a73955dad8.tar.bz2 rails-aeb58ab70470b7f395a1e77b10c9b7a73955dad8.zip |
Block new share attempts if there's an exclusive waiter
Diffstat (limited to 'activesupport/test/share_lock_test.rb')
-rw-r--r-- | activesupport/test/share_lock_test.rb | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb index 465a657308..0a5b074bee 100644 --- a/activesupport/test/share_lock_test.rb +++ b/activesupport/test/share_lock_test.rb @@ -114,14 +114,17 @@ class ShareLockTest < ActiveSupport::TestCase [true, false].each do |use_upgrading| with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| begin + together = Concurrent::CyclicBarrier.new(2) conflicting_exclusive_threads = [ Thread.new do @lock.send(use_upgrading ? :sharing : :tap) do + together.wait @lock.exclusive(purpose: :red, compatible: [:green, :purple]) {} end end, Thread.new do @lock.send(use_upgrading ? :sharing : :tap) do + together.wait @lock.exclusive(purpose: :blue, compatible: [:green]) {} end end @@ -183,11 +186,14 @@ class ShareLockTest < ActiveSupport::TestCase load_params = [:load, [:load]] unload_params = [:unload, [:unload, :load]] + all_sharing = Concurrent::CyclicBarrier.new(4) + [load_params, load_params, unload_params, unload_params].permutation do |thread_params| with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| threads = thread_params.map do |purpose, compatible| Thread.new do @lock.sharing do + all_sharing.wait @lock.exclusive(purpose: purpose, compatible: compatible) do scratch_pad_mutex.synchronize { scratch_pad << purpose } end @@ -209,6 +215,32 @@ class ShareLockTest < ActiveSupport::TestCase end end + def test_new_share_attempts_block_on_waiting_exclusive + with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| + release_exclusive = Concurrent::CountDownLatch.new + + waiting_exclusive = Thread.new do + @lock.sharing do + @lock.exclusive do + release_exclusive.wait + end + end + end + assert_threads_stuck waiting_exclusive + + late_share_attempt = Thread.new do + @lock.sharing {} + end + assert_threads_stuck late_share_attempt + + sharing_thread_release_latch.count_down + assert_threads_stuck late_share_attempt + + release_exclusive.count_down + assert_threads_not_stuck late_share_attempt + end + end + def test_in_shared_section_incompatible_non_upgrading_threads_cannot_preempt_upgrading_threads scratch_pad = [] scratch_pad_mutex = Mutex.new |