Index: uspace/lib/c/generic/async/client.c
===================================================================
--- uspace/lib/c/generic/async/client.c	(revision 9bde0d5d49e92705a496ff7207d8be4268690bb1)
+++ uspace/lib/c/generic/async/client.c	(revision bec18a999fe8f0a0d11e4e8b663b60185763e1c7)
@@ -104,5 +104,4 @@
 #include <ipc/irq.h>
 #include <ipc/event.h>
-#include <futex.h>
 #include <fibril.h>
 #include <adt/hash_table.h>
@@ -128,5 +127,5 @@
 /** Message data */
 typedef struct {
-	awaiter_t wdata;
+	fibril_event_t received;
 
 	/** If reply was received. */
@@ -136,7 +135,4 @@
 	bool forget;
 
-	/** If already destroyed. */
-	bool destroyed;
-
 	/** Pointer to where the answer data is stored. */
 	ipc_call_t *dataptr;
@@ -145,50 +141,11 @@
 } amsg_t;
 
-static void to_event_initialize(to_event_t *to)
-{
-	struct timeval tv = { 0, 0 };
-
-	to->inlist = false;
-	to->occurred = false;
-	link_initialize(&to->link);
-	to->expires = tv;
-}
-
-static void wu_event_initialize(wu_event_t *wu)
-{
-	wu->inlist = false;
-	link_initialize(&wu->link);
-}
-
-void awaiter_initialize(awaiter_t *aw)
-{
-	aw->fid = 0;
-	aw->active = false;
-	to_event_initialize(&aw->to_event);
-	wu_event_initialize(&aw->wu_event);
-}
-
 static amsg_t *amsg_create(void)
 {
-	amsg_t *msg = malloc(sizeof(amsg_t));
-	if (msg) {
-		msg->done = false;
-		msg->forget = false;
-		msg->destroyed = false;
-		msg->dataptr = NULL;
-		msg->retval = EINVAL;
-		awaiter_initialize(&msg->wdata);
-	}
-
-	return msg;
+	return calloc(1, sizeof(amsg_t));
 }
 
 static void amsg_destroy(amsg_t *msg)
 {
-	if (!msg)
-		return;
-
-	assert(!msg->destroyed);
-	msg->destroyed = true;
 	free(msg);
 }
@@ -251,22 +208,14 @@
 	msg->retval = IPC_GET_RETVAL(*data);
 
-	/* Copy data after futex_down, just in case the call was detached */
+	/* Copy data inside lock, just in case the call was detached */
 	if ((msg->dataptr) && (data))
 		*msg->dataptr = *data;
 
-	write_barrier();
-
-	/* Remove message from timeout list */
-	if (msg->wdata.to_event.inlist)
-		list_remove(&msg->wdata.to_event.link);
-
 	msg->done = true;
 
 	if (msg->forget) {
-		assert(msg->wdata.active);
 		amsg_destroy(msg);
-	} else if (!msg->wdata.active) {
-		msg->wdata.active = true;
-		fibril_add_ready(msg->wdata.fid);
+	} else {
+		fibril_notify(&msg->received);
 	}
 
@@ -301,5 +250,4 @@
 
 	msg->dataptr = dataptr;
-	msg->wdata.active = true;
 
 	errno_t rc = ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3,
@@ -343,5 +291,4 @@
 
 	msg->dataptr = dataptr;
-	msg->wdata.active = true;
 
 	errno_t rc = ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3,
@@ -371,24 +318,6 @@
 
 	amsg_t *msg = (amsg_t *) amsgid;
-
-	futex_lock(&async_futex);
-
-	assert(!msg->forget);
-	assert(!msg->destroyed);
-
-	if (msg->done) {
-		futex_unlock(&async_futex);
-		goto done;
-	}
-
-	msg->wdata.fid = fibril_get_id();
-	msg->wdata.active = false;
-	msg->wdata.to_event.inlist = false;
-
-	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_FROM_BLOCKED);
-	futex_unlock(&async_futex);
-
-done:
+	fibril_wait_for(&msg->received);
+
 	if (retval)
 		*retval = msg->retval;
@@ -420,14 +349,4 @@
 
 	amsg_t *msg = (amsg_t *) amsgid;
-
-	futex_lock(&async_futex);
-
-	assert(!msg->forget);
-	assert(!msg->destroyed);
-
-	if (msg->done) {
-		futex_unlock(&async_futex);
-		goto done;
-	}
 
 	/*
@@ -438,36 +357,12 @@
 		timeout = 0;
 
-	getuptime(&msg->wdata.to_event.expires);
-	tv_add_diff(&msg->wdata.to_event.expires, timeout);
-
-	/*
-	 * Current fibril is inserted as waiting regardless of the
-	 * "size" of the timeout.
-	 *
-	 * Checking for msg->done and immediately bailing out when
-	 * timeout == 0 would mean that the manager fibril would never
-	 * run (consider single threaded program).
-	 * Thus the IPC answer would be never retrieved from the kernel.
-	 *
-	 * Notice that the actual delay would be very small because we
-	 * - switch to manager fibril
-	 * - the manager sees expired timeout
-	 * - and thus adds us back to ready queue
-	 * - manager switches back to some ready fibril
-	 *   (prior it, it checks for incoming IPC).
-	 *
-	 */
-	msg->wdata.fid = fibril_get_id();
-	msg->wdata.active = false;
-	async_insert_timeout(&msg->wdata);
-
-	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_FROM_BLOCKED);
-	futex_unlock(&async_futex);
-
-	if (!msg->done)
-		return ETIMEOUT;
-
-done:
+	struct timeval expires;
+	getuptime(&expires);
+	tv_add_diff(&expires, timeout);
+
+	errno_t rc = fibril_wait_timeout(&msg->received, &expires);
+	if (rc != EOK)
+		return rc;
+
 	if (retval)
 		*retval = msg->retval;
@@ -475,5 +370,5 @@
 	amsg_destroy(msg);
 
-	return 0;
+	return EOK;
 }
 
@@ -494,5 +389,4 @@
 
 	assert(!msg->forget);
-	assert(!msg->destroyed);
 
 	futex_lock(&async_futex);
@@ -506,49 +400,4 @@
 
 	futex_unlock(&async_futex);
-}
-
-/** Wait for specified time.
- *
- * The current fibril is suspended but the thread continues to execute.
- *
- * @param timeout Duration of the wait in microseconds.
- *
- */
-void fibril_usleep(suseconds_t timeout)
-{
-	awaiter_t awaiter;
-	awaiter_initialize(&awaiter);
-
-	awaiter.fid = fibril_get_id();
-
-	getuptime(&awaiter.to_event.expires);
-	tv_add_diff(&awaiter.to_event.expires, timeout);
-
-	futex_lock(&async_futex);
-
-	async_insert_timeout(&awaiter);
-
-	/* Leave the async_futex locked when entering this function */
-	fibril_switch(FIBRIL_FROM_BLOCKED);
-	futex_unlock(&async_futex);
-}
-
-/** Delay execution for the specified number of seconds
- *
- * @param sec Number of seconds to sleep
- */
-void fibril_sleep(unsigned int sec)
-{
-	/*
-	 * Sleep in 1000 second steps to support
-	 * full argument range
-	 */
-
-	while (sec > 0) {
-		unsigned int period = (sec > 1000) ? 1000 : sec;
-
-		fibril_usleep(period * 1000000);
-		sec -= period;
-	}
 }
 
@@ -716,5 +565,4 @@
 
 	msg->dataptr = &result;
-	msg->wdata.active = true;
 
 	errno_t rc = ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO,
Index: uspace/lib/c/generic/async/server.c
===================================================================
--- uspace/lib/c/generic/async/server.c	(revision 9bde0d5d49e92705a496ff7207d8be4268690bb1)
+++ uspace/lib/c/generic/async/server.c	(revision bec18a999fe8f0a0d11e4e8b663b60185763e1c7)
@@ -104,5 +104,4 @@
 #include <ipc/irq.h>
 #include <ipc/event.h>
-#include <futex.h>
 #include <fibril.h>
 #include <adt/hash_table.h>
@@ -118,4 +117,5 @@
 #include <stdlib.h>
 #include <macros.h>
+#include <str_error.h>
 #include <as.h>
 #include <abi/mm/as.h>
@@ -127,7 +127,4 @@
 /** Async framework global futex */
 futex_t async_futex = FUTEX_INITIALIZER;
-
-/** Number of threads waiting for IPC in the kernel. */
-static atomic_t threads_in_ipc_wait = { 0 };
 
 /** Call data */
@@ -148,5 +145,6 @@
 /* Server connection data */
 typedef struct {
-	awaiter_t wdata;
+	/** Fibril handling the connection. */
+	fid_t fid;
 
 	/** Hash table link. */
@@ -161,4 +159,7 @@
 	/** Link to the client tracking structure. */
 	client_t *client;
+
+	/** Message event. */
+	fibril_event_t msg_arrived;
 
 	/** Messages that should be delivered to this fibril. */
@@ -251,5 +252,4 @@
 /* The remaining structures are guarded by async_futex. */
 static hash_table_t conn_hash_table;
-static LIST_INITIALIZE(timeout_list);
 
 static size_t client_key_hash(void *key)
@@ -487,9 +487,10 @@
 			ipc_answer_0(call->cap_handle, ENOMEM);
 
-		return (uintptr_t) NULL;
+		return (fid_t) NULL;
 	}
 
 	conn->in_task_id = in_task_id;
 	conn->in_phone_hash = in_phone_hash;
+	conn->msg_arrived = FIBRIL_EVENT_INIT;
 	list_initialize(&conn->msg_queue);
 	conn->close_chandle = CAP_NIL;
@@ -503,8 +504,7 @@
 
 	/* We will activate the fibril ASAP */
-	conn->wdata.active = true;
-	conn->wdata.fid = fibril_create(connection_fibril, conn);
-
-	if (conn->wdata.fid == 0) {
+	conn->fid = fibril_create(connection_fibril, conn);
+
+	if (conn->fid == 0) {
 		free(conn);
 
@@ -512,5 +512,5 @@
 			ipc_answer_0(call->cap_handle, ENOMEM);
 
-		return (uintptr_t) NULL;
+		return (fid_t) NULL;
 	}
 
@@ -521,7 +521,7 @@
 	futex_unlock(&async_futex);
 
-	fibril_add_ready(conn->wdata.fid);
-
-	return conn->wdata.fid;
+	fibril_add_ready(conn->fid);
+
+	return conn->fid;
 }
 
@@ -566,5 +566,5 @@
 	fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
 	    NULL, handler, data);
-	if (fid == (uintptr_t) NULL)
+	if (fid == (fid_t) NULL)
 		return ENOMEM;
 
@@ -602,30 +602,4 @@
 };
 
-/** Sort in current fibril's timeout request.
- *
- * @param wd Wait data of the current fibril.
- *
- */
-void async_insert_timeout(awaiter_t *wd)
-{
-	assert(wd);
-
-	wd->to_event.occurred = false;
-	wd->to_event.inlist = true;
-
-	link_t *tmp = timeout_list.head.next;
-	while (tmp != &timeout_list.head) {
-		awaiter_t *cur =
-		    list_get_instance(tmp, awaiter_t, to_event.link);
-
-		if (tv_gteq(&cur->to_event.expires, &wd->to_event.expires))
-			break;
-
-		tmp = tmp->next;
-	}
-
-	list_insert_before(&wd->to_event.link, tmp);
-}
-
 /** Try to route a call to an appropriate connection fibril.
  *
@@ -657,4 +631,5 @@
 	connection_t *conn = hash_table_get_inst(link, connection_t, link);
 
+	// FIXME: malloc in critical section
 	msg_t *msg = malloc(sizeof(*msg));
 	if (!msg) {
@@ -670,15 +645,5 @@
 
 	/* If the connection fibril is waiting for an event, activate it */
-	if (!conn->wdata.active) {
-
-		/* If in timeout list, remove it */
-		if (conn->wdata.to_event.inlist) {
-			conn->wdata.to_event.inlist = false;
-			list_remove(&conn->wdata.to_event.link);
-		}
-
-		conn->wdata.active = true;
-		fibril_add_ready(conn->wdata.fid);
-	}
+	fibril_notify(&conn->msg_arrived);
 
 	futex_unlock(&async_futex);
@@ -987,11 +952,13 @@
 	connection_t *conn = fibril_connection;
 
+	struct timeval tv;
+	struct timeval *expires = NULL;
+	if (usecs) {
+		getuptime(&tv);
+		tv_add_diff(&tv, usecs);
+		expires = &tv;
+	}
+
 	futex_lock(&async_futex);
-
-	if (usecs) {
-		getuptime(&conn->wdata.to_event.expires);
-		tv_add_diff(&conn->wdata.to_event.expires, usecs);
-	} else
-		conn->wdata.to_event.inlist = false;
 
 	/* If nothing in queue, wait until something arrives */
@@ -1011,23 +978,12 @@
 		}
 
-		if (usecs)
-			async_insert_timeout(&conn->wdata);
-
-		conn->wdata.active = false;
-
-		/*
-		 * Note: the current fibril will be rescheduled either due to a
-		 * timeout or due to an arriving message destined to it. In the
-		 * former case, handle_expired_timeouts() and, in the latter
-		 * case, route_call() will perform the wakeup.
-		 */
-		fibril_switch(FIBRIL_FROM_BLOCKED);
-
-		if ((usecs) && (conn->wdata.to_event.occurred) &&
-		    (list_empty(&conn->msg_queue))) {
-			/* If we timed out -> exit */
-			futex_unlock(&async_futex);
+		// TODO: replace with cvar
+		futex_unlock(&async_futex);
+
+		errno_t rc = fibril_wait_timeout(&conn->msg_arrived, expires);
+		if (rc == ETIMEOUT)
 			return false;
-		}
+
+		futex_lock(&async_futex);
 	}
 
@@ -1126,54 +1082,4 @@
 }
 
-/** Fire all timeouts that expired. */
-static suseconds_t handle_expired_timeouts(unsigned int *flags)
-{
-	/* Make sure the async_futex is held. */
-	futex_assert_is_locked(&async_futex);
-
-	struct timeval tv;
-	getuptime(&tv);
-
-	bool fired = false;
-
-	link_t *cur = list_first(&timeout_list);
-	while (cur != NULL) {
-		awaiter_t *waiter =
-		    list_get_instance(cur, awaiter_t, to_event.link);
-
-		if (tv_gt(&waiter->to_event.expires, &tv)) {
-			if (fired) {
-				*flags = SYNCH_FLAGS_NON_BLOCKING;
-				return 0;
-			}
-			*flags = 0;
-			return tv_sub_diff(&waiter->to_event.expires, &tv);
-		}
-
-		list_remove(&waiter->to_event.link);
-		waiter->to_event.inlist = false;
-		waiter->to_event.occurred = true;
-
-		/*
-		 * Redundant condition?
-		 * The fibril should not be active when it gets here.
-		 */
-		if (!waiter->active) {
-			waiter->active = true;
-			fibril_add_ready(waiter->fid);
-			fired = true;
-		}
-
-		cur = list_first(&timeout_list);
-	}
-
-	if (fired) {
-		*flags = SYNCH_FLAGS_NON_BLOCKING;
-		return 0;
-	}
-
-	return SYNCH_NO_TIMEOUT;
-}
-
 /** Endless loop dispatching incoming calls and answers.
  *
@@ -1183,24 +1089,9 @@
 static errno_t async_manager_worker(void)
 {
+	ipc_call_t call;
+	errno_t rc;
+
 	while (true) {
-		futex_lock(&async_futex);
-		fibril_switch(FIBRIL_FROM_MANAGER);
-
-		/*
-		 * The switch only returns when there is no non-manager fibril
-		 * it can run.
-		 */
-
-		unsigned int flags = SYNCH_FLAGS_NONE;
-		suseconds_t next_timeout = handle_expired_timeouts(&flags);
-		futex_unlock(&async_futex);
-
-		atomic_inc(&threads_in_ipc_wait);
-
-		ipc_call_t call;
-		errno_t rc = ipc_wait(&call, next_timeout, flags);
-
-		atomic_dec(&threads_in_ipc_wait);
-
+		rc = fibril_ipc_wait(&call, NULL);
 		if (rc == EOK)
 			handle_call(&call);
@@ -1225,15 +1116,9 @@
 
 /** Add one manager to manager list. */
-void async_create_manager(void)
+fid_t async_create_manager(void)
 {
 	fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE);
-	if (fid != 0)
-		fibril_add_manager(fid);
-}
-
-/** Remove one manager from manager list */
-void async_destroy_manager(void)
-{
-	fibril_remove_manager();
+	fibril_start(fid);
+	return fid;
 }
 
@@ -1252,4 +1137,6 @@
 	    &notification_hash_table_ops))
 		abort();
+
+	async_create_manager();
 }
 
@@ -1342,11 +1229,4 @@
 
 	return EOK;
-}
-
-/** Interrupt one thread of this task from waiting for IPC. */
-void async_poke(void)
-{
-	if (atomic_get(&threads_in_ipc_wait) > 0)
-		ipc_poke();
 }
 
@@ -1834,6 +1714,6 @@
 __noreturn void async_manager(void)
 {
-	futex_lock(&async_futex);
-	fibril_switch(FIBRIL_FROM_DEAD);
+	fibril_event_t ever = FIBRIL_EVENT_INIT;
+	fibril_wait_for(&ever);
 	__builtin_unreachable();
 }
