Permalink
Browse files

Add a JRuby::Synchronized module that makes a class's methods (and it…

…s subclasses' methods) be wrapped with synchronization.
  • Loading branch information...
1 parent 0ab11d4 commit 10a114f67c9ea96dc916de0d78cc132e9cc720fa @headius headius committed Mar 24, 2010
View
@@ -44,8 +44,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -128,7 +126,6 @@
import com.kenai.constantine.ConstantSet;
import com.kenai.constantine.platform.Errno;
import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
import java.io.File;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicLong;
@@ -1378,6 +1375,7 @@ private void initBuiltins() {
addLazyBuiltin("jruby/util.rb", "jruby/util", "org.jruby.RubyJRuby$UtilLibrary");
addLazyBuiltin("jruby/core_ext.rb", "jruby/core_ext", "org.jruby.RubyJRuby$CoreExtLibrary");
addLazyBuiltin("jruby/type.rb", "jruby/type", "org.jruby.RubyJRuby$TypeLibrary");
+ addLazyBuiltin("jruby/synchronized.rb", "jruby/synchronized", "org.jruby.RubyJRuby$SynchronizedLibrary");
addLazyBuiltin("iconv.jar", "iconv", "org.jruby.libraries.IConvLibrary");
addLazyBuiltin("nkf.jar", "nkf", "org.jruby.libraries.NKFLibrary");
addLazyBuiltin("stringio.jar", "stringio", "org.jruby.libraries.StringIOLibrary");
@@ -311,7 +311,7 @@ public static RubyClass createBootstrapClass(Ruby runtime, String name, RubyClas
protected RubyClass(Ruby runtime, RubyClass superClass, boolean objectSpace) {
super(runtime, runtime.getClassClass(), objectSpace);
this.runtime = runtime;
- this.superClass = superClass; // this is the only case it might be null here (in MetaClass construction)
+ setSuperClass(superClass); // this is the only case it might be null here (in MetaClass construction)
}
/** separate path for MetaClass and IncludedModuleWrapper construction
@@ -321,7 +321,7 @@ protected RubyClass(Ruby runtime, RubyClass superClass, boolean objectSpace) {
protected RubyClass(Ruby runtime, RubyClass superClass, Generation generation, boolean objectSpace) {
super(runtime, runtime.getClassClass(), generation, objectSpace);
this.runtime = runtime;
- this.superClass = superClass; // this is the only case it might be null here (in MetaClass construction)
+ setSuperClass(superClass); // this is the only case it might be null here (in MetaClass construction)
}
/** used by CLASS_ALLOCATOR (any Class' class will be a Class!)
@@ -338,7 +338,7 @@ protected RubyClass(Ruby runtime) {
*/
protected RubyClass(Ruby runtime, RubyClass superClazz) {
this(runtime);
- superClass = superClazz;
+ setSuperClass(superClazz);
marshal = superClazz.marshal; // use parent's marshal
superClazz.addSubclass(this);
allocator = superClazz.allocator;
@@ -351,7 +351,7 @@ protected RubyClass(Ruby runtime, RubyClass superClazz) {
*/
protected RubyClass(Ruby runtime, RubyClass superClazz, CallSite[] extraCallSites) {
this(runtime);
- this.superClass = superClazz;
+ setSuperClass(superClazz);
this.marshal = superClazz.marshal; // use parent's marshal
superClazz.addSubclass(this);
@@ -819,7 +819,7 @@ public IRubyObject initialize19(ThreadContext context, IRubyObject superObject,
}
private IRubyObject initializeCommon(RubyClass superClazz, Block block, boolean callInheritBeforeSuper) {
- superClass = superClazz;
+ setSuperClass(superClazz);
allocator = superClazz.allocator;
makeMetaClass(superClazz.getMetaClass());
@@ -858,7 +858,7 @@ protected void setModuleSuperClass(RubyClass superClass) {
// add us to new superclass's child classes
superClass.addSubclass(this);
// update superclass reference
- this.superClass = superClass;
+ setSuperClass(superClass);
}
public Collection subclasses(boolean includeDescendants) {
@@ -932,6 +932,17 @@ public synchronized void replaceSubclass(RubyClass subclass, RubyClass newSubcla
}
}
+ public void becomeSynchronized() {
+ // make this class and all subclasses sync
+ synchronized (getRuntime().getHierarchyLock()) {
+ super.becomeSynchronized();
+ Set<RubyClass> mySubclasses = subclasses;
+ if (mySubclasses != null) for (RubyClass subclass : mySubclasses) {
+ subclass.becomeSynchronized();
+ }
+ }
+ }
+
/**
* Invalidate all subclasses of this class by walking the set of all
* subclasses and asking them to invalidate themselves.
@@ -119,6 +119,18 @@ public static void createJRubyCoreExt(Ruby runtime) {
runtime.getString().defineAnnotatedMethods(JRubyStringExtensions.class);
}
+ public static class JRubySynchronizedMeta {
+ @JRubyMethod
+ public static IRubyObject append_features(IRubyObject self, IRubyObject target) {
+ if (target instanceof RubyClass && self instanceof RubyModule) { // should always be true
+ RubyClass targetModule = ((RubyClass)target);
+ targetModule.becomeSynchronized();
+ return ((RubyModule)self).append_features(target);
+ }
+ throw target.getRuntime().newTypeError(self + " can only be included into classes");
+ }
+ }
+
public static class ExtLibrary implements Library {
public void load(Ruby runtime, boolean wrap) throws IOException {
RubyJRuby.createJRubyExt(runtime);
@@ -132,6 +144,13 @@ public void load(Ruby runtime, boolean wrap) throws IOException {
RubyJRuby.createJRubyCoreExt(runtime);
}
}
+
+ public static class SynchronizedLibrary implements Library {
+ public void load(Ruby runtime, boolean wrap) throws IOException {
+ RubyModule syncModule = runtime.getOrCreateModule("JRuby").defineModuleUnder("Synchronized");
+ syncModule.getSingletonClass().defineAnnotatedMethods(JRubySynchronizedMeta.class);
+ }
+ }
public static class TypeLibrary implements Library {
public void load(Ruby runtime, boolean wrap) throws IOException {
@@ -76,6 +76,7 @@
import org.jruby.internal.runtime.methods.MethodMethod;
import org.jruby.internal.runtime.methods.ProcMethod;
import org.jruby.internal.runtime.methods.SimpleCallbackMethod;
+import org.jruby.internal.runtime.methods.SynchronizedDynamicMethod;
import org.jruby.internal.runtime.methods.UndefinedMethod;
import org.jruby.internal.runtime.methods.WrapperMethod;
import org.jruby.javasupport.util.RuntimeHelpers;
@@ -330,6 +331,7 @@ public RubyClass getSuperClass() {
protected void setSuperClass(RubyClass superClass) {
// update superclass reference
this.superClass = superClass;
+ if (superClass != null && superClass.isSynchronized()) becomeSynchronized();
}
public RubyModule getParent() {
@@ -923,8 +925,35 @@ private CacheEntry cacheHit(String name) {
return null;
}
+ protected static abstract class CacheEntryFactory {
+ public abstract CacheEntry newCacheEntry(DynamicMethod method, Object token);
+ }
+
+ protected static CacheEntryFactory NormalCacheEntryFactory = new CacheEntryFactory() {
+ public CacheEntry newCacheEntry(DynamicMethod method, Object token) {
+ return new CacheEntry(method, token);
+ }
+ };
+
+ protected static CacheEntryFactory SynchronizedCacheEntryFactory = new CacheEntryFactory() {
+ public CacheEntry newCacheEntry(DynamicMethod method, Object token) {
+ return new CacheEntry(new SynchronizedDynamicMethod(method), token);
+ }
+ };
+
+ private volatile CacheEntryFactory cacheEntryFactory = NormalCacheEntryFactory;
+
+ // modifies this class only; used to make the Synchronized module synchronized
+ public void becomeSynchronized() {
+ cacheEntryFactory = SynchronizedCacheEntryFactory;
+ }
+
+ public boolean isSynchronized() {
+ return cacheEntryFactory == SynchronizedCacheEntryFactory;
+ }
+
private CacheEntry addToCache(String name, DynamicMethod method, Object token) {
- CacheEntry entry = new CacheEntry(method, token);
+ CacheEntry entry = cacheEntryFactory.newCacheEntry(method, token);
getCachedMethodsForWrite().put(name, entry);
return entry;
@@ -0,0 +1,37 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jruby.internal.runtime.methods;
+
+import org.jruby.RubyModule;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+/**
+ *
+ * @author headius
+ */
+public class SynchronizedDynamicMethod extends DynamicMethod {
+ private final DynamicMethod delegate;
+
+ public SynchronizedDynamicMethod(DynamicMethod delegate) {
+ super(delegate.getImplementationClass(), delegate.getVisibility(), delegate.getCallConfig());
+ this.delegate = delegate;
+ }
+
+ @Override
+ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
+ synchronized (self) {
+ return delegate.call(context, self, clazz, name, args, block);
+ }
+ }
+
+ @Override
+ public DynamicMethod dup() {
+ return new SynchronizedDynamicMethod(delegate);
+ }
+
+}

0 comments on commit 10a114f

Please sign in to comment.