Reset the owner ivar in LRU#synchronize
Without this the following could happen: 1. Thread A acquires the lock and sets the ownership to A. 2. Thread A yields and returns 3. Thread B tries to acquire the lock 4. At this exact moment Thread A calls the "synchronize" method again and sees that the "owner" variable is still set to Thread A 5. Both thread A and B can now access the underlying data in parallel, possibly leading to corrupted objects This can be demonstrated using the following script: require 'oga' lru = Oga::LRU.new(64) threads = 50.times.map do Thread.new do loop do number = rand(100) lru[number] = number end end end threads.each(&:join) Run this for a while on either JRuby or Rubinius and you'll end up with errors such as "ConcurrencyError: Detected invalid array contents due to unsynchronized modifications with concurrent users" on JRuby or "ArgumentError: negative array size" on Rubinius. Resetting the owner variable ensures the above can never happen. Thanks to @chrisseaton for bringing this up earlier today.
This commit is contained in:
parent
ed3cbe7975
commit
32b75bf62c
|
@ -137,8 +137,10 @@ module Oga
|
|||
if @owner != Thread.current
|
||||
@mutex.synchronize do
|
||||
@owner = Thread.current
|
||||
retval = yield
|
||||
@owner = nil
|
||||
|
||||
yield
|
||||
retval
|
||||
end
|
||||
else
|
||||
yield
|
||||
|
|
Loading…
Reference in New Issue