Skip to content

Commit 7a6cb23

Browse files
committed
Improved java extension loading.
The original implementation assumed that the Java extensions would always be compiled and loaded when running on JRuby. This is not always the case. During development and testing if the gem in included directly from source, as when the Gemfile references git directly, none of the native extensions will exist. In production if the pure-Ruby gem is loaded under JRuby the extensions won't exist, either. This commit updates Java extension loading to follow the existing pattern for C extensions. Relevant parts of the code check to see if the extensions have been correctly loaded first, rather than assuming they are. The test suite still assumes that Java and C extensions are loaded, however. This is necessary to catch bugs which prevent extensions from properly compiling and loading.
1 parent 0c75e79 commit 7a6cb23

File tree

9 files changed

+74
-56
lines changed

9 files changed

+74
-56
lines changed

lib/concurrent/atomic/atomic_boolean.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ module Concurrent
4848
# Explicitly sets the value to false.
4949
#
5050
# @return [Boolean] true is value has changed, otherwise false
51-
51+
5252
###################################################################
5353

5454
# @!macro [new] atomic_boolean_public_api
@@ -79,7 +79,7 @@ module Concurrent
7979
# @!visibility private
8080
# @!macro internal_implementation_note
8181
AtomicBooleanImplementation = case
82-
when Concurrent.on_jruby?
82+
when defined?(JavaAtomicBoolean)
8383
JavaAtomicBoolean
8484
when defined?(CAtomicBoolean)
8585
CAtomicBoolean

lib/concurrent/atomic/atomic_fixnum.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ module Concurrent
9696
# @!visibility private
9797
# @!macro internal_implementation_note
9898
AtomicFixnumImplementation = case
99-
when Concurrent.on_jruby?
99+
when defined?(JavaAtomicFixnum)
100100
JavaAtomicFixnum
101101
when defined?(CAtomicFixnum)
102102
CAtomicFixnum

lib/concurrent/atomic/semaphore.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ module Concurrent
9191
# @!visibility private
9292
# @!macro internal_implementation_note
9393
SemaphoreImplementation = case
94-
when Concurrent.on_jruby?
94+
when defined?(JavaSemaphore)
9595
JavaSemaphore
9696
else
9797
MutexSemaphore

lib/concurrent/map.rb

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
11
require 'thread'
22
require 'concurrent/constants'
3+
require 'concurrent/utility/native_extension_loader'
34

45
module Concurrent
56
# @!visibility private
67
module Collection
78

89
# @!visibility private
9-
MapImplementation = if defined?(RUBY_ENGINE)
10-
case RUBY_ENGINE
11-
when 'jruby'
12-
# noinspection RubyResolve
13-
JRubyMapBackend
14-
when 'ruby'
15-
require 'concurrent/collection/map/mri_map_backend'
16-
MriMapBackend
17-
when 'rbx'
18-
require 'concurrent/collection/map/atomic_reference_map_backend'
19-
AtomicReferenceMapBackend
20-
else
21-
warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
22-
require 'concurrent/collection/map/synchronized_map_backend'
23-
SynchronizedMapBackend
24-
end
25-
else
26-
MriMapBackend
27-
end
10+
MapImplementation = if Concurrent.java_extensions_loaded?
11+
# noinspection RubyResolve
12+
JRubyMapBackend
13+
elsif defined?(RUBY_ENGINE)
14+
case RUBY_ENGINE
15+
when 'ruby'
16+
require 'concurrent/collection/map/mri_map_backend'
17+
MriMapBackend
18+
when 'rbx'
19+
require 'concurrent/collection/map/atomic_reference_map_backend'
20+
AtomicReferenceMapBackend
21+
else
22+
warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
23+
require 'concurrent/collection/map/synchronized_map_backend'
24+
SynchronizedMapBackend
25+
end
26+
else
27+
MriMapBackend
28+
end
2829
end
2930

3031
# `Concurrent::Map` is a hash-like object and should have much better performance

lib/concurrent/synchronization/jruby_lockable_object.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Concurrent
22
module Synchronization
33

4-
if Concurrent.on_jruby?
4+
if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
55

66
# @!visibility private
77
# @!macro internal_implementation_note

lib/concurrent/synchronization/jruby_object.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Concurrent
22
module Synchronization
33

4-
if Concurrent.on_jruby?
4+
if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
55

66
# @!visibility private
77
# @!macro internal_implementation_note

lib/concurrent/synchronization/lockable_object.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Synchronization
88
MriMonitorLockableObject
99
when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
1010
MriMutexLockableObject
11-
when Concurrent.on_jruby?
11+
when defined? JRubyLockableObject
1212
JRubyLockableObject
1313
when Concurrent.on_rbx?
1414
RbxLockableObject

lib/concurrent/synchronization/object.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module Synchronization
66
ObjectImplementation = case
77
when Concurrent.on_cruby?
88
MriObject
9-
when Concurrent.on_jruby?
9+
when defined? JRubyObject
1010
JRubyObject
1111
when Concurrent.on_rbx?
1212
RbxObject

lib/concurrent/utility/native_extension_loader.rb

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,57 @@ module Utility
77
# @!visibility private
88
module NativeExtensionLoader
99

10-
@c_ext_loaded ||= false
11-
@java_ext_loaded ||= false
12-
13-
# @!visibility private
1410
def allow_c_extensions?
1511
Concurrent.on_cruby?
1612
end
1713

18-
if Concurrent.on_cruby? && !@c_ext_loaded
19-
tries = [
20-
lambda do
21-
require 'concurrent/extension'
22-
@c_ext_loaded = true
23-
end,
24-
lambda do
25-
# may be a Windows cross-compiled native gem
26-
require "concurrent/#{RUBY_VERSION[0..2]}/extension"
27-
@c_ext_loaded = true
28-
end]
29-
30-
tries.each do |try|
31-
begin
32-
try.call
33-
break
34-
rescue LoadError
35-
next
14+
def c_extensions_loaded?
15+
@c_extensions_loaded ||= false
16+
end
17+
18+
def java_extensions_loaded?
19+
@java_extensions_loaded ||= false
20+
end
21+
22+
def set_c_extensions_loaded
23+
@c_extensions_loaded = true
24+
end
25+
26+
def set_java_extensions_loaded
27+
@java_extensions_loaded = true
28+
end
29+
30+
def load_native_extensions
31+
if Concurrent.on_cruby? && !c_extensions_loaded?
32+
tries = [
33+
lambda do
34+
require 'concurrent/extension'
35+
set_c_extensions_loaded
36+
end,
37+
lambda do
38+
# may be a Windows cross-compiled native gem
39+
require "concurrent/#{RUBY_VERSION[0..2]}/extension"
40+
set_c_extensions_loaded
41+
end]
42+
43+
tries.each do |try|
44+
begin
45+
try.call
46+
break
47+
rescue LoadError
48+
next
49+
end
3650
end
3751
end
38-
end
3952

40-
if Concurrent.on_jruby? && !@java_ext_loaded
41-
begin
42-
require 'concurrent_ruby_ext'
43-
@java_ext_loaded = true
44-
rescue LoadError
45-
# move on with pure-Ruby implementations
53+
if Concurrent.on_jruby? && !java_extensions_loaded?
54+
begin
55+
require 'concurrent_ruby_ext'
56+
set_java_extensions_loaded
57+
rescue LoadError
58+
# move on with pure-Ruby implementations
59+
warn 'On JRuby but Java extensions failed to load.'
60+
end
4661
end
4762
end
4863
end
@@ -51,3 +66,5 @@ def allow_c_extensions?
5166
# @!visibility private
5267
extend Utility::NativeExtensionLoader
5368
end
69+
70+
Concurrent.load_native_extensions

0 commit comments

Comments
 (0)