Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/app/trace/ipcp.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -323,5 +323,6 @@
 	pending_call_t *pcall;
 	
-	if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
+	if ((call->flags & IPC_CALLID_ANSWERED) == 0 &&
+	    hash != IPCP_CALLID_SYNC) {
 		/* Not a response */
 		if ((display_mask & DM_IPC) != 0) {
@@ -331,6 +332,4 @@
 	}
 	
-	hash = hash & ~IPC_CALLID_ANSWERED;
-	
 	item = hash_table_find(&pending_calls, &hash);
 	if (item == NULL)
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/app/trace/syscalls.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -54,5 +54,5 @@
 
     [SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6,	V_HASH },
-    [SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2,	V_HASH },
+    [SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 3,	V_HASH },
 
     [SYS_IPC_ANSWER_FAST] = { "ipc_answer_fast",	6,	V_ERRNO },
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/lib/c/generic/async.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -1341,5 +1341,5 @@
 	
 	/* Kernel notification */
-	if ((callid & IPC_CALLID_NOTIFICATION)) {
+	if (call->flags & IPC_CALLID_NOTIFICATION) {
 		fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data;
 		unsigned oldsw = fibril->switches;
@@ -1495,5 +1495,5 @@
 		}
 		
-		if (callid & IPC_CALLID_ANSWERED)
+		if (call.flags & IPC_CALLID_ANSWERED)
 			continue;
 		
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/lib/c/generic/ipc.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2017 Jakub Jermar
  * All rights reserved.
  *
@@ -50,49 +51,15 @@
 
 /**
- * Structures of this type are used for keeping track
- * of sent asynchronous calls and queing unsent calls.
- */
-typedef struct {
-	link_t list;
-	
+ * Structures of this type are used for keeping track of sent asynchronous calls.
+ */
+typedef struct async_call {
 	ipc_async_callback_t callback;
 	void *private;
 	
-	union {
-		ipc_callid_t callid;
-		struct {
-			ipc_call_t data;
-			int phoneid;
-		} msg;
-	} u;
-	
-	/** Fibril waiting for sending this call. */
-	fid_t fid;
+	struct {
+		ipc_call_t data;
+		int phoneid;
+	} msg;
 } async_call_t;
-
-LIST_INITIALIZE(dispatched_calls);
-
-/** List of asynchronous calls that were not accepted by kernel.
- *
- * Protected by async_futex, because if the call is not accepted
- * by the kernel, the async framework is used automatically.
- *
- */
-LIST_INITIALIZE(queued_calls);
-
-static futex_t ipc_futex = FUTEX_INITIALIZER;
-
-/** Send asynchronous message via syscall.
- *
- * @param phoneid Phone handle for the call.
- * @param data    Call data with the request.
- *
- * @return Hash of the call or an error code.
- *
- */
-static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
-{
-	return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
-}
 
 /** Prologue for ipc_call_async_*() functions.
@@ -133,11 +100,8 @@
 	if (!call) {
 		/* Nothing to do regardless if failed or not */
-		futex_unlock(&ipc_futex);
 		return;
 	}
 	
 	if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
-		futex_unlock(&ipc_futex);
-		
 		/* Call asynchronous handler with error code */
 		if (call->callback)
@@ -147,15 +111,9 @@
 		return;
 	}
-	
-	call->u.callid = callid;
-	
-	/* Add call to the list of dispatched calls */
-	list_append(&call->list, &dispatched_calls);
-	futex_unlock(&ipc_futex);
 }
 
 /** Fast asynchronous call.
  *
- * This function can only handle four arguments of payload. It is, however,
+ * This function can only handle three arguments of payload. It is, however,
  * faster than the more generic ipc_call_async_slow().
  *
@@ -171,28 +129,16 @@
  * @param arg2        Service-defined payload argument.
  * @param arg3        Service-defined payload argument.
- * @param arg4        Service-defined payload argument.
  * @param private     Argument to be passed to the answer/error callback.
  * @param callback    Answer or error callback.
  */
 void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
-    ipc_async_callback_t callback)
-{
-	async_call_t *call = NULL;
-	
-	if (callback) {
-		call = ipc_prepare_async(private, callback);
-		if (!call)
-			return;
-	}
-	
-	/*
-	 * We need to make sure that we get callid
-	 * before another thread accesses the queue again.
-	 */
-	
-	futex_lock(&ipc_futex);
+    sysarg_t arg2, sysarg_t arg3, void *private, ipc_async_callback_t callback)
+{
+	async_call_t *call = ipc_prepare_async(private, callback);
+	if (!call)
+		return;
+	
 	ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
-	    imethod, arg1, arg2, arg3, arg4);
+	    imethod, arg1, arg2, arg3, (sysarg_t) call);
 	
 	ipc_finish_async(callid, phoneid, call);
@@ -225,19 +171,13 @@
 		return;
 	
-	IPC_SET_IMETHOD(call->u.msg.data, imethod);
-	IPC_SET_ARG1(call->u.msg.data, arg1);
-	IPC_SET_ARG2(call->u.msg.data, arg2);
-	IPC_SET_ARG3(call->u.msg.data, arg3);
-	IPC_SET_ARG4(call->u.msg.data, arg4);
-	IPC_SET_ARG5(call->u.msg.data, arg5);
-	
-	/*
-	 * We need to make sure that we get callid
-	 * before another threadaccesses the queue again.
-	 */
-	
-	futex_lock(&ipc_futex);
-	ipc_callid_t callid =
-	    ipc_call_async_internal(phoneid, &call->u.msg.data);
+	IPC_SET_IMETHOD(call->msg.data, imethod);
+	IPC_SET_ARG1(call->msg.data, arg1);
+	IPC_SET_ARG2(call->msg.data, arg2);
+	IPC_SET_ARG3(call->msg.data, arg3);
+	IPC_SET_ARG4(call->msg.data, arg4);
+	IPC_SET_ARG5(call->msg.data, arg5);
+	
+	ipc_callid_t callid = __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW, phoneid,
+	    (sysarg_t) &call->msg.data, (sysarg_t) call);
 	
 	ipc_finish_async(callid, phoneid, call);
@@ -296,88 +236,19 @@
 }
 
-/** Try to dispatch queued calls from the async queue.
- *
- */
-static void dispatch_queued_calls(void)
-{
-	/** @todo
-	 * Integrate intelligently ipc_futex so that it is locked during
-	 * ipc_call_async_*() until it is added to dispatched_calls.
-	 */
-	
-	futex_down(&async_futex);
-	
-	while (!list_empty(&queued_calls)) {
-		async_call_t *call =
-		    list_get_instance(list_first(&queued_calls), async_call_t, list);
-		ipc_callid_t callid =
-		    ipc_call_async_internal(call->u.msg.phoneid, &call->u.msg.data);
-		
-		list_remove(&call->list);
-		
-		futex_up(&async_futex);
-		
-		assert(call->fid);
-		fibril_add_ready(call->fid);
-		
-		if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
-			if (call->callback)
-				call->callback(call->private, ENOENT, NULL);
-			
-			free(call);
-		} else {
-			call->u.callid = callid;
-			
-			futex_lock(&ipc_futex);
-			list_append(&call->list, &dispatched_calls);
-			futex_unlock(&ipc_futex);
-		}
-		
-		futex_down(&async_futex);
-	}
-	
-	futex_up(&async_futex);
-}
-
 /** Handle received answer.
- *
- * Find the hash of the answer and call the answer callback.
- *
- * The answer has the same hash as the request OR'ed with
- * the IPC_CALLID_ANSWERED bit.
- *
- * @todo Use hash table.
  *
  * @param callid Hash of the received answer.
  * @param data   Call data of the answer.
- *
  */
 static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
 {
-	callid &= ~IPC_CALLID_ANSWERED;
-	
-	futex_lock(&ipc_futex);
-	
-	link_t *item;
-	for (item = dispatched_calls.head.next; item != &dispatched_calls.head;
-	    item = item->next) {
-		async_call_t *call =
-		    list_get_instance(item, async_call_t, list);
-		
-		if (call->u.callid == callid) {
-			list_remove(&call->list);
-			
-			futex_unlock(&ipc_futex);
-			
-			if (call->callback)
-				call->callback(call->private,
-				    IPC_GET_RETVAL(*data), data);
-			
-			free(call);
-			return;
-		}
-	}
-	
-	futex_unlock(&ipc_futex);
+	async_call_t *call = data->label;
+
+	if (!call)
+		return;
+
+	if (call->callback)
+		call->callback(call->private, IPC_GET_RETVAL(*data), data);
+	free(call);
 }
 
@@ -388,8 +259,5 @@
  * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
  *
- * @return Hash of the call. Note that certain bits have special
- *         meaning: IPC_CALLID_ANSWERED is set in an answer
- *         and IPC_CALLID_NOTIFICATION is used for notifications.
- *
+ * @return Hash of the call.
  */
 ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
@@ -400,8 +268,6 @@
 	
 	/* Handle received answers */
-	if (callid & IPC_CALLID_ANSWERED) {
+	if (callid && (call->flags & IPC_CALLID_ANSWERED))
 		handle_answer(callid, call);
-		dispatch_queued_calls();
-	}
 	
 	return callid;
@@ -432,5 +298,5 @@
 	do {
 		callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
-	} while (callid & IPC_CALLID_ANSWERED);
+	} while (callid && (call->flags & IPC_CALLID_ANSWERED));
 	
 	return callid;
@@ -453,5 +319,5 @@
 		callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
 		    SYNCH_FLAGS_NON_BLOCKING);
-	} while (callid & IPC_CALLID_ANSWERED);
+	} while (callid && (call->flags & IPC_CALLID_ANSWERED));
 	
 	return callid;
Index: uspace/lib/c/include/ipc/common.h
===================================================================
--- uspace/lib/c/include/ipc/common.h	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/lib/c/include/ipc/common.h	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -43,8 +43,12 @@
 #define IPC_FLAG_BLOCKING  0x01
 
+struct async_call;
+
 typedef struct {
 	sysarg_t args[IPC_CALL_LEN];
 	task_id_t in_task_id;
 	sysarg_t in_phone_hash;
+	unsigned flags;
+	struct async_call *label;
 } ipc_call_t;
 
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision 0851a3ddbbf4ba5ef46cc8620a6dea43b2b1756a)
+++ uspace/lib/c/include/ipc/ipc.h	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -89,19 +89,18 @@
 
 #define ipc_call_async_0(phoneid, method, private, callback) \
-	ipc_call_async_fast((phoneid), (method), 0, 0, 0, 0, (private), \
-	    (callback))
+	ipc_call_async_fast((phoneid), (method), 0, 0, 0, (private), (callback))
 #define ipc_call_async_1(phoneid, method, arg1, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), 0, 0, 0, (private), \
+	ipc_call_async_fast((phoneid), (method), (arg1), 0, 0, (private), \
 	    (callback))
 #define ipc_call_async_2(phoneid, method, arg1, arg2, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
+	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), 0, \
 	    (private), (callback))
 #define ipc_call_async_3(phoneid, method, arg1, arg2, arg3, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, \
+	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), \
 	    (private), (callback))
 #define ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, private, \
     callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), (private), (callback))
+	ipc_call_async_slow((phoneid), (method), (arg1), (arg2), (arg3), \
+	    (arg4), 0, (private), (callback))
 #define ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, \
     private, callback) \
@@ -110,5 +109,5 @@
 
 extern void ipc_call_async_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, void *, ipc_async_callback_t);
+    void *, ipc_async_callback_t);
 extern void ipc_call_async_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, void *, ipc_async_callback_t);
