Index: uspace/lib/c/generic/async/client.c
===================================================================
--- uspace/lib/c/generic/async/client.c	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/async/client.c	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -372,7 +372,6 @@
 
 	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_TO_MANAGER);
-
-	/* Futex is up automatically after fibril_switch */
+	fibril_switch(FIBRIL_FROM_BLOCKED);
+	futex_unlock(&async_futex);
 
 done:
@@ -445,7 +444,6 @@
 
 	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_TO_MANAGER);
-
-	/* Futex is up automatically after fibril_switch */
+	fibril_switch(FIBRIL_FROM_BLOCKED);
+	futex_unlock(&async_futex);
 
 	if (!msg->done)
@@ -511,7 +509,6 @@
 
 	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_TO_MANAGER);
-
-	/* Futex is up automatically after fibril_switch() */
+	fibril_switch(FIBRIL_FROM_BLOCKED);
+	futex_unlock(&async_futex);
 }
 
Index: uspace/lib/c/generic/async/server.c
===================================================================
--- uspace/lib/c/generic/async/server.c	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/async/server.c	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -997,11 +997,6 @@
 		 * case, route_call() will perform the wakeup.
 		 */
-		fibril_switch(FIBRIL_TO_MANAGER);
-
-		/*
-		 * Futex is up after getting back from async_manager.
-		 * Get it again.
-		 */
-		futex_lock(&async_futex);
+		fibril_switch(FIBRIL_FROM_BLOCKED);
+
 		if ((usecs) && (conn->wdata.to_event.occurred) &&
 		    (list_empty(&conn->msg_queue))) {
@@ -1143,14 +1138,11 @@
 {
 	while (true) {
-		if (fibril_switch(FIBRIL_FROM_MANAGER)) {
-			futex_unlock(&async_futex);
-			/*
-			 * async_futex is always held when entering a manager
-			 * fibril.
-			 */
-			continue;
-		}
-
 		futex_lock(&async_futex);
+		fibril_switch(FIBRIL_FROM_MANAGER);
+
+		/*
+		 * The switch only returns when there is no non-manager fibril
+		 * it can run.
+		 */
 
 		suseconds_t timeout;
@@ -1226,11 +1218,5 @@
 static errno_t async_manager_fibril(void *arg)
 {
-	futex_unlock(&async_futex);
-
-	/*
-	 * async_futex is always locked when entering manager
-	 */
 	async_manager_worker();
-
 	return 0;
 }
Index: uspace/lib/c/generic/fibril.c
===================================================================
--- uspace/lib/c/generic/fibril.c	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/fibril.c	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -71,6 +71,7 @@
 static void fibril_main(void)
 {
-	/* fibril_futex is locked when a fibril is first started. */
-	futex_unlock(&fibril_futex);
+	/* fibril_futex and async_futex are locked when a fibril is started. */
+	futex_unlock(&fibril_futex);
+	futex_unlock(&async_futex);
 
 	fibril_t *fibril = fibril_self();
@@ -127,6 +128,6 @@
 /** Switch from the current fibril.
  *
- * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
- * be held.
+ * The async_futex must be held when entering this function,
+ * and is still held on return.
  *
  * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
@@ -140,4 +141,7 @@
 int fibril_switch(fibril_switch_type_t stype)
 {
+	/* Make sure the async_futex is held. */
+	futex_assert_is_locked(&async_futex);
+
 	futex_lock(&fibril_futex);
 
@@ -146,9 +150,11 @@
 
 	/* Choose a new fibril to run */
-	switch (stype) {
-	case FIBRIL_TO_MANAGER:
-	case FIBRIL_FROM_DEAD:
-		/* Make sure the async_futex is held. */
-		futex_assert_is_locked(&async_futex);
+	if (list_empty(&ready_list)) {
+		if (stype == FIBRIL_PREEMPT) {
+			// FIXME: This means that as long as there is a fibril
+			// that only yields, IPC messages are never retrieved.
+			futex_unlock(&fibril_futex);
+			return 0;
+		}
 
 		/* If we are going to manager and none exists, create it */
@@ -161,25 +167,12 @@
 		dstf = list_get_instance(list_first(&manager_list),
 		    fibril_t, link);
-
-		/* Bookkeeping. */
-		futex_give_to(&async_futex, dstf);
-
-		if (stype == FIBRIL_FROM_DEAD)
-			dstf->clean_after_me = srcf;
-		break;
-	case FIBRIL_PREEMPT:
-	case FIBRIL_FROM_MANAGER:
-		futex_assert_is_not_locked(&async_futex);
-
-		if (list_empty(&ready_list)) {
-			futex_unlock(&fibril_futex);
-			return 0;
-		}
-
+	} else {
 		dstf = list_get_instance(list_first(&ready_list), fibril_t,
 		    link);
-		break;
-	}
+	}
+
 	list_remove(&dstf->link);
+	if (stype == FIBRIL_FROM_DEAD)
+		dstf->clean_after_me = srcf;
 
 	/* Put the current fibril into the correct run list */
@@ -192,16 +185,12 @@
 		break;
 	case FIBRIL_FROM_DEAD:
+	case FIBRIL_FROM_BLOCKED:
 		// Nothing.
 		break;
-	case FIBRIL_TO_MANAGER:
-		/*
-		 * Don't put the current fibril into any list, it should
-		 * already be somewhere, or it will be lost.
-		 */
-		break;
 	}
 
 	/* Bookkeeping. */
 	futex_give_to(&fibril_futex, dstf);
+	futex_give_to(&async_futex, dstf);
 
 	/* Swap to the next fibril. */
@@ -350,5 +339,7 @@
 void fibril_yield(void)
 {
-	fibril_switch(FIBRIL_PREEMPT);
+	futex_lock(&async_futex);
+	(void) fibril_switch(FIBRIL_PREEMPT);
+	futex_unlock(&async_futex);
 }
 
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/fibril_synch.c	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -116,9 +116,9 @@
 		check_for_deadlock(&fm->oi);
 		f->waits_for = &fm->oi;
-		fibril_switch(FIBRIL_TO_MANAGER);
+		fibril_switch(FIBRIL_FROM_BLOCKED);
 	} else {
 		fm->oi.owned_by = f;
-		futex_unlock(&async_futex);
-	}
+	}
+	futex_unlock(&async_futex);
 }
 
@@ -206,11 +206,11 @@
 		check_for_deadlock(&frw->oi);
 		f->waits_for = &frw->oi;
-		fibril_switch(FIBRIL_TO_MANAGER);
+		fibril_switch(FIBRIL_FROM_BLOCKED);
 	} else {
 		/* Consider the first reader the owner. */
 		if (frw->readers++ == 0)
 			frw->oi.owned_by = f;
-		futex_unlock(&async_futex);
-	}
+	}
+	futex_unlock(&async_futex);
 }
 
@@ -230,10 +230,10 @@
 		check_for_deadlock(&frw->oi);
 		f->waits_for = &frw->oi;
-		fibril_switch(FIBRIL_TO_MANAGER);
+		fibril_switch(FIBRIL_FROM_BLOCKED);
 	} else {
 		frw->oi.owned_by = f;
 		frw->writers++;
-		futex_unlock(&async_futex);
-	}
+	}
+	futex_unlock(&async_futex);
 }
 
@@ -377,8 +377,12 @@
 	list_append(&wdata.wu_event.link, &fcv->waiters);
 	_fibril_mutex_unlock_unsafe(fm);
-	fibril_switch(FIBRIL_TO_MANAGER);
+	fibril_switch(FIBRIL_FROM_BLOCKED);
+	futex_unlock(&async_futex);
+
+	// XXX: This could be replaced with an unlocked version to get rid
+	// of the unlock-lock pair. I deliberately don't do that because
+	// further changes would most likely need to revert that optimization.
 	fibril_mutex_lock(fm);
 
-	/* async_futex not held after fibril_switch() */
 	futex_lock(&async_futex);
 	if (wdata.to_event.inlist)
@@ -698,7 +702,7 @@
 	wdata.fid = fibril_get_id();
 	list_append(&wdata.wu_event.link, &sem->waiters);
-	fibril_switch(FIBRIL_TO_MANAGER);
-
-	/* async_futex not held after fibril_switch() */
+
+	fibril_switch(FIBRIL_FROM_BLOCKED);
+	futex_unlock(&async_futex);
 }
 
Index: uspace/lib/c/generic/private/fibril.h
===================================================================
--- uspace/lib/c/generic/private/fibril.h	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/private/fibril.h	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -59,5 +59,5 @@
 typedef enum {
 	FIBRIL_PREEMPT,
-	FIBRIL_TO_MANAGER,
+	FIBRIL_FROM_BLOCKED,
 	FIBRIL_FROM_MANAGER,
 	FIBRIL_FROM_DEAD
Index: uspace/lib/c/generic/rcu.c
===================================================================
--- uspace/lib/c/generic/rcu.c	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
+++ uspace/lib/c/generic/rcu.c	(revision ab6edb66478acf791a711b3f91d2a5a370fb7a0c)
@@ -373,5 +373,7 @@
 			blocked_fib.is_ready = false;
 			futex_unlock(&rcu.sync_lock.futex);
-			fibril_switch(FIBRIL_TO_MANAGER);
+			futex_lock(&async_futex);
+			fibril_switch(FIBRIL_FROM_BLOCKED);
+			futex_unlock(&async_futex);
 			futex_lock(&rcu.sync_lock.futex);
 		} while (rcu.sync_lock.locked);
