Skip to content

Commit f9cf17f

Browse files
author
Petr Chalupa
committed
Merge pull request #273 from ruby-concurrency/synchronization
Synchronization layer
2 parents b9d9469 + 759c025 commit f9cf17f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+735
-277
lines changed

Rakefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env rake
22

3-
require_relative './lib/extension_helper'
3+
require 'concurrent/native_extensions'
44

55
## load the two gemspec files
66
CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec')
@@ -12,7 +12,7 @@ GEM_NAME = 'concurrent-ruby'
1212
EXTENSION_NAME = 'extension'
1313
JAVA_EXT_NAME = 'concurrent_ruby_ext'
1414

15-
if Concurrent.jruby?
15+
if Concurrent.on_jruby?
1616
CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem"
1717
else
1818
CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}.gem"
@@ -35,7 +35,7 @@ Dir.glob('tasks/**/*.rake').each do |rakefile|
3535
safe_load rakefile
3636
end
3737

38-
if Concurrent.jruby?
38+
if Concurrent.on_jruby?
3939

4040
## create the compile task for the JRuby-specific gem
4141
require 'rake/javaextensiontask'
@@ -95,15 +95,15 @@ end
9595
namespace :build do
9696

9797
build_deps = [:clean]
98-
build_deps << :compile if Concurrent.jruby?
98+
build_deps << :compile if Concurrent.on_jruby?
9999

100100
desc "Build #{CORE_GEM} into the pkg directory"
101101
task :core => build_deps do
102102
sh "gem build #{CORE_GEMSPEC.name}.gemspec"
103103
sh 'mv *.gem pkg/'
104104
end
105105

106-
unless Concurrent.jruby?
106+
unless Concurrent.on_jruby?
107107
desc "Build #{EXTENSION_GEM} into the pkg directory"
108108
task :ext => [:clean] do
109109
sh "gem build #{EXT_GEMSPEC.name}.gemspec"
@@ -120,7 +120,7 @@ namespace :build do
120120
end
121121
end
122122

123-
if Concurrent.jruby?
123+
if Concurrent.on_jruby?
124124
desc 'Build JRuby-specific core gem (alias for `build:core`)'
125125
task :build => ['build:core']
126126
else

concurrent-ruby-ext.gemspec

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
2020

2121
s.files = Dir['ext/**/*.{h,c,cpp}']
2222
s.files += [
23-
'lib/extension_helper.rb',
2423
'lib/concurrent/atomic_reference/concurrent_update_error.rb',
2524
'lib/concurrent/atomic_reference/direct_update.rb',
2625
'lib/concurrent/atomic_reference/numeric_cas_wrapper.rb',

ext/ConcurrentRubyExtService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public boolean basicLoad(final Ruby runtime) throws IOException {
99
new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false);
1010
new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false);
1111
new com.concurrent_ruby.ext.JavaSemaphoreLibrary().load(runtime, false);
12+
new com.concurrent_ruby.ext.SynchronizationLibrary().load(runtime, false);
1213
return true;
1314
}
1415
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.concurrent_ruby.ext;
2+
3+
import java.io.IOException;
4+
import java.util.concurrent.atomic.AtomicBoolean;
5+
6+
import org.jruby.Ruby;
7+
import org.jruby.RubyClass;
8+
import org.jruby.RubyModule;
9+
import org.jruby.RubyObject;
10+
import org.jruby.anno.JRubyClass;
11+
import org.jruby.anno.JRubyMethod;
12+
import org.jruby.runtime.ObjectAllocator;
13+
import org.jruby.runtime.builtin.IRubyObject;
14+
import org.jruby.runtime.load.Library;
15+
import org.jruby.runtime.Block;
16+
import org.jruby.RubyBoolean;
17+
import org.jruby.RubyNil;
18+
import org.jruby.runtime.ThreadContext;
19+
20+
public class SynchronizationLibrary implements Library {
21+
22+
public void load(Ruby runtime, boolean wrap) throws IOException {
23+
RubyModule synchronizationModule = runtime.
24+
defineModule("Concurrent").
25+
defineModuleUnder("Synchronization");
26+
RubyClass parentClass = synchronizationModule.getClass("AbstractObject");
27+
28+
if (parentClass == null)
29+
throw runtime.newRuntimeError("Concurrent::Synchronization::AbstractObject is missing");
30+
31+
RubyClass synchronizedObjectJavaClass =
32+
synchronizationModule.defineClassUnder("JavaObject", parentClass, JRUBYREFERENCE_ALLOCATOR);
33+
34+
synchronizedObjectJavaClass.defineAnnotatedMethods(JavaObject.class);
35+
}
36+
37+
private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
38+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
39+
return new JavaObject(runtime, klazz);
40+
}
41+
};
42+
43+
@JRubyClass(name = "JavaObject", parent = "AbstractObject")
44+
public static class JavaObject extends RubyObject {
45+
46+
public JavaObject(Ruby runtime, RubyClass metaClass) {
47+
super(runtime, metaClass);
48+
}
49+
50+
@JRubyMethod
51+
public IRubyObject initialize(ThreadContext context) {
52+
return context.nil;
53+
}
54+
55+
@JRubyMethod(name = "synchronize")
56+
public IRubyObject rubySynchronize(ThreadContext context, Block block) {
57+
synchronized (this) {
58+
return block.yield(context, null);
59+
}
60+
}
61+
62+
@JRubyMethod(name = "ns_wait", optional = 1)
63+
public IRubyObject nsWait(ThreadContext context, IRubyObject[] args) {
64+
Ruby runtime = context.runtime;
65+
if (args.length > 1) {
66+
throw runtime.newArgumentError(args.length, 1);
67+
}
68+
Double timeout = null;
69+
if (args.length > 0 && !args[0].isNil()) {
70+
timeout = args[0].convertToFloat().getDoubleValue();
71+
if (timeout < 0) {
72+
throw runtime.newArgumentError("time interval must be positive");
73+
}
74+
}
75+
if (Thread.interrupted()) {
76+
throw runtime.newConcurrencyError("thread interrupted");
77+
}
78+
boolean success = false;
79+
try {
80+
success = context.getThread().wait_timeout(this, timeout);
81+
} catch (InterruptedException ie) {
82+
throw runtime.newConcurrencyError(ie.getLocalizedMessage());
83+
} finally {
84+
// An interrupt or timeout may have caused us to miss
85+
// a notify that we consumed, so do another notify in
86+
// case someone else is available to pick it up.
87+
if (!success) {
88+
this.notify();
89+
}
90+
}
91+
return this;
92+
}
93+
94+
@JRubyMethod(name = "ns_signal")
95+
public IRubyObject nsSignal(ThreadContext context) {
96+
notify();
97+
return this;
98+
}
99+
100+
@JRubyMethod(name = "ns_broadcast")
101+
public IRubyObject nsBroadcast(ThreadContext context) {
102+
notifyAll();
103+
return this;
104+
}
105+
}
106+
}

ext/concurrent/extconf.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'fileutils'
22

3-
require_relative '../../lib/extension_helper'
3+
require 'concurrent/native_extensions'
44

55
EXTENSION_NAME = 'extension'
66

lib/concurrent.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
require 'concurrent/version'
22

3+
require 'concurrent/synchronization'
4+
35
require 'concurrent/configuration'
46

57
require 'concurrent/actor'

lib/concurrent/actor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require 'concurrent/executor/serialized_execution'
44
require 'concurrent/ivar'
55
require 'concurrent/logging'
6-
require 'concurrent/atomic/synchronization'
6+
require 'concurrent/synchronization'
77

88
module Concurrent
99
# TODO https://github.com/celluloid/celluloid/wiki/Supervision-Groups ?

lib/concurrent/actor/core.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ module Actor
99
# @note devel: core should not block on anything, e.g. it cannot wait on
1010
# children to terminate that would eat up all threads in task pool and
1111
# deadlock
12-
class Core
12+
class Core < Synchronization::Object
1313
include TypeCheck
1414
include Concurrent::Logging
15-
include Synchronization
1615

1716
# @!attribute [r] reference
1817
# @return [Reference] reference to this actor which can be safely passed around
@@ -48,6 +47,7 @@ class Core
4847
# any logging system
4948
# @param [Proc] block for class instantiation
5049
def initialize(opts = {}, &block)
50+
super(&nil)
5151
synchronize do
5252
@mailbox = Array.new
5353
@serialized_execution = SerializedExecution.new

lib/concurrent/atomic.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
# user that they should use the new implementation instead.
44

55
if defined?(Atomic)
6-
warn <<-RUBY
6+
warn <<-TXT
77
[ATOMIC] Detected an `Atomic` class, which may indicate a dependency
88
on the ruby-atomic gem. That gem has been deprecated and merged into
99
the concurrent-ruby gem. Please use the Concurrent::Atomic class for
1010
atomic references and not the Atomic class.
11-
RUBY
11+
TXT
1212
end
1313
#####################################################################
1414

15-
require_relative '../extension_helper'
15+
require 'concurrent/native_extensions'
16+
require 'concurrent/utility/engine'
1617
require 'concurrent/atomic_reference/concurrent_update_error'
1718
require 'concurrent/atomic_reference/mutex_atomic'
1819

@@ -21,7 +22,7 @@
2122
if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK']
2223
ruby_engine = 'mutex_atomic'
2324
else
24-
ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby'
25+
ruby_engine = Concurrent.ruby_engine
2526
end
2627

2728
require "concurrent/atomic_reference/#{ruby_engine}"

lib/concurrent/atomic/atomic_boolean.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require_relative '../../extension_helper'
1+
require 'concurrent/native_extensions'
22

33
module Concurrent
44

@@ -113,7 +113,7 @@ def make_false
113113
end
114114
end
115115

116-
if RUBY_PLATFORM == 'java'
116+
if Concurrent.on_jruby?
117117

118118
class AtomicBoolean < JavaAtomicBoolean
119119
end

0 commit comments

Comments
 (0)