summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/core.clj12
-rw-r--r--src/clj/clojure/zip.clj10
-rw-r--r--src/jvm/clojure/lang/Keyword.java4
-rw-r--r--src/jvm/clojure/lang/LispReader.java15
-rw-r--r--src/jvm/clojure/lang/LockingTransaction.java108
-rw-r--r--src/jvm/clojure/lang/Ref.java2
-rw-r--r--src/jvm/clojure/lang/Var.java13
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)
{