Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/include/mm/as.h	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -102,8 +102,8 @@
 		asid_t asid;
 		
+		/** Number of references (i.e tasks that reference this as). */
+		atomic_t refcount;
+
 		mutex_t lock;
-		
-		/** Number of references (i.e tasks that reference this as). */
-		count_t refcount;
 		
 		/** B+tree of address space areas. */
@@ -148,8 +148,8 @@
 	asid_t asid;
 
+	/** Number of references (i.e tasks that reference this as). */
+	atomic_t refcount;
+
 	mutex_t lock;
-
-	/** Number of references (i.e tasks that reference this as). */
-	count_t refcount;
 
 	/** B+tree of address space areas. */
Index: kernel/generic/include/synch/mutex.h
===================================================================
--- kernel/generic/include/synch/mutex.h	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/include/synch/mutex.h	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -45,11 +45,9 @@
 
 #define mutex_lock(mtx) \
-	_mutex_lock_timeout((mtx),SYNCH_NO_TIMEOUT,SYNCH_FLAGS_NONE)
+	_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE)
 #define mutex_trylock(mtx) \
-	_mutex_lock_timeout((mtx),SYNCH_NO_TIMEOUT,SYNCH_FLAGS_NON_BLOCKING)
-#define mutex_lock_timeout(mtx,usec) \
-	_mutex_lock_timeout((mtx),(usec),SYNCH_FLAGS_NON_BLOCKING)
-#define mutex_lock_active(mtx) \
-	while (mutex_trylock((mtx)) != ESYNCH_OK_ATOMIC)
+	_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING)
+#define mutex_lock_timeout(mtx, usec) \
+	_mutex_lock_timeout((mtx), (usec), SYNCH_FLAGS_NON_BLOCKING)
 
 extern void mutex_initialize(mutex_t *mtx);
Index: kernel/generic/include/synch/spinlock.h
===================================================================
--- kernel/generic/include/synch/spinlock.h	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/include/synch/spinlock.h	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -102,4 +102,22 @@
 }
 
+#ifdef CONFIG_DEBUG_SPINLOCK
+
+extern int printf(const char *, ...);
+
+#define DEADLOCK_THRESHOLD		100000000
+#define DEADLOCK_PROBE_INIT(pname)	count_t pname = 0
+#define DEADLOCK_PROBE(pname, value)					\
+	if ((pname)++ > (value)) {					\
+		(pname) = 0;						\
+		printf("Deadlock probe %s: exceeded threshold %d\n",	\
+		    "cpu%d: function=%s, line=%d\n",			\
+		    #pname, (value), CPU->id, __FUNCTION__, __LINE__);	\
+	}
+#else
+#define DEADLOCK_PROBE_INIT(pname)
+#define DEADLOCK_PROBE(pname, value)
+#endif
+
 #else
 
@@ -114,4 +132,7 @@
 #define spinlock_unlock(x)		preemption_enable()
 
+#define DEADLOCK_PROBE_INIT(pname)
+#define DEADLOCK_PROBE(pname, value)
+
 #endif
 
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/ipc/ipc.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -375,4 +375,5 @@
 	call_t *call;
 	phone_t *phone;
+	DEADLOCK_PROBE_INIT(p_phonelck);
 
 	/* Disconnect all our phones ('ipc_phone_hangup') */
@@ -388,7 +389,8 @@
 	while (!list_empty(&TASK->answerbox.connected_phones)) {
 		phone = list_get_instance(TASK->answerbox.connected_phones.next,
-					  phone_t, link);
+		    phone_t, link);
 		if (! spinlock_trylock(&phone->lock)) {
 			spinlock_unlock(&TASK->answerbox.lock);
+			DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
 			goto restart_phones;
 		}
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/ipc/irq.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -337,4 +337,5 @@
 		link_t *cur = box->irq_head.next;
 		irq_t *irq;
+		DEADLOCK_PROBE_INIT(p_irqlock);
 		
 		irq = list_get_instance(cur, irq_t, notif_cfg.link);
@@ -345,4 +346,5 @@
 			spinlock_unlock(&box->irq_lock);
 			interrupts_restore(ipl);
+			DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
 			goto loop;
 		}
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/mm/as.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -58,4 +58,5 @@
 #include <mm/asid.h>
 #include <arch/mm/asid.h>
+#include <preemption.h>
 #include <synch/spinlock.h>
 #include <synch/mutex.h>
@@ -182,5 +183,5 @@
 		as->asid = ASID_INVALID;
 	
-	as->refcount = 0;
+	atomic_set(&as->refcount, 0);
 	as->cpu_refcount = 0;
 #ifdef AS_PAGE_TABLE
@@ -197,4 +198,6 @@
  * When there are no tasks referencing this address space (i.e. its refcount is
  * zero), the address space can be destroyed.
+ *
+ * We know that we don't hold any spinlock.
  */
 void as_destroy(as_t *as)
@@ -202,6 +205,7 @@
 	ipl_t ipl;
 	bool cond;
-
-	ASSERT(as->refcount == 0);
+	DEADLOCK_PROBE_INIT(p_asidlock);
+
+	ASSERT(atomic_get(&as->refcount) == 0);
 	
 	/*
@@ -210,6 +214,21 @@
 	 */
 
-	ipl = interrupts_disable();
-	spinlock_lock(&asidlock);
+	/*
+	 * We need to avoid deadlock between TLB shootdown and asidlock.
+	 * We therefore try to take asid conditionally and if we don't succeed,
+	 * we enable interrupts and try again. This is done while preemption is
+	 * disabled to prevent nested context switches. We also depend on the
+	 * fact that so far no spinlocks are held.
+	 */
+	preemption_disable();
+	ipl = interrupts_read();
+retry:
+	interrupts_disable();
+	if (!spinlock_trylock(&asidlock)) {
+		interrupts_enable();
+		DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
+		goto retry;
+	}
+	preemption_enable();	/* Interrupts disabled, enable preemption */
 	if (as->asid != ASID_INVALID && as != AS_KERNEL) {
 		if (as != AS && as->cpu_refcount == 0)
@@ -473,13 +492,14 @@
 		 * Finish TLB shootdown sequence.
 		 */
+
 		tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
 		    area->pages - pages);
+		/*
+		 * Invalidate software translation caches (e.g. TSB on sparc64).
+		 */
+		as_invalidate_translation_cache(as, area->base +
+		    pages * PAGE_SIZE, area->pages - pages);
 		tlb_shootdown_finalize();
 		
-		/*
-		 * Invalidate software translation caches (e.g. TSB on sparc64).
-		 */
-		as_invalidate_translation_cache(as, area->base +
-		    pages * PAGE_SIZE, area->pages - pages);
 	} else {
 		/*
@@ -569,7 +589,6 @@
 	 * Finish TLB shootdown sequence.
 	 */
+
 	tlb_invalidate_pages(as->asid, area->base, area->pages);
-	tlb_shootdown_finalize();
-	
 	/*
 	 * Invalidate potential software translation caches (e.g. TSB on
@@ -577,4 +596,5 @@
 	 */
 	as_invalidate_translation_cache(as, area->base, area->pages);
+	tlb_shootdown_finalize();
 	
 	btree_destroy(&area->used_space);
@@ -868,4 +888,6 @@
  * thing which is forbidden in this context is locking the address space.
  *
+ * When this function is enetered, no spinlocks may be held.
+ *
  * @param old Old address space or NULL.
  * @param new New address space.
@@ -873,5 +895,20 @@
 void as_switch(as_t *old_as, as_t *new_as)
 {
-	spinlock_lock(&asidlock);
+	DEADLOCK_PROBE_INIT(p_asidlock);
+	preemption_disable();
+retry:
+	(void) interrupts_disable();
+	if (!spinlock_trylock(&asidlock)) {
+		/* 
+		 * Avoid deadlock with TLB shootdown.
+		 * We can enable interrupts here because
+		 * preemption is disabled. We should not be
+		 * holding any other lock.
+		 */
+		(void) interrupts_enable();
+		DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
+		goto retry;
+	}
+	preemption_enable();
 
 	/*
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/proc/scheduler.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -378,5 +378,6 @@
 {
 	int priority;
-	
+	DEADLOCK_PROBE_INIT(p_joinwq);
+
 	ASSERT(CPU != NULL);
 	
@@ -407,4 +408,6 @@
 					delay(10);
 					spinlock_lock(&THREAD->lock);
+					DEADLOCK_PROBE(p_joinwq,
+					    DEADLOCK_THRESHOLD);
 					goto repeat;
 				}
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/proc/task.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -42,4 +42,5 @@
 #include <mm/as.h>
 #include <mm/slab.h>
+#include <atomic.h>
 #include <synch/spinlock.h>
 #include <synch/waitq.h>
@@ -141,9 +142,6 @@
 	/*
 	 * Increment address space reference count.
-	 * TODO: Reconsider the locking scheme.
-	 */
-	mutex_lock(&as->lock);
-	as->refcount++;
-	mutex_unlock(&as->lock);
+	 */
+	atomic_inc(&as->refcount);
 
 	spinlock_lock(&tasks_lock);
@@ -167,13 +165,6 @@
 	btree_destroy(&t->futexes);
 
-	mutex_lock_active(&t->as->lock);
-	if (--t->as->refcount == 0) {
-		mutex_unlock(&t->as->lock);
+	if (atomic_predec(&t->as->refcount) == 0) 
 		as_destroy(t->as);
-		/*
-		 * t->as is destroyed.
-		 */
-	} else
-		mutex_unlock(&t->as->lock);
 	
 	free(t);
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/proc/thread.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -497,5 +497,5 @@
 
 	/*
-	 * Since the thread is expected to not be already detached,
+	 * Since the thread is expected not to be already detached,
 	 * pointer to it must be still valid.
 	 */
Index: kernel/generic/src/synch/spinlock.c
===================================================================
--- kernel/generic/src/synch/spinlock.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/synch/spinlock.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -74,5 +74,4 @@
  */
 #ifdef CONFIG_DEBUG_SPINLOCK
-#define DEADLOCK_THRESHOLD	100000000
 void spinlock_lock_debug(spinlock_t *sl)
 {
Index: kernel/generic/src/synch/waitq.c
===================================================================
--- kernel/generic/src/synch/waitq.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/synch/waitq.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -87,4 +87,5 @@
 	waitq_t *wq;
 	bool do_wakeup = false;
+	DEADLOCK_PROBE_INIT(p_wqlock);
 
 	spinlock_lock(&threads_lock);
@@ -97,4 +98,5 @@
 		if (!spinlock_trylock(&wq->lock)) {
 			spinlock_unlock(&t->lock);
+			DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
 			goto grab_locks;	/* avoid deadlock */
 		}
@@ -129,4 +131,5 @@
 	bool do_wakeup = false;
 	ipl_t ipl;
+	DEADLOCK_PROBE_INIT(p_wqlock);
 
 	ipl = interrupts_disable();
@@ -148,4 +151,5 @@
 		if (!spinlock_trylock(&wq->lock)) {
 			spinlock_unlock(&t->lock);
+			DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
 			goto grab_locks;	/* avoid deadlock */
 		}
Index: kernel/generic/src/time/timeout.c
===================================================================
--- kernel/generic/src/time/timeout.c	(revision 879585a3fd47daccb6ab751ad240297f65de5bae)
+++ kernel/generic/src/time/timeout.c	(revision 31d8e103d56f8142eb714a22e4d2cbd7e22e5b5a)
@@ -45,5 +45,4 @@
 #include <arch/asm.h>
 #include <arch.h>
-
 
 /** Initialize timeouts
@@ -176,4 +175,5 @@
 	link_t *l;
 	ipl_t ipl;
+	DEADLOCK_PROBE_INIT(p_tolock);
 
 grab_locks:
@@ -187,5 +187,6 @@
 	if (!spinlock_trylock(&t->cpu->timeoutlock)) {
 		spinlock_unlock(&t->lock);
-		interrupts_restore(ipl);		
+		interrupts_restore(ipl);
+		DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD);
 		goto grab_locks;
 	}
