Index: uspace/lib/c/include/futex.h
===================================================================
--- uspace/lib/c/include/futex.h	(revision cb10bc9a558169f21c11cf80a9da8706c68bcdc3)
+++ uspace/lib/c/include/futex.h	(revision 1b7eec9d6a4ae85223280afbf0d3b7a82de447cb)
@@ -40,6 +40,6 @@
 #include <libc.h>
 
-
-#define FUTEX_INITIALIZER  {{1}}
+#define FUTEX_INITIALIZE(val) {{(val)}}
+#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
 
 typedef struct futex {
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision cb10bc9a558169f21c11cf80a9da8706c68bcdc3)
+++ uspace/lib/c/include/sys/time.h	(revision 1b7eec9d6a4ae85223280afbf0d3b7a82de447cb)
@@ -79,4 +79,5 @@
 
 extern void udelay(useconds_t);
+extern int usleep(useconds_t);
 
 extern time_t mktime(struct tm *tm);
Index: uspace/lib/urcu/rcu.c
===================================================================
--- uspace/lib/urcu/rcu.c	(revision cb10bc9a558169f21c11cf80a9da8706c68bcdc3)
+++ uspace/lib/urcu/rcu.c	(revision 1b7eec9d6a4ae85223280afbf0d3b7a82de447cb)
@@ -78,4 +78,5 @@
 #include <smp_memory_barrier.h>
 #include <assert.h>
+#include <time.h>
 
 
@@ -99,10 +100,22 @@
 /** Process global RCU data. */
 typedef struct rcu_data {
-	fibril_mutex_t mtx;
 	size_t cur_gp;
 	size_t reader_group;
 	futex_t list_futex;
 	list_t fibrils_list;
+	struct {
+		futex_t futex;
+		bool locked;
+		list_t blocked_fibrils;
+		size_t blocked_thread_cnt;
+		futex_t futex_blocking_threads;
+	} sync_lock;
 } rcu_data_t;
+
+typedef struct blocked_fibril {
+	fid_t id;
+	link_t link;
+	bool is_ready;
+} blocked_fibril_t;
 
 
@@ -119,15 +132,25 @@
 /** Process global RCU data. */
 static rcu_data_t rcu = {
-	.mtx = FIBRIL_MUTEX_INITIALIZER(rcu.mtx),
 	.cur_gp = 0,
 	.reader_group = RCU_GROUP_A,
 	.list_futex = FUTEX_INITIALIZER,
 	.fibrils_list = LIST_INITIALIZER(rcu.fibrils_list),
+	.sync_lock = {
+		.futex = FUTEX_INITIALIZER,
+		.locked = false,
+		.blocked_fibrils = LIST_INITIALIZER(rcu.sync_lock.blocked_fibrils),
+		.blocked_thread_cnt = 0,
+		.futex_blocking_threads = FUTEX_INITIALIZE(0),
+	},
 };
 
 
-static void wait_for_readers(size_t reader_group);
+static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode);
 static void force_mb_in_all_threads(void);
 static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group);
+
+static void lock_sync(blocking_mode_t blocking_mode);
+static void unlock_sync(void);
+static void sync_sleep(blocking_mode_t blocking_mode);
 
 static bool is_in_group(size_t nesting_cnt, size_t group);
@@ -145,7 +168,7 @@
 	assert(!fibril_rcu.registered);
 	
-	futex_down(&rcu.list_futex);
+	_futex_down(&rcu.list_futex);
 	list_append(&fibril_rcu.link, &rcu.fibrils_list);
-	futex_up(&rcu.list_futex);
+	_futex_up(&rcu.list_futex);
 	
 	fibril_rcu.registered = true;
@@ -170,7 +193,7 @@
 	fibril_rcu.nesting_cnt = 0;
 	
-	futex_down(&rcu.list_futex);
+	_futex_down(&rcu.list_futex);
 	list_remove(&fibril_rcu.link);
-	futex_up(&rcu.list_futex);
+	_futex_up(&rcu.list_futex);
 
 	fibril_rcu.registered = false;
@@ -214,5 +237,5 @@
 
 /** Blocks until all preexisting readers exit their critical sections. */
-void rcu_synchronize(void)
+void _rcu_synchronize(blocking_mode_t blocking_mode)
 {
 	assert(!rcu_read_locked());
@@ -224,6 +247,5 @@
 	size_t gp_in_progress = ACCESS_ONCE(rcu.cur_gp);
 	
-	/* todo: early exit for batched sync()s */
-	fibril_mutex_lock(&rcu.mtx);
+	lock_sync(blocking_mode);
 	
 	/* 
@@ -236,5 +258,5 @@
 	/* rcu.cur_gp >= gp_in_progress + 2, but tolerates overflows. */
 	if (rcu.cur_gp != gp_in_progress && rcu.cur_gp + 1 != gp_in_progress) {
-		fibril_mutex_unlock(&rcu.mtx);
+		unlock_sync();
 		return;
 	}
@@ -273,5 +295,5 @@
 	
 	size_t new_reader_group = get_other_group(rcu.reader_group);
-	wait_for_readers(new_reader_group);
+	wait_for_readers(new_reader_group, blocking_mode);
 	
 	/* Separates waiting for readers in new_reader_group from group flip. */
@@ -285,10 +307,10 @@
 	memory_barrier();
 	
-	wait_for_readers(old_reader_group);
+	wait_for_readers(old_reader_group, blocking_mode);
 	
 	/* MB_FORCE_U  */
 	force_mb_in_all_threads(); /* MB_FORCE_U */
 	
-	fibril_mutex_unlock(&rcu.mtx);
+	unlock_sync();
 }
 
@@ -305,7 +327,7 @@
 
 /** Waits for readers of reader_group to exit their readers sections. */
-static void wait_for_readers(size_t reader_group)
-{
-	futex_down(&rcu.list_futex);
+static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode)
+{
+	_futex_down(&rcu.list_futex);
 	
 	list_t quiescent_fibrils;
@@ -318,7 +340,8 @@
 			
 			if (is_preexisting_reader(fib, reader_group)) {
-				futex_up(&rcu.list_futex);
-				async_usleep(RCU_SLEEP_MS * 1000);
-				futex_down(&rcu.list_futex);
+				_futex_up(&rcu.list_futex);
+				sync_sleep(blocking_mode);
+				_futex_down(&rcu.list_futex);
+				/* Break to while loop. */
 				break;
 			} else {
@@ -330,6 +353,84 @@
 	
 	list_concat(&rcu.fibrils_list, &quiescent_fibrils);
-	futex_up(&rcu.list_futex);
-}
+	_futex_up(&rcu.list_futex);
+}
+
+static void lock_sync(blocking_mode_t blocking_mode)
+{
+	_futex_down(&rcu.sync_lock.futex);
+	if (rcu.sync_lock.locked) {
+		if (blocking_mode == BM_BLOCK_FIBRIL) {
+			blocked_fibril_t blocked_fib;
+			blocked_fib.id = fibril_get_id();
+				
+			list_append(&blocked_fib.link, &rcu.sync_lock.blocked_fibrils);
+			
+			do {
+				blocked_fib.is_ready = false;
+				_futex_up(&rcu.sync_lock.futex);
+				fibril_switch(FIBRIL_TO_MANAGER);
+				_futex_down(&rcu.sync_lock.futex);
+			} while (rcu.sync_lock.locked);
+			
+			list_remove(&blocked_fib.link);
+			rcu.sync_lock.locked = true;
+		} else {
+			assert(blocking_mode == BM_BLOCK_THREAD);
+			rcu.sync_lock.blocked_thread_cnt++;
+			_futex_up(&rcu.sync_lock.futex);
+			_futex_down(&rcu.sync_lock.futex_blocking_threads);
+		}
+	} else {
+		rcu.sync_lock.locked = true;
+	}
+}
+
+static void unlock_sync(void)
+{
+	assert(rcu.sync_lock.locked);
+	
+	/* 
+	 * Blocked threads have a priority over fibrils when accessing sync().
+	 * Pass the lock onto a waiting thread.
+	 */
+	if (0 < rcu.sync_lock.blocked_thread_cnt) {
+		--rcu.sync_lock.blocked_thread_cnt;
+		_futex_up(&rcu.sync_lock.futex_blocking_threads);
+	} else {
+		/* Unlock but wake up any fibrils waiting for the lock. */
+		
+		if (!list_empty(&rcu.sync_lock.blocked_fibrils)) {
+			blocked_fibril_t *blocked_fib = member_to_inst(
+				list_first(&rcu.sync_lock.blocked_fibrils), blocked_fibril_t, link);
+	
+			if (!blocked_fib->is_ready) {
+				blocked_fib->is_ready = true;
+				fibril_add_ready(blocked_fib->id);
+			}
+		}
+		
+		rcu.sync_lock.locked = false;
+		_futex_up(&rcu.sync_lock.futex);
+	}
+}
+
+static void sync_sleep(blocking_mode_t blocking_mode)
+{
+	assert(rcu.sync_lock.locked);
+	/* 
+	 * Release the futex to avoid deadlocks in singlethreaded apps 
+	 * but keep sync locked. 
+	 */
+	_futex_up(&rcu.sync_lock.futex);
+
+	if (blocking_mode == BM_BLOCK_FIBRIL) {
+		async_usleep(RCU_SLEEP_MS * 1000);
+	} else {
+		usleep(RCU_SLEEP_MS * 1000);
+	}
+		
+	_futex_down(&rcu.sync_lock.futex);
+}
+
 
 static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group)
Index: uspace/lib/urcu/rcu.h
===================================================================
--- uspace/lib/urcu/rcu.h	(revision cb10bc9a558169f21c11cf80a9da8706c68bcdc3)
+++ uspace/lib/urcu/rcu.h	(revision 1b7eec9d6a4ae85223280afbf0d3b7a82de447cb)
@@ -92,4 +92,8 @@
 #define rcu_access(ptr) ACCESS_ONCE(ptr)
 
+typedef enum blocking_mode {
+	BM_BLOCK_FIBRIL,
+	BM_BLOCK_THREAD
+} blocking_mode_t;
 
 extern void rcu_register_fibril(void);
@@ -101,5 +105,7 @@
 extern bool rcu_read_locked(void);
 
-extern void rcu_synchronize(void);
+#define rcu_synchronize() _rcu_synchronize(BM_BLOCK_FIBRIL)
+
+extern void _rcu_synchronize(blocking_mode_t);
 
 #endif
