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/lib/active_support/concurrency | |
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/lib/active_support/concurrency')
-rw-r--r-- | activesupport/lib/active_support/concurrency/share_lock.rb | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb index ca48164c54..1537f2898f 100644 --- a/activesupport/lib/active_support/concurrency/share_lock.rb +++ b/activesupport/lib/active_support/concurrency/share_lock.rb @@ -48,14 +48,14 @@ module ActiveSupport def start_exclusive(purpose: nil, compatible: [], no_wait: false) synchronize do unless @exclusive_thread == Thread.current - if busy?(purpose) + if busy_for_exclusive?(purpose) return false if no_wait loose_shares = @sharing.delete(Thread.current) @waiting[Thread.current] = compatible if loose_shares begin - @cv.wait_while { busy?(purpose) } + @cv.wait_while { busy_for_exclusive?(purpose) } ensure @waiting.delete Thread.current @sharing[Thread.current] = loose_shares if loose_shares @@ -83,10 +83,10 @@ module ActiveSupport end end - def start_sharing + def start_sharing(purpose: :share) synchronize do - if @exclusive_thread && @exclusive_thread != Thread.current - @cv.wait_while { @exclusive_thread } + if busy_for_sharing?(purpose) + @cv.wait_while { busy_for_sharing?(purpose) } end @sharing[Thread.current] += 1 end @@ -132,11 +132,15 @@ module ActiveSupport private # Must be called within synchronize - def busy?(purpose) - (@exclusive_thread && @exclusive_thread != Thread.current) || - @waiting.any? { |k, v| k != Thread.current && !v.include?(purpose) } || + def busy_for_exclusive?(purpose) + busy_for_sharing?(purpose) || @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0) end + + def busy_for_sharing?(purpose) + (@exclusive_thread && @exclusive_thread != Thread.current) || + @waiting.any? { |k, v| k != Thread.current && !v.include?(purpose) } + end end end end |