diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/core.clj | 12 | ||||
-rw-r--r-- | src/clj/clojure/zip.clj | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Keyword.java | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 15 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LockingTransaction.java | 108 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Ref.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Var.java | 13 |
7 files changed, 129 insertions, 35 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index a2907aa8..ef5f2482 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -357,14 +357,14 @@ (defn symbol "Returns a Symbol with the given namespace and name." - ([name] (if (symbol? name) name (. clojure.lang.Symbol (intern name)))) - ([ns name] (. clojure.lang.Symbol (intern ns name)))) + ([name] (if (symbol? name) name (clojure.lang.Symbol/intern name))) + ([ns name] (clojure.lang.Symbol/intern ns name))) (defn keyword "Returns a Keyword with the given namespace and name. Do not use : in the keyword strings, it will be added automatically." - ([name] (if (keyword? name) name (. clojure.lang.Keyword (intern nil name)))) - ([ns name] (. clojure.lang.Keyword (intern ns name)))) + ([name] (if (keyword? name) name (clojure.lang.Keyword/intern name))) + ([ns name] (clojure.lang.Keyword/intern ns name))) (defn gensym "Returns a new symbol with a unique name. If a prefix string is @@ -4307,8 +4307,8 @@ (invoke [x] (locking d (if (pos? (.getCount d)) - (do (.countDown d) - (reset! v x) + (do (reset! v x) + (.countDown d) this) (throw (IllegalStateException. "Multiple deliver calls to a promise")))))))) diff --git a/src/clj/clojure/zip.clj b/src/clj/clojure/zip.clj index 81b09060..00cc3be5 100644 --- a/src/clj/clojure/zip.clj +++ b/src/clj/clojure/zip.clj @@ -31,12 +31,18 @@ (defn seq-zip "Returns a zipper for nested sequences, given a root sequence" [root] - (zipper seq? identity (fn [node children] children) root)) + (zipper seq? + identity + (fn [node children] (with-meta children (meta node))) + root)) (defn vector-zip "Returns a zipper for nested vectors, given a root vector" [root] - (zipper vector? seq (fn [node children] (apply vector children)) root)) + (zipper vector? + seq + (fn [node children] (with-meta (vec children) (meta node))) + root)) (defn xml-zip "Returns a zipper for xml elements (as from xml/parse), diff --git a/src/jvm/clojure/lang/Keyword.java b/src/jvm/clojure/lang/Keyword.java index fcb814f6..9b5aea9a 100644 --- a/src/jvm/clojure/lang/Keyword.java +++ b/src/jvm/clojure/lang/Keyword.java @@ -30,6 +30,10 @@ public static Keyword intern(String ns, String name){ return intern(Symbol.intern(ns, name)); } +public static Keyword intern(String nsname){ + return intern(Symbol.intern(nsname)); +} + private Keyword(Symbol sym){ this.sym = sym; } diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 5bf22e66..368bc1fa 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -704,7 +704,20 @@ public static class SyntaxQuoteReader extends AFn{ // Simply quote method names. } else - sym = Compiler.resolveSymbol(sym); + { + Object maybeClass = null; + if(sym.ns != null) + maybeClass = Compiler.currentNS().getMapping( + Symbol.intern(null, sym.ns)); + if(maybeClass instanceof Class) + { + // Classname/foo -> package.qualified.Classname/foo + sym = Symbol.intern( + ((Class)maybeClass).getName(), sym.name); + } + else + sym = Compiler.resolveSymbol(sym); + } ret = RT.list(Compiler.QUOTE, sym); } else if(isUnquote(form)) diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java index 4976d169..bb61e1b6 100644 --- a/src/jvm/clojure/lang/LockingTransaction.java +++ b/src/jvm/clojure/lang/LockingTransaction.java @@ -16,6 +16,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; @SuppressWarnings({"SynchronizeOnNonFinalField"}) public class LockingTransaction{ @@ -104,13 +105,32 @@ final HashMap<Ref, Object> vals = new HashMap<Ref, Object>(); final HashSet<Ref> sets = new HashSet<Ref>(); final TreeMap<Ref, ArrayList<CFn>> commutes = new TreeMap<Ref, ArrayList<CFn>>(); +final HashSet<Ref> ensures = new HashSet<Ref>(); //all hold readLock + + +void tryWriteLock(Ref ref){ + try + { + if(!ref.lock.writeLock().tryLock(LOCK_WAIT_MSECS, TimeUnit.MILLISECONDS)) + throw retryex; + } + catch(InterruptedException e) + { + throw retryex; + } +} //returns the most recent val Object lock(Ref ref){ - boolean unlocked = false; + //can't upgrade readLock, so release it + releaseIfEnsured(ref); + + boolean unlocked = true; try { - ref.lock.writeLock().lock(); + tryWriteLock(ref); + unlocked = false; + if(ref.tvals != null && ref.tvals.point > readPoint) throw retryex; Info refinfo = ref.tinfo; @@ -122,9 +142,23 @@ Object lock(Ref ref){ { ref.lock.writeLock().unlock(); unlocked = true; - //stop prior to blocking - stop(RETRY); - synchronized(refinfo) + return blockAndBail(refinfo); + } + } + ref.tinfo = info; + return ref.tvals == null ? null : ref.tvals.val; + } + finally + { + if(!unlocked) + ref.lock.writeLock().unlock(); + } +} + +private Object blockAndBail(Info refinfo){ +//stop prior to blocking + stop(RETRY); + synchronized(refinfo) { if(refinfo.running()) { @@ -133,20 +167,18 @@ Object lock(Ref ref){ refinfo.wait(LOCK_WAIT_MSECS); } catch(InterruptedException e) - { - } - } - } - throw retryex; + { } } - ref.tinfo = info; - return ref.tvals == null ? null : ref.tvals.val; } - finally + throw retryex; +} + +private void releaseIfEnsured(Ref ref){ + if(ensures.contains(ref)) { - if(!unlocked) - ref.lock.writeLock().unlock(); + ensures.remove(ref); + ref.lock.readLock().unlock(); } } @@ -240,8 +272,16 @@ Object run(Callable fn) throws Exception{ for(Map.Entry<Ref, ArrayList<CFn>> e : commutes.entrySet()) { Ref ref = e.getKey(); - ref.lock.writeLock().lock(); + if(sets.contains(ref)) continue; + + boolean wasEnsured = ensures.contains(ref); + //can't upgrade readLock, so release it + releaseIfEnsured(ref); + tryWriteLock(ref); locked.add(ref); + if(wasEnsured && ref.tvals != null && ref.tvals.point > readPoint) + throw retryex; + Info refinfo = ref.tinfo; if(refinfo != null && refinfo != info && refinfo.running()) { @@ -249,8 +289,7 @@ Object run(Callable fn) throws Exception{ throw retryex; } Object val = ref.tvals == null ? null : ref.tvals.val; - if(!sets.contains(ref)) - vals.put(ref, val); + vals.put(ref, val); for(CFn f : e.getValue()) { vals.put(ref, f.fn.applyTo(RT.cons(vals.get(ref), f.args))); @@ -258,11 +297,8 @@ Object run(Callable fn) throws Exception{ } for(Ref ref : sets) { - if(!commutes.containsKey(ref)) - { - ref.lock.writeLock().lock(); - locked.add(ref); - } + tryWriteLock(ref); + locked.add(ref); } //validate and enqueue notifications @@ -319,6 +355,11 @@ Object run(Callable fn) throws Exception{ locked.get(k).lock.writeLock().unlock(); } locked.clear(); + for(Ref r : ensures) + { + r.lock.readLock().unlock(); + } + ensures.clear(); stop(done ? COMMITTED : RETRY); try { @@ -391,10 +432,27 @@ Object doSet(Ref ref, Object val){ return val; } -void doTouch(Ref ref){ +void doEnsure(Ref ref){ if(!info.running()) throw retryex; - lock(ref); + if(ensures.contains(ref)) + return; + ref.lock.readLock().lock(); + + Info refinfo = ref.tinfo; + + //writer exists + if(refinfo != null && refinfo.running()) + { + ref.lock.readLock().unlock(); + + if(refinfo != info) //not us, ensure is doomed + { + blockAndBail(refinfo); + } + } + else + ensures.add(ref); } Object doCommute(Ref ref, IFn fn, ISeq args) throws Exception{ diff --git a/src/jvm/clojure/lang/Ref.java b/src/jvm/clojure/lang/Ref.java index fef7c439..a4626acb 100644 --- a/src/jvm/clojure/lang/Ref.java +++ b/src/jvm/clojure/lang/Ref.java @@ -175,7 +175,7 @@ public Object alter(IFn fn, ISeq args) throws Exception{ } public void touch(){ - LockingTransaction.getEx().doTouch(this); + LockingTransaction.getEx().doEnsure(this); } //*/ diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java index 598a5785..e9286c36 100644 --- a/src/jvm/clojure/lang/Var.java +++ b/src/jvm/clojure/lang/Var.java @@ -309,6 +309,19 @@ public static void releaseThreadBindings(){ dvals.set(null); } +public static Associative getThreadBindings(){ + Frame f = dvals.get(); + IPersistentMap ret = PersistentHashMap.EMPTY; + for(ISeq bs = f.bindings.seq(); bs != null; bs = bs.next()) + { + IMapEntry e = (IMapEntry) bs.first(); + Var v = (Var) e.key(); + Box b = (Box) e.val(); + ret = ret.assoc(v, b.val); + } + return ret; +} + final Box getThreadBinding(){ if(count.get() > 0) { |