Skip to content

Commit

Permalink
concurrent/cached_value: Volatile result access
Browse files Browse the repository at this point in the history
Refs #300
  • Loading branch information
glebm committed Sep 18, 2018
1 parent 6e2017e commit 4fbf49c
Showing 1 changed file with 33 additions and 9 deletions.
42 changes: 33 additions & 9 deletions lib/i18n/tasks/concurrent/cached_value.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,47 @@ class CachedValue
def initialize(&computation)
@computation = computation
@mutex = Mutex.new

# Ruby instance variables are currently implicitly "volatile" in all major implementations, see:
# https://bugs.ruby-lang.org/issues/11539
#
# If the Ruby specification changes, this variable must be marked "volatile".
@result = NULL
end

# @return [Object] Result of the computation.
def get
return @result unless @result == NULL
return get_result_volatile unless get_result_volatile == NULL
@mutex.synchronize do
next unless @result == NULL
@result = @computation.call
next unless get_result_volatile == NULL
set_result_volatile @computation.call
@computation = nil
end
@result
get_result_volatile
end

private

# Ruby instance variable volatility is currently unspecified:
# https://bugs.ruby-lang.org/issues/11539
#
# Below are the implementations for major ruby engines, based on concurrent-ruby.
# rubocop:disable Lint/DuplicateMethods,Naming/AccessorMethodName
case RUBY_ENGINE
when 'rbx'
def get_result_volatile
Rubinius.memory_barrier
@result
end

def set_result_volatile(value)
@result = value
Rubinius.memory_barrier
end
else
def get_result_volatile
@result
end

def set_result_volatile(value)
@result = value
end
end
# rubocop:enable Lint/DuplicateMethods,Naming/AccessorMethodName
end
end

1 comment on commit 4fbf49c

@glebm
Copy link
Owner Author

@glebm glebm commented on 4fbf49c Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @headius!

I don't want to bring in the 338 KiB concurrent-ruby gem, as all I need is volatile access to implement double-checked locking correctly.

  1. Do you think volatile instance variable access is needed here?
  2. Is it needed particularly for JRuby?

Please sign in to comment.