Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/Makefile	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -46,5 +46,4 @@
 	app/stats \
 	app/taskdump \
-	app/tasks \
 	app/tester \
 	app/tetris \
Index: uspace/app/stats/stats.c
===================================================================
--- uspace/app/stats/stats.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/app/stats/stats.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
  * All rights reserved.
  *
@@ -36,10 +37,16 @@
 
 #include <stdio.h>
+#include <task.h>
+#include <thread.h>
 #include <stats.h>
-#include <sys/time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <malloc.h>
 #include <inttypes.h>
-#include <malloc.h>
-
-#define NAME  "sysstat"
+#include <bool.h>
+#include <str.h>
+#include <arg_parse.h>
+
+#define NAME  "stats"
 
 #define DAY     86400
@@ -47,39 +54,260 @@
 #define MINUTE  60
 
-int main(int argc, char *argv[])
-{
-	struct timeval time;
-	if (gettimeofday(&time, NULL) != 0) {
-		fprintf(stderr, "%s: Cannot get time of day\n", NAME);
-		return -1;
-	}
-	
-	uint64_t sec = time.tv_sec;
-	printf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64,
-	    (sec % DAY) / HOUR, (sec % HOUR) / MINUTE, sec % MINUTE);
-	
+static void list_tasks(void)
+{
+	size_t count;
+	stats_task_t *stats_tasks = stats_get_tasks(&count);
+	
+	if (stats_tasks == NULL) {
+		fprintf(stderr, "%s: Unable to get tasks\n", NAME);
+		return;
+	}
+	
+	printf("[taskid] [thrds] [resident] [virtual] [ucycles]"
+	    " [kcycles] [name\n");
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		uint64_t resmem, virtmem, ucycles, kcycles;
+		char resmem_suffix, virtmem_suffix, usuffix, ksuffix;
+		
+		order_suffix(stats_tasks[i].resmem, &resmem, &resmem_suffix);
+		order_suffix(stats_tasks[i].virtmem, &virtmem, &virtmem_suffix);
+		order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
+		order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
+		
+		printf("%-8" PRIu64 " %7zu %9" PRIu64 "%c %8" PRIu64 "%c"
+		    " %8" PRIu64 "%c %8" PRIu64 "%c %s\n",
+		    stats_tasks[i].task_id, stats_tasks[i].threads,
+		    resmem, resmem_suffix, virtmem, virtmem_suffix,
+		    ucycles, usuffix, kcycles, ksuffix, stats_tasks[i].name);
+	}
+	
+	free(stats_tasks);
+}
+
+static void list_threads(task_id_t task_id, bool all)
+{
+	size_t count;
+	stats_thread_t *stats_threads = stats_get_threads(&count);
+	
+	if (stats_threads == NULL) {
+		fprintf(stderr, "%s: Unable to get threads\n", NAME);
+		return;
+	}
+	
+	printf("[taskid] [threadid] [state ] [prio] [cpu ] [ucycles] [kcycles]\n");
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if ((all) || (stats_threads[i].task_id == task_id)) {
+			uint64_t ucycles, kcycles;
+			char usuffix, ksuffix;
+			
+			order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
+			order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
+			
+			printf("%-8" PRIu64 " %-10" PRIu64 " %-8s %6d ",
+			    stats_threads[i].task_id, stats_threads[i].thread_id,
+			    thread_get_state(stats_threads[i].state),
+			    stats_threads[i].priority);
+			
+			if (stats_threads[i].on_cpu)
+				printf("%6u ", stats_threads[i].cpu);
+			else
+				printf("(none) ");
+			
+			printf("%8" PRIu64"%c %8" PRIu64"%c\n",
+			    ucycles, usuffix, kcycles, ksuffix);
+		}
+	}
+	
+	free(stats_threads);
+}
+
+static void list_cpus(void)
+{
+	size_t count;
+	stats_cpu_t *cpus = stats_get_cpus(&count);
+	
+	if (cpus == NULL) {
+		fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
+		return;
+	}
+	
+	printf("[id] [MHz     ] [busy cycles] [idle cycles]\n");
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		printf("%-4u ", cpus[i].id);
+		if (cpus[i].active) {
+			uint64_t bcycles, icycles;
+			char bsuffix, isuffix;
+			
+			order_suffix(cpus[i].busy_cycles, &bcycles, &bsuffix);
+			order_suffix(cpus[i].idle_cycles, &icycles, &isuffix);
+			
+			printf("%10" PRIu16 " %12" PRIu64 "%c %12" PRIu64 "%c\n",
+			    cpus[i].frequency_mhz, bcycles, bsuffix,
+			    icycles, isuffix);
+		} else
+			printf("inactive\n");
+	}
+	
+	free(cpus);
+}
+
+static void print_load(void)
+{
+	size_t count;
+	load_t *load = stats_get_load(&count);
+	
+	if (load == NULL) {
+		fprintf(stderr, "%s: Unable to get load\n", NAME);
+		return;
+	}
+	
+	printf("%s: Load average: ", NAME);
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (i > 0)
+			printf(" ");
+		
+		stats_print_load_fragment(load[i], 2);
+	}
+	
+	printf("\n");
+	
+	free(load);
+}
+
+static void print_uptime(void)
+{
 	sysarg_t uptime = stats_get_uptime();
-	printf(", up %" PRIun " days, %" PRIun " hours, "
-	    "%" PRIun " minutes, %" PRIun " seconds",
+	printf("%s: Up %" PRIun " days, %" PRIun " hours, "
+	    "%" PRIun " minutes, %" PRIun " seconds\n", NAME,
 	    uptime / DAY, (uptime % DAY) / HOUR,
 	    (uptime % HOUR) / MINUTE, uptime % MINUTE);
-	
-	size_t count;
-	load_t *load = stats_get_load(&count);
-	if (load != NULL) {
-		printf(", load average: ");
-		
-		size_t i;
-		for (i = 0; i < count; i++) {
-			if (i > 0)
-				printf(" ");
-			
-			stats_print_load_fragment(load[i], 2);
-		}
-		
-		free(load);
-	}
-	
-	printf("\n");
+}
+
+static void usage(const char *name)
+{
+	printf(
+	    "Usage: %s [-t task_id] [-a] [-c] [-l] [-u]\n" \
+	    "\n" \
+	    "Options:\n" \
+	    "\t-t task_id\n" \
+	    "\t--task=task_id\n" \
+	    "\t\tList threads of the given task\n" \
+	    "\n" \
+	    "\t-a\n" \
+	    "\t--all\n" \
+	    "\t\tList all threads\n" \
+	    "\n" \
+	    "\t-c\n" \
+	    "\t--cpus\n" \
+	    "\t\tList CPUs\n" \
+	    "\n" \
+	    "\t-l\n" \
+	    "\t--load\n" \
+	    "\t\tPrint system load\n" \
+	    "\n" \
+	    "\t-u\n" \
+	    "\t--uptime\n" \
+	    "\t\tPrint system uptime\n" \
+	    "\n" \
+	    "\t-h\n" \
+	    "\t--help\n" \
+	    "\t\tPrint this usage information\n"
+	    "\n" \
+	    "Without any options all tasks are listed\n",
+	    name
+	);
+}
+
+int main(int argc, char *argv[])
+{
+	bool toggle_tasks = true;
+	bool toggle_threads = false;
+	bool toggle_all = false;
+	bool toggle_cpus = false;
+	bool toggle_load = false;
+	bool toggle_uptime = false;
+	
+	task_id_t task_id = 0;
+	
+	int i;
+	for (i = 1; i < argc; i++) {
+		int off;
+		
+		/* Usage */
+		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
+			usage(argv[0]);
+			return 0;
+		}
+		
+		/* All threads */
+		if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
+			toggle_tasks = false;
+			toggle_threads = true;
+			toggle_all = true;
+			continue;
+		}
+		
+		/* CPUs */
+		if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
+			toggle_tasks = false;
+			toggle_cpus = true;
+			continue;
+		}
+		
+		/* Threads */
+		if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
+			// TODO: Support for 64b range
+			int tmp;
+			int ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			if (ret != EOK) {
+				printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
+				return -1;
+			}
+			
+			task_id = tmp;
+			
+			toggle_tasks = false;
+			toggle_threads = true;
+			continue;
+		}
+		
+		/* Load */
+		if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
+			toggle_tasks = false;
+			toggle_load = true;
+			continue;
+		}
+		
+		/* Uptime */
+		if ((off = arg_parse_short_long(argv[i], "-u", "--uptime")) != -1) {
+			toggle_tasks = false;
+			toggle_uptime = true;
+			continue;
+		}
+	}
+	
+	if (toggle_tasks)
+		list_tasks();
+	
+	if (toggle_threads)
+		list_threads(task_id, toggle_all);
+	
+	if (toggle_cpus)
+		list_cpus();
+	
+	if (toggle_load)
+		print_load();
+	
+	if (toggle_uptime)
+		print_uptime();
+	
 	return 0;
 }
Index: uspace/app/tasks/Makefile
===================================================================
--- uspace/app/tasks/Makefile	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ 	(revision )
@@ -1,36 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../..
-BINARY = tasks
-
-SOURCES = \
-	tasks.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tasks/tasks.c
===================================================================
--- uspace/app/tasks/tasks.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ 	(revision )
@@ -1,285 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * Copyright (c) 2010 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup tasks
- * @brief Task lister.
- * @{
- */
-/**
- * @file
- */
-
-#include <stdio.h>
-#include <task.h>
-#include <thread.h>
-#include <stats.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <inttypes.h>
-#include <bool.h>
-#include <str.h>
-#include <arg_parse.h>
-
-#define NAME  "tasks"
-
-#define TASK_COUNT    10
-#define THREAD_COUNT  50
-
-#define PRINT_LOAD1(x)  ((x) >> 11)
-#define PRINT_LOAD2(x)  (((x) & 0x7ff) / 2)
-
-static void list_tasks(void)
-{
-	size_t count;
-	stats_task_t *stats_tasks = stats_get_tasks(&count);
-	
-	if (stats_tasks == NULL) {
-		fprintf(stderr, "%s: Unable to get tasks\n", NAME);
-		return;
-	}
-	
-	printf(" Task ID  Threads      Mem       uCycles       kCycles   Name\n");
-	
-	size_t i;
-	for (i = 0; i < count; i++) {
-		uint64_t virtmem, ucycles, kcycles;
-		char vmsuffix, usuffix, ksuffix;
-		
-		order_suffix(stats_tasks[i].virtmem, &virtmem, &vmsuffix);
-		order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
-		order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
-		
-		printf("%8" PRIu64 "%8zu %8" PRIu64 "%c %12"
-		    PRIu64 "%c %12" PRIu64 "%c %s\n", stats_tasks[i].task_id,
-		    stats_tasks[i].threads, virtmem, vmsuffix, ucycles, usuffix,
-		    kcycles, ksuffix, stats_tasks[i].name);
-	}
-	
-	free(stats_tasks);
-}
-
-static void list_threads(task_id_t task_id, bool all)
-{
-	size_t count;
-	stats_thread_t *stats_threads = stats_get_threads(&count);
-	
-	if (stats_threads == NULL) {
-		fprintf(stderr, "%s: Unable to get threads\n", NAME);
-		return;
-	}
-	
-	printf(" ThrID    State  CPU   Prio    [k]uCycles    [k]kcycles   Cycle fault\n");
-	size_t i;
-	for (i = 0; i < count; i++) {
-		if ((all) || (stats_threads[i].task_id == task_id)) {
-			uint64_t ucycles, kcycles;
-			char usuffix, ksuffix;
-			
-			order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
-			order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
-			
-			if (stats_threads[i].on_cpu) {
-				printf("%8" PRIu64 " %-8s %4u %6d %12"
-				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
-				    thread_get_state(stats_threads[i].state),
-				    stats_threads[i].cpu, stats_threads[i].priority,
-				    ucycles, usuffix, kcycles, ksuffix);
-			} else {
-				printf("%8" PRIu64 " %-8s ---- %6d %12"
-				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
-				    thread_get_state(stats_threads[i].state),
-				    stats_threads[i].priority,
-				    ucycles, usuffix, kcycles, ksuffix);
-			}
-		}
-	}
-	
-	free(stats_threads);
-}
-
-static void print_load(void)
-{
-	size_t count;
-	load_t *load = stats_get_load(&count);
-	
-	if (load == NULL) {
-		fprintf(stderr, "%s: Unable to get load\n", NAME);
-		return;
-	}
-	
-	printf("%s: Load average: ", NAME);
-	
-	size_t i;
-	for (i = 0; i < count; i++) {
-		if (i > 0)
-			printf(" ");
-		
-		stats_print_load_fragment(load[i], 2);
-	}
-	
-	printf("\n");
-	
-	free(load);
-}
-
-static void list_cpus(void)
-{
-	size_t count;
-	stats_cpu_t *cpus = stats_get_cpus(&count);
-	
-	if (cpus == NULL) {
-		fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
-		return;
-	}
-	
-	printf("%s: %zu CPU(s) detected\n", NAME, count);
-	
-	size_t i;
-	for (i = 0; i < count; i++) {
-		if (cpus[i].active) {
-			printf("cpu%u: %" PRIu16 " MHz, busy cycles: "
-			    "%" PRIu64 ", idle cycles: %" PRIu64 "\n",
-			    cpus[i].id, cpus[i].frequency_mhz, cpus[i].busy_cycles,
-			    cpus[i].idle_cycles);
-		} else {
-			printf("cpu%u: inactive\n", cpus[i].id);
-		}
-	}
-	
-	free(cpus);
-}
-
-static void usage()
-{
-	printf(
-	    "Usage: tasks [-t task_id] [-a] [-l] [-c]\n" \
-	    "\n" \
-	    "Options:\n" \
-	    "\t-t task_id\n" \
-	    "\t--task=task_id\n" \
-	    "\t\tList threads of the given task\n" \
-	    "\n" \
-	    "\t-a\n" \
-	    "\t--all\n" \
-	    "\t\tList all threads\n" \
-	    "\n" \
-	    "\t-l\n" \
-	    "\t--load\n" \
-	    "\t\tPrint system load\n" \
-	    "\n" \
-	    "\t-c\n" \
-	    "\t--cpu\n" \
-	    "\t\tList CPUs\n" \
-	    "\n" \
-	    "\t-h\n" \
-	    "\t--help\n" \
-	    "\t\tPrint this usage information\n"
-	    "\n" \
-	    "Without any options all tasks are listed\n"
-	);
-}
-
-int main(int argc, char *argv[])
-{
-	bool toggle_tasks = true;
-	bool toggle_threads = false;
-	bool toggle_all = false;
-	bool toggle_load = false;
-	bool toggle_cpus = false;
-	
-	task_id_t task_id = 0;
-	
-	int i;
-	for (i = 1; i < argc; i++) {
-		int off;
-		
-		/* Usage */
-		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
-			usage();
-			return 0;
-		}
-		
-		/* All threads */
-		if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
-			toggle_tasks = false;
-			toggle_threads = true;
-			toggle_all = true;
-			continue;
-		}
-		
-		/* Load */
-		if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
-			toggle_tasks = false;
-			toggle_load = true;
-			continue;
-		}
-		
-		/* CPUs */
-		if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
-			toggle_tasks = false;
-			toggle_cpus = true;
-			continue;
-		}
-		
-		/* Threads */
-		if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
-			// TODO: Support for 64b range
-			int tmp;
-			int ret = arg_parse_int(argc, argv, &i, &tmp, off);
-			if (ret != EOK) {
-				printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
-				return -1;
-			}
-			
-			task_id = tmp;
-			
-			toggle_tasks = false;
-			toggle_threads = true;
-			continue;
-		}
-	}
-	
-	if (toggle_tasks)
-		list_tasks();
-	
-	if (toggle_threads)
-		list_threads(task_id, toggle_all);
-	
-	if (toggle_load)
-		print_load();
-	
-	if (toggle_cpus)
-		list_cpus();
-	
-	return 0;
-}
-
-/** @}
- */
Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/app/top/screen.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -274,5 +274,5 @@
 {
 	screen_style_inverted();
-	printf("[taskid] [threads] [resident] [%%resi] [virtual] [%%virt]"
+	printf("[taskid] [thrds] [resident] [%%resi] [virtual] [%%virt]"
 	    " [%%user] [%%kern] [name");
 	screen_newline();
@@ -303,5 +303,5 @@
 		order_suffix(task->virtmem, &virtmem, &virtmem_suffix);
 		
-		printf("%-8" PRIu64 " %9zu %9" PRIu64 "%c ",
+		printf("%-8" PRIu64 " %7zu %9" PRIu64 "%c ",
 		    task->task_id, task->threads, resmem, resmem_suffix);
 		print_percent(perc->resmem, 2);
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/async.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -134,4 +134,11 @@
 
 typedef struct {
+	sysarg_t in_task_hash;
+	link_t link;
+	int refcnt;
+	void *data;
+} client_t;
+
+typedef struct {
 	awaiter_t wdata;
 	
@@ -139,7 +146,12 @@
 	link_t link;
 	
+	/** Incoming client task hash. */
+	sysarg_t in_task_hash;
 	/** Incoming phone hash. */
 	sysarg_t in_phone_hash;
 	
+	/** Link to the client tracking structure. */
+	client_t *client;
+
 	/** Messages that should be delivered to this fibril. */
 	link_t msg_queue;
@@ -160,4 +172,35 @@
 fibril_local connection_t *FIBRIL_connection;
 
+static void *default_client_data_constructor(void)
+{
+	return NULL;
+}
+
+static void default_client_data_destructor(void *data)
+{
+}
+
+static async_client_data_ctor_t async_client_data_create =
+    default_client_data_constructor;
+static async_client_data_dtor_t async_client_data_destroy =
+    default_client_data_destructor;
+
+void async_set_client_data_constructor(async_client_data_ctor_t ctor)
+{
+	async_client_data_create = ctor;
+}
+
+void async_set_client_data_destructor(async_client_data_dtor_t dtor)
+{
+	async_client_data_destroy = dtor;
+}
+
+void *async_client_data_get(void)
+{
+	assert(FIBRIL_connection);
+
+	return FIBRIL_connection->client->data;
+}
+
 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
@@ -174,8 +217,33 @@
 static async_client_conn_t interrupt_received = default_interrupt_received;
 
+static hash_table_t client_hash_table;
 static hash_table_t conn_hash_table;
 static LIST_INITIALIZE(timeout_list);
 
-#define CONN_HASH_TABLE_CHAINS  32
+#define CLIENT_HASH_TABLE_BUCKETS	32
+#define CONN_HASH_TABLE_BUCKETS		32
+
+static hash_index_t client_hash(unsigned long *key)
+{
+	assert(key);
+	return (((*key) >> 4) % CLIENT_HASH_TABLE_BUCKETS); 
+}
+
+static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	client_t *cl = hash_table_get_instance(item, client_t, link);
+	return (key[0] == cl->in_task_hash);
+}
+
+static void client_remove(link_t *item)
+{
+}
+
+/** Operations for the client hash table. */
+static hash_table_operations_t client_hash_table_ops = {
+	.hash = client_hash,
+	.compare = client_compare,
+	.remove_callback = client_remove
+};
 
 /** Compute hash into the connection hash table based on the source phone hash.
@@ -189,5 +257,5 @@
 {
 	assert(key);
-	return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS);
+	return (((*key) >> 4) % CONN_HASH_TABLE_BUCKETS);
 }
 
@@ -480,19 +548,76 @@
 static int connection_fibril(void *arg)
 {
+	unsigned long key;
+	client_t *cl;
+	link_t *lnk;
+	bool destroy = false;
+
 	/*
-	 * Setup fibril-local connection pointer and call client_connection().
-	 *
+	 * Setup fibril-local connection pointer.
 	 */
 	FIBRIL_connection = (connection_t *) arg;
+
+	/*
+	 * Add our reference for the current connection in the client task
+	 * tracking structure. If this is the first reference, create and
+	 * hash in a new tracking structure.
+	 */
+	futex_down(&async_futex);
+	key = FIBRIL_connection->in_task_hash;
+	lnk = hash_table_find(&client_hash_table, &key);
+	if (lnk) {
+		cl = hash_table_get_instance(lnk, client_t, link);
+		cl->refcnt++;
+	} else {
+		cl = malloc(sizeof(client_t));
+		if (!cl) {
+			ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
+			futex_up(&async_futex);
+			return 0;
+		}
+		cl->in_task_hash = FIBRIL_connection->in_task_hash;
+		async_serialize_start();
+		cl->data = async_client_data_create();
+		async_serialize_end();
+		cl->refcnt = 1;
+		hash_table_insert(&client_hash_table, &key, &cl->link);
+	}
+	futex_up(&async_futex);
+
+	FIBRIL_connection->client = cl;
+
+	/*
+	 * Call the connection handler function.
+	 */
 	FIBRIL_connection->cfibril(FIBRIL_connection->callid,
 	    &FIBRIL_connection->call);
 	
-	/* Remove myself from the connection hash table */
+	/*
+	 * Remove the reference for this client task connection.
+	 */
 	futex_down(&async_futex);
-	unsigned long key = FIBRIL_connection->in_phone_hash;
+	if (--cl->refcnt == 0) {
+		hash_table_remove(&client_hash_table, &key, 1);
+		destroy = true;
+	}
+	futex_up(&async_futex);
+
+	if (destroy) {
+		if (cl->data)
+			async_client_data_destroy(cl->data);
+		free(cl);
+	}
+
+	/*
+	 * Remove myself from the connection hash table.
+	 */
+	futex_down(&async_futex);
+	key = FIBRIL_connection->in_phone_hash;
 	hash_table_remove(&conn_hash_table, &key, 1);
 	futex_up(&async_futex);
 	
-	/* Answer all remaining messages with EHANGUP */
+	/*
+	 * Answer all remaining messages with EHANGUP.
+	 */
 	while (!list_empty(&FIBRIL_connection->msg_queue)) {
 		msg_t *msg;
@@ -505,4 +630,8 @@
 	}
 	
+	/*
+	 * If the connection was hung-up, answer the last call,
+	 * i.e. IPC_M_PHONE_HUNGUP.
+	 */
 	if (FIBRIL_connection->close_callid)
 		ipc_answer_0(FIBRIL_connection->close_callid, EOK);
@@ -517,4 +646,5 @@
  * particular fibrils.
  *
+ * @param in_task_hash  Identification of the incoming connection.
  * @param in_phone_hash Identification of the incoming connection.
  * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
@@ -529,6 +659,7 @@
  *
  */
-fid_t async_new_connection(sysarg_t in_phone_hash, ipc_callid_t callid,
-    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
+fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
+    ipc_callid_t callid, ipc_call_t *call,
+    void (*cfibril)(ipc_callid_t, ipc_call_t *))
 {
 	connection_t *conn = malloc(sizeof(*conn));
@@ -539,4 +670,5 @@
 	}
 	
+	conn->in_task_hash = in_task_hash;
 	conn->in_phone_hash = in_phone_hash;
 	list_initialize(&conn->msg_queue);
@@ -592,6 +724,6 @@
 	case IPC_M_CONNECT_ME_TO:
 		/* Open new connection with fibril etc. */
-		async_new_connection(IPC_GET_ARG5(*call), callid, call,
-		    client_connection);
+		async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
+		    callid, call, client_connection);
 		goto out;
 	}
@@ -744,7 +876,7 @@
 int __async_init(void)
 {
-	if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
-	    &conn_hash_table_ops)) {
-		printf("%s: Cannot create async hash table\n", "libc");
+	if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
+	    &client_hash_table_ops) || !hash_table_create(&conn_hash_table,
+	    CONN_HASH_TABLE_BUCKETS, 1, &conn_hash_table_ops)) {
 		return ENOMEM;
 	}
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/devman.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -116,6 +116,5 @@
 	async_set_client_connection(conn);
 	
-	sysarg_t callback_phonehash;
-	ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
+	ipc_connect_to_me(phone, 0, 0, 0, NULL, NULL);
 	async_wait_for(req, &retval);
 	
Index: uspace/lib/c/generic/devmap.c
===================================================================
--- uspace/lib/c/generic/devmap.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/devmap.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -116,6 +116,5 @@
 	async_set_client_connection(conn);
 	
-	sysarg_t callback_phonehash;
-	ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
+	ipc_connect_to_me(phone, 0, 0, 0, NULL, NULL);
 	async_wait_for(req, &retval);
 	
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/ipc.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -578,5 +578,7 @@
  * @param arg2		Service-defined argument.
  * @param arg3		Service-defined argument.
- * @param phonehash	Storage where the library will store an opaque
+ * @param taskhash	Storage where the kernel will store an opaque
+ *			identifier of the client task.
+ * @param phonehash	Storage where the kernel will store an opaque
  *			identifier of the phone that will be used for incoming
  *			calls. This identifier can be used for connection
@@ -586,8 +588,8 @@
  */
 int ipc_connect_to_me(int phoneid, int arg1, int arg2, int arg3, 
-    sysarg_t *phonehash)
+    sysarg_t *taskhash, sysarg_t *phonehash)
 {
 	return ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2,
-	    arg3, NULL, NULL, NULL, NULL, phonehash);
+	    arg3, NULL, NULL, NULL, taskhash, phonehash);
 }
 
Index: uspace/lib/c/generic/net/modules.c
===================================================================
--- uspace/lib/c/generic/net/modules.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/net/modules.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -143,12 +143,15 @@
 	if (phone >= 0) {
 		/* Request the bidirectional connection */
+		sysarg_t taskhash;
 		sysarg_t phonehash;
 		
-		rc = ipc_connect_to_me(phone, arg1, arg2, arg3, &phonehash);
+		rc = ipc_connect_to_me(phone, arg1, arg2, arg3, &taskhash,
+		    &phonehash);
 		if (rc != EOK) {
 			ipc_hangup(phone);
 			return rc;
 		}
-		async_new_connection(phonehash, 0, NULL, client_receiver);
+		async_new_connection(taskhash, phonehash, 0, NULL,
+		    client_receiver);
 	}
 	
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -46,7 +46,7 @@
 #include <ipc/services.h>
 #include <async.h>
-#include <atomic.h>
-#include <futex.h>
+#include <fibril_synch.h>
 #include <errno.h>
+#include <assert.h>
 #include <str.h>
 #include <devmap.h>
@@ -54,7 +54,10 @@
 #include <ipc/devmap.h>
 
+static async_sess_t vfs_session;
+
+static FIBRIL_MUTEX_INITIALIZE(vfs_phone_mutex);
 static int vfs_phone = -1;
-static futex_t vfs_phone_futex = FUTEX_INITIALIZER;
-static futex_t cwd_futex = FUTEX_INITIALIZER;
+
+static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
 
 static int cwd_fd = -1;
@@ -67,14 +70,14 @@
 	char *ncwd_path_nc;
 
-	futex_down(&cwd_futex);
+	fibril_mutex_lock(&cwd_mutex);
 	size_t size = str_size(path);
 	if (*path != '/') {
 		if (!cwd_path) {
-			futex_up(&cwd_futex);
+			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
 		ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
 		if (!ncwd_path_nc) {
-			futex_up(&cwd_futex);
+			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
@@ -85,5 +88,5 @@
 		ncwd_path_nc = malloc(size + 1);
 		if (!ncwd_path_nc) {
-			futex_up(&cwd_futex);
+			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
@@ -93,5 +96,5 @@
 	ncwd_path = canonify(ncwd_path_nc, retlen);
 	if (!ncwd_path) {
-		futex_up(&cwd_futex);
+		fibril_mutex_unlock(&cwd_mutex);
 		free(ncwd_path_nc);
 		return NULL;
@@ -105,15 +108,43 @@
 	free(ncwd_path_nc);
 	if (!ncwd_path) {
-		futex_up(&cwd_futex);
+		fibril_mutex_unlock(&cwd_mutex);
 		return NULL;
 	}
-	futex_up(&cwd_futex);
+	fibril_mutex_unlock(&cwd_mutex);
 	return ncwd_path;
 }
 
+/** Connect to VFS service and create session. */
 static void vfs_connect(void)
 {
-	while (vfs_phone < 0)
-		vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0);
+	while (vfs_phone < 0) {
+		vfs_phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_VFS,
+		    0, 0);
+	}
+	
+	async_session_create(&vfs_session, vfs_phone, 0);
+}
+
+/** Start an async exchange on the VFS session.
+ *
+ * @return		New phone to be used during the exchange.
+ */
+static int vfs_exchange_begin(void)
+{
+	fibril_mutex_lock(&vfs_phone_mutex);
+	if (vfs_phone < 0)
+		vfs_connect();
+	fibril_mutex_unlock(&vfs_phone_mutex);
+
+	return async_exchange_begin(&vfs_session);
+}
+
+/** End an async exchange on the VFS session.
+ *
+ * @param phone		Phone used during the exchange.
+ */
+static void vfs_exchange_end(int phone)
+{
+	async_exchange_end(&vfs_session, phone);
 }
 
@@ -154,16 +185,13 @@
 	}
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
-	
+	int vfs_phone = vfs_exchange_begin();
+
 	sysarg_t rc_orig;
 	aid_t req = async_send_2(vfs_phone, VFS_IN_MOUNT, devmap_handle, flags, NULL);
 	sysarg_t rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(mpa);
+		async_wait_for(req, &rc_orig);
 		
 		if (null_id != -1)
@@ -178,8 +206,7 @@
 	rc = async_data_write_start(vfs_phone, (void *) opts, str_size(opts));
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(mpa);
+		async_wait_for(req, &rc_orig);
 		
 		if (null_id != -1)
@@ -194,8 +221,7 @@
 	rc = async_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(mpa);
+		async_wait_for(req, &rc_orig);
 		
 		if (null_id != -1)
@@ -211,8 +237,7 @@
 	rc = async_req_0_0(vfs_phone, IPC_M_PING);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(mpa);
+		async_wait_for(req, &rc_orig);
 		
 		if (null_id != -1)
@@ -225,8 +250,7 @@
 	}
 	
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	free(mpa);
+	async_wait_for(req, &rc);
 	
 	if ((rc != EOK) && (null_id != -1))
@@ -248,26 +272,22 @@
 		return ENOMEM;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_0(vfs_phone, VFS_IN_UNMOUNT, NULL);
 	rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(mpa);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	
+
+	vfs_exchange_end(vfs_phone);
 	free(mpa);
+	async_wait_for(req, &rc);
 	
 	return (int) rc;
@@ -276,7 +296,5 @@
 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
 {
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	ipc_call_t answer;
@@ -285,19 +303,17 @@
 	
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+
 		sysarg_t rc_orig;
 		async_wait_for(req, &rc_orig);
 		
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
-		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	
+	vfs_exchange_end(vfs_phone);
+	async_wait_for(req, &rc);
 	
 	if (rc != EOK)
@@ -322,7 +338,5 @@
 int open_node(fdi_node_t *node, int oflag)
 {
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	ipc_call_t answer;
@@ -330,8 +344,8 @@
 	    node->devmap_handle, node->index, oflag, &answer);
 	
-	sysarg_t rc;
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
+
+	sysarg_t rc;
+	async_wait_for(req, &rc);
 	
 	if (rc != EOK)
@@ -345,12 +359,9 @@
 	sysarg_t rc;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes);
 	
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	
 	return (int)rc;
@@ -363,16 +374,14 @@
 	aid_t req;
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
 	rc = async_data_read_start(vfs_phone, (void *)buf, nbyte);
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+
 		sysarg_t rc_orig;
-	
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+
 		if (rc_orig == EOK)
 			return (ssize_t) rc;
@@ -380,7 +389,6 @@
 			return (ssize_t) rc_orig;
 	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
+	async_wait_for(req, &rc);
 	if (rc == EOK)
 		return (ssize_t) IPC_GET_ARG1(answer);
@@ -395,16 +403,14 @@
 	aid_t req;
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
 	rc = async_data_write_start(vfs_phone, (void *)buf, nbyte);
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+
 		sysarg_t rc_orig;
-	
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+
 		if (rc_orig == EOK)
 			return (ssize_t) rc;
@@ -412,7 +418,6 @@
 			return (ssize_t) rc_orig;
 	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
+	async_wait_for(req, &rc);
 	if (rc == EOK)
 		return (ssize_t) IPC_GET_ARG1(answer);
@@ -423,12 +428,9 @@
 int fsync(int fildes)
 {
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	sysarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
 	
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	
 	return (int) rc;
@@ -437,7 +439,5 @@
 off64_t lseek(int fildes, off64_t offset, int whence)
 {
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	sysarg_t newoff_lo;
@@ -447,6 +447,5 @@
 	    &newoff_lo, &newoff_hi);
 	
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	
 	if (rc != EOK)
@@ -460,12 +459,9 @@
 	sysarg_t rc;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	rc = async_req_3_0(vfs_phone, VFS_IN_TRUNCATE, fildes,
 	    LOWER32(length), UPPER32(length));
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	
 	return (int) rc;
@@ -477,16 +473,14 @@
 	aid_t req;
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
 	rc = async_data_read_start(vfs_phone, (void *) stat, sizeof(struct stat));
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+
 		sysarg_t rc_orig;
-		
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+
 		if (rc_orig == EOK)
 			return (ssize_t) rc;
@@ -494,7 +488,6 @@
 			return (ssize_t) rc_orig;
 	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
+	async_wait_for(req, &rc);
 
 	return rc;
@@ -512,15 +505,12 @@
 		return ENOMEM;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
 	rc = async_data_write_start(vfs_phone, pa, pa_size);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(pa);
+		async_wait_for(req, &rc_orig);
 		if (rc_orig == EOK)
 			return (int) rc;
@@ -530,17 +520,15 @@
 	rc = async_data_read_start(vfs_phone, stat, sizeof(struct stat));
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(pa);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	vfs_exchange_end(vfs_phone);
 	free(pa);
+	async_wait_for(req, &rc);
 	return rc;
 }
@@ -601,26 +589,23 @@
 		return ENOMEM;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
 	rc = async_data_write_start(vfs_phone, pa, pa_size);
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+		free(pa);
+
 		sysarg_t rc_orig;
-	
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
-		free(pa);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	vfs_exchange_end(vfs_phone);
 	free(pa);
+	async_wait_for(req, &rc);
 	return rc;
 }
@@ -636,26 +621,23 @@
 		return ENOMEM;
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
 	rc = async_data_write_start(vfs_phone, pa, pa_size);
 	if (rc != EOK) {
+		vfs_exchange_end(vfs_phone);
+		free(pa);
+
 		sysarg_t rc_orig;
-
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
-		free(pa);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	vfs_exchange_end(vfs_phone);
 	free(pa);
+	async_wait_for(req, &rc);
 	return rc;
 }
@@ -689,16 +671,13 @@
 	}
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
 	rc = async_data_write_start(vfs_phone, olda, olda_size);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(olda);
 		free(newa);
+		async_wait_for(req, &rc_orig);
 		if (rc_orig == EOK)
 			return (int) rc;
@@ -708,19 +687,17 @@
 	rc = async_data_write_start(vfs_phone, newa, newa_size);
 	if (rc != EOK) {
-		async_wait_for(req, &rc_orig);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+		vfs_exchange_end(vfs_phone);
 		free(olda);
 		free(newa);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	async_wait_for(req, &rc);
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+		async_wait_for(req, &rc_orig);
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	vfs_exchange_end(vfs_phone);
 	free(olda);
 	free(newa);
+	async_wait_for(req, &rc);
 	return rc;
 }
@@ -740,5 +717,5 @@
 	}
 	
-	futex_down(&cwd_futex);
+	fibril_mutex_lock(&cwd_mutex);
 	
 	if (cwd_fd >= 0)
@@ -753,5 +730,5 @@
 	cwd_size = abs_size;
 	
-	futex_up(&cwd_futex);
+	fibril_mutex_unlock(&cwd_mutex);
 	return EOK;
 }
@@ -762,13 +739,13 @@
 		return NULL;
 	
-	futex_down(&cwd_futex);
+	fibril_mutex_lock(&cwd_mutex);
 	
 	if ((cwd_size == 0) || (size < cwd_size + 1)) {
-		futex_up(&cwd_futex);
+		fibril_mutex_unlock(&cwd_mutex);
 		return NULL;
 	}
 	
 	str_cpy(buf, size, cwd_path);
-	futex_up(&cwd_futex);
+	fibril_mutex_unlock(&cwd_mutex);
 	
 	return buf;
@@ -806,13 +783,10 @@
 int dup2(int oldfd, int newfd)
 {
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	vfs_connect();
+	int vfs_phone = vfs_exchange_begin();
 	
 	sysarg_t ret;
 	sysarg_t rc = async_req_2_1(vfs_phone, VFS_IN_DUP, oldfd, newfd, &ret);
 	
-	async_serialize_end();
-	futex_up(&vfs_phone_futex);
+	vfs_exchange_end(vfs_phone);
 	
 	if (rc == EOK)
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/include/async.h	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -44,5 +44,9 @@
 
 typedef ipc_callid_t aid_t;
-typedef void (*async_client_conn_t)(ipc_callid_t callid, ipc_call_t *call);
+
+typedef void *(*async_client_data_ctor_t)(void);
+typedef void (*async_client_data_dtor_t)(void *);
+
+typedef void (*async_client_conn_t)(ipc_callid_t, ipc_call_t *);
 
 extern atomic_t async_futex;
@@ -51,5 +55,5 @@
 
 extern int __async_init(void);
-extern ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs);
+extern ipc_callid_t async_get_call_timeout(ipc_call_t *, suseconds_t);
 
 static inline ipc_callid_t async_get_call(ipc_call_t *data)
@@ -85,21 +89,24 @@
 	    (arg5), (dataptr))
 
-extern aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr);
-extern aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
-    ipc_call_t *dataptr);
-extern void async_wait_for(aid_t amsgid, sysarg_t *result);
-extern int async_wait_timeout(aid_t amsgid, sysarg_t *retval,
-    suseconds_t timeout);
-
-extern fid_t async_new_connection(sysarg_t in_phone_hash, ipc_callid_t callid,
-    ipc_call_t *call, void (*cthread)(ipc_callid_t, ipc_call_t *));
-extern void async_usleep(suseconds_t timeout);
+extern aid_t async_send_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, ipc_call_t *);
+extern aid_t async_send_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, ipc_call_t *);
+extern void async_wait_for(aid_t, sysarg_t *);
+extern int async_wait_timeout(aid_t, sysarg_t *, suseconds_t);
+
+extern fid_t async_new_connection(sysarg_t, sysarg_t, ipc_callid_t,
+    ipc_call_t *, void (*)(ipc_callid_t, ipc_call_t *));
+extern void async_usleep(suseconds_t);
 extern void async_create_manager(void);
 extern void async_destroy_manager(void);
 
-extern void async_set_client_connection(async_client_conn_t conn);
-extern void async_set_interrupt_received(async_client_conn_t conn);
+extern void async_set_client_data_constructor(async_client_data_ctor_t);
+extern void async_set_client_data_destructor(async_client_data_dtor_t);
+
+extern void *async_client_data_get(void);
+
+extern void async_set_client_connection(async_client_conn_t);
+extern void async_set_interrupt_received(async_client_conn_t);
 
 /* Wrappers for simple communication */
@@ -243,10 +250,9 @@
 	    (arg5), (rc1), (rc2), (rc3), (rc4), (rc5))
 
-extern sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
-    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5);
-extern sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
-    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5);
+extern sysarg_t async_req_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *);
+extern sysarg_t async_req_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *,
+    sysarg_t *);
 
 static inline void async_serialize_start(void)
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/c/include/ipc/ipc.h	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -46,4 +46,5 @@
 typedef struct {
 	sysarg_t args[IPC_CALL_LEN];
+	sysarg_t in_task_hash;
 	sysarg_t in_phone_hash;
 } ipc_call_t;
@@ -258,5 +259,5 @@
     sysarg_t, sysarg_t, void *, ipc_async_callback_t, int);
 
-extern int ipc_connect_to_me(int, int, int, int, sysarg_t *);
+extern int ipc_connect_to_me(int, int, int, int, sysarg_t *, sysarg_t *);
 extern int ipc_connect_me_to(int, int, int, int);
 extern int ipc_connect_me_to_blocking(int, int, int, int);
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/fs/libfs.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -102,5 +102,6 @@
 	 * Ask VFS for callback connection.
 	 */
-	ipc_connect_to_me(vfs_phone, 0, 0, 0, &reg->vfs_phonehash);
+	sysarg_t taskhash;
+	ipc_connect_to_me(vfs_phone, 0, 0, 0, &taskhash, &reg->vfs_phonehash);
 	
 	/*
@@ -131,5 +132,5 @@
 	 * Create a connection fibril to handle the callback connection.
 	 */
-	async_new_connection(reg->vfs_phonehash, 0, NULL, conn);
+	async_new_connection(taskhash, reg->vfs_phonehash, 0, NULL, conn);
 	
 	/*
Index: uspace/lib/net/il/il_skel.c
===================================================================
--- uspace/lib/net/il/il_skel.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/net/il/il_skel.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -115,6 +115,5 @@
 		goto out;
 	
-	sysarg_t phonehash;
-	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, NULL, NULL);
 	if (rc != EOK)
 		goto out;
Index: uspace/lib/net/nil/nil_skel.c
===================================================================
--- uspace/lib/net/nil/nil_skel.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/net/nil/nil_skel.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -115,6 +115,5 @@
 		goto out;
 	
-	sysarg_t phonehash;
-	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, NULL, NULL);
 	if (rc != EOK)
 		goto out;
Index: uspace/lib/net/tl/tl_skel.c
===================================================================
--- uspace/lib/net/tl/tl_skel.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/net/tl/tl_skel.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -117,6 +117,5 @@
 		goto out;
 	
-	sysarg_t phonehash;
-	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, service, 0, 0, NULL, NULL);
 	if (rc != EOK)
 		goto out;
Index: uspace/lib/usbvirt/src/main.c
===================================================================
--- uspace/lib/usbvirt/src/main.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/lib/usbvirt/src/main.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -221,5 +221,6 @@
 	
 	sysarg_t phonehash;
-	rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
+	sysarg_t taskhash;
+	rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &taskhash, &phonehash);
 	if (rc != EOK) {
 		printf("ipc_connect_to_me() failed\n");
@@ -233,5 +234,5 @@
 	virtual_device->id = 0;
 	
-	async_new_connection(phonehash, 0, NULL, callback_connection);
+	async_new_connection(taskhash, phonehash, 0, NULL, callback_connection);
 	
 	return EOK;
Index: uspace/srv/clip/clip.c
===================================================================
--- uspace/srv/clip/clip.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/clip/clip.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -183,6 +183,5 @@
 	async_set_client_connection(clip_connection);
 	
-	sysarg_t phonead;
-	if (ipc_connect_to_me(PHONE_NS, SERVICE_CLIPBOARD, 0, 0, &phonead) != 0) 
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_CLIPBOARD, 0, 0, NULL, NULL)) 
 		return -1;
 	
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/devman/main.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -587,6 +587,5 @@
 
 	/* Register device manager at naming service. */
-	sysarg_t phonead;
-	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAN, 0, 0, &phonead) != 0)
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAN, 0, 0, NULL, NULL) != 0)
 		return -1;
 
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/devmap/devmap.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -1150,6 +1150,5 @@
 	
 	/* Register device mapper at naming service */
-	sysarg_t phonead;
-	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) 
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, NULL, NULL) != 0)
 		return -1;
 	
Index: uspace/srv/hid/adb_mouse/adb_dev.c
===================================================================
--- uspace/srv/hid/adb_mouse/adb_dev.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/adb_mouse/adb_dev.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -68,11 +68,12 @@
 
 	/* NB: The callback connection is slotted for removal */
+	sysarg_t taskhash;
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &phonehash) != 0) {
+	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &taskhash, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return false;
 	}
 
-	async_new_connection(phonehash, 0, NULL, adb_dev_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, adb_dev_events);
 
 	return 0;
Index: uspace/srv/hid/char_mouse/chardev.c
===================================================================
--- uspace/srv/hid/char_mouse/chardev.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/char_mouse/chardev.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -70,11 +70,12 @@
 
 	/* NB: The callback connection is slotted for removal */
+	sysarg_t taskhash;
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &phonehash) != 0) {
+	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &taskhash, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return false;
 	}
 
-	async_new_connection(phonehash, 0, NULL, chardev_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, chardev_events);
 
 	return 0;
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/console/console.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -727,6 +727,7 @@
 	/* NB: The callback connection is slotted for removal */
 	sysarg_t phonehash;
+	sysarg_t taskhash;
 	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
-	    0, 0, NULL, NULL, NULL, NULL, &phonehash);
+	    0, 0, NULL, NULL, NULL, &taskhash, &phonehash);
 	if (rc != EOK) {
 		printf(NAME ": Failed to create callback from input device\n");
@@ -734,5 +735,5 @@
 	}
 	
-	async_new_connection(phonehash, 0, NULL, keyboard_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, keyboard_events);
 
 	printf(NAME ": we got a hit (new keyboard \"%s\").\n", path);
@@ -784,6 +785,7 @@
 	/* NB: The callback connection is slotted for removal */
 	sysarg_t phonehash;
+	sysarg_t taskhash;
 	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
-	    0, 0, NULL, NULL, NULL, NULL, &phonehash);
+	    0, 0, NULL, NULL, NULL, &taskhash, &phonehash);
 	if (rc != EOK) {
 		printf(NAME ": Failed to create callback from input device\n");
@@ -791,5 +793,5 @@
 	}
 
-	async_new_connection(phonehash, 0, NULL, keyboard_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, keyboard_events);
 
 	printf(NAME ": we got a hit (new keyboard \"/dev/%s\").\n",
@@ -862,6 +864,8 @@
 	}
 	
+	sysarg_t taskhash;
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
+	if (ipc_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, &taskhash,
+	    &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from mouse device\n");
 		mouse_phone = -1;
@@ -869,5 +873,5 @@
 	}
 	
-	async_new_connection(phonehash, 0, NULL, mouse_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, mouse_events);
 skip_mouse:
 	
Index: uspace/srv/hid/fb/main.c
===================================================================
--- uspace/srv/hid/fb/main.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/fb/main.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -114,6 +114,5 @@
 		return -1;
 	
-	sysarg_t phonead;
-	if (ipc_connect_to_me(PHONE_NS, SERVICE_VIDEO, 0, 0, &phonead) != 0) 
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_VIDEO, 0, 0, NULL, NULL) != 0)
 		return -1;
 	
Index: uspace/srv/hid/kbd/port/adb.c
===================================================================
--- uspace/srv/hid/kbd/port/adb.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/kbd/port/adb.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -71,11 +71,12 @@
 
 	/* NB: The callback connection is slotted for removal */
+	sysarg_t taskhash;
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &phonehash) != 0) {
+	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &taskhash, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return false;
 	}
 
-	async_new_connection(phonehash, 0, NULL, kbd_port_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, kbd_port_events);
 
 	return 0;
Index: uspace/srv/hid/kbd/port/chardev.c
===================================================================
--- uspace/srv/hid/kbd/port/chardev.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hid/kbd/port/chardev.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -91,11 +91,12 @@
 
 	/* NB: The callback connection is slotted for removal */
+	sysarg_t taskhash;
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &phonehash) != 0) {
+	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &taskhash, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return -1;
 	}
 
-	async_new_connection(phonehash, 0, NULL, kbd_port_events);
+	async_new_connection(taskhash, phonehash, 0, NULL, kbd_port_events);
 
 	return 0;
Index: uspace/srv/hw/irc/apic/apic.c
===================================================================
--- uspace/srv/hw/irc/apic/apic.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hw/irc/apic/apic.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -108,6 +108,5 @@
 	
 	async_set_client_connection(apic_connection);
-	sysarg_t phonead;
-	ipc_connect_to_me(PHONE_NS, SERVICE_APIC, 0, 0, &phonead);
+	ipc_connect_to_me(PHONE_NS, SERVICE_APIC, 0, 0, NULL, NULL);
 	
 	return true;
Index: uspace/srv/hw/irc/fhc/fhc.c
===================================================================
--- uspace/srv/hw/irc/fhc/fhc.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hw/irc/fhc/fhc.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -137,6 +137,5 @@
 	
 	async_set_client_connection(fhc_connection);
-	sysarg_t phonead;
-	ipc_connect_to_me(PHONE_NS, SERVICE_FHC, 0, 0, &phonead);
+	ipc_connect_to_me(PHONE_NS, SERVICE_FHC, 0, 0, NULL, NULL);
 	
 	return true;
Index: uspace/srv/hw/irc/i8259/i8259.c
===================================================================
--- uspace/srv/hw/irc/i8259/i8259.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hw/irc/i8259/i8259.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -150,6 +150,5 @@
 	
 	async_set_client_connection(i8259_connection);
-	sysarg_t phonead;
-	ipc_connect_to_me(PHONE_NS, SERVICE_I8259, 0, 0, &phonead);
+	ipc_connect_to_me(PHONE_NS, SERVICE_I8259, 0, 0, NULL, NULL);
 	
 	return true;
Index: uspace/srv/hw/irc/obio/obio.c
===================================================================
--- uspace/srv/hw/irc/obio/obio.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hw/irc/obio/obio.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -138,6 +138,5 @@
 	
 	async_set_client_connection(obio_connection);
-	sysarg_t phonead;
-	ipc_connect_to_me(PHONE_NS, SERVICE_OBIO, 0, 0, &phonead);
+	ipc_connect_to_me(PHONE_NS, SERVICE_OBIO, 0, 0, NULL, NULL);
 	
 	return true;
Index: uspace/srv/hw/netif/ne2000/ne2000.c
===================================================================
--- uspace/srv/hw/netif/ne2000/ne2000.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/hw/netif/ne2000/ne2000.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -397,6 +397,5 @@
 	async_set_interrupt_received(irq_handler);
 	
-	sysarg_t phonehash;
-	return ipc_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, &phonehash);
+	return ipc_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, NULL, NULL);
 }
 
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/loader/main.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -423,5 +423,4 @@
 int main(int argc, char *argv[])
 {
-	sysarg_t phonead;
 	task_id_t id;
 	int rc;
@@ -439,5 +438,5 @@
 	
 	/* Register at naming service. */
-	if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) 
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, NULL, NULL) != 0)
 		return -2;
 
Index: uspace/srv/net/net/net.c
===================================================================
--- uspace/srv/net/net/net.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/net/net/net.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -326,5 +326,4 @@
 static int net_module_start(async_client_conn_t client_connection)
 {
-	sysarg_t phonehash;
 	int rc;
 	
@@ -338,5 +337,5 @@
 		goto out;
 	
-	rc = ipc_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, NULL, NULL);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/netif/lo/lo.c
===================================================================
--- uspace/srv/net/netif/lo/lo.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/net/netif/lo/lo.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -167,6 +167,5 @@
 int netif_initialize(void)
 {
-	sysarg_t phonehash;
-	return ipc_connect_to_me(PHONE_NS, SERVICE_LO, 0, 0, &phonehash);
+	return ipc_connect_to_me(PHONE_NS, SERVICE_LO, 0, 0, NULL, NULL);
 }
 
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/vfs/vfs.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -59,14 +59,4 @@
 	ipc_answer_0(iid, EOK);
 	
-	/*
-	 * Here we enter the main connection fibril loop.
-	 * The logic behind this loop and the protocol is that we'd like to keep
-	 * each connection open until the client hangs up. When the client hangs
-	 * up, we will free its VFS state. The act of hanging up the connection
-	 * by the client is equivalent to client termination because we cannot
-	 * distinguish one from the other. On the other hand, the client can
-	 * hang up arbitrarily if it has no open files and reestablish the
-	 * connection later.
-	 */
 	while (keep_on_going) {
 		ipc_call_t call;
@@ -133,6 +123,9 @@
 		}
 	}
-	
-	vfs_files_done();
+
+	/*
+	 * Open files for this client will be cleaned up when its last
+	 * connection fibril terminates.
+	 */
 }
 
@@ -166,4 +159,10 @@
 	
 	/*
+	 * Set client data constructor and destructor.
+	 */
+	async_set_client_data_constructor(vfs_client_data_create);
+	async_set_client_data_destructor(vfs_client_data_destroy);
+
+	/*
 	 * Set a connection handling function/fibril.
 	 */
@@ -173,6 +172,5 @@
 	 * Register at the naming service.
 	 */
-	sysarg_t phonead;
-	ipc_connect_to_me(PHONE_NS, SERVICE_VFS, 0, 0, &phonead);
+	ipc_connect_to_me(PHONE_NS, SERVICE_VFS, 0, 0, NULL, NULL);
 	
 	/*
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/vfs/vfs.h	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -188,13 +188,12 @@
 #define MAX_OPEN_FILES	128
 
-extern bool vfs_files_init(void);
-extern void vfs_files_done(void);
+extern void *vfs_client_data_create(void);
+extern void vfs_client_data_destroy(void *);
+
 extern vfs_file_t *vfs_file_get(int);
-extern int vfs_fd_assign(vfs_file_t *file, int fd);
+extern void vfs_file_put(vfs_file_t *);
+extern int vfs_fd_assign(vfs_file_t *, int);
 extern int vfs_fd_alloc(bool desc);
 extern int vfs_fd_free(int);
-
-extern void vfs_file_addref(vfs_file_t *);
-extern void vfs_file_delref(vfs_file_t *);
 
 extern void vfs_node_addref(vfs_node_t *);
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/vfs/vfs_file.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -45,50 +45,98 @@
 #include "vfs.h"
 
-/**
- * This is a per-connection table of open files.
- * Our assumption is that each client opens only one connection and therefore
- * there is one table of open files per task. However, this may not be the case
- * and the client can open more connections to VFS. In that case, there will be
- * several tables and several file handle name spaces per task. Besides of this,
- * the functionality will stay unchanged. So unless the client knows what it is
- * doing, it should open one connection to VFS only.
- *
- * Allocation of the open files table is deferred until the client makes the
- * first VFS_OPEN operation.
- *
- * This resource being per-connection and, in the first place, per-fibril, we
- * don't need to protect it by a mutex.
- */
-fibril_local vfs_file_t **files = NULL;
+#define VFS_DATA	((vfs_client_data_t *) async_client_data_get())
+#define FILES		(VFS_DATA->files)
+
+typedef struct {
+	fibril_mutex_t lock;
+	vfs_file_t **files;
+} vfs_client_data_t;
 
 /** Initialize the table of open files. */
-bool vfs_files_init(void)
-{
-	if (!files) {
-		files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
-		if (!files)
+static bool vfs_files_init(void)
+{
+	fibril_mutex_lock(&VFS_DATA->lock);
+	if (!FILES) {
+		FILES = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		if (!FILES) {
+			fibril_mutex_unlock(&VFS_DATA->lock);
 			return false;
-		memset(files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
-	}
+		}
+		memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
+	}
+	fibril_mutex_unlock(&VFS_DATA->lock);
 	return true;
 }
 
 /** Cleanup the table of open files. */
-void vfs_files_done(void)
+static void vfs_files_done(void)
 {
 	int i;
 
-	if (!files)
+	if (!FILES)
 		return;
 
 	for (i = 0; i < MAX_OPEN_FILES; i++) {
-		if (files[i]) {
-			(void) vfs_close_internal(files[i]);
+		if (FILES[i]) {
+			(void) vfs_close_internal(FILES[i]);
 			(void) vfs_fd_free(i);
 		}
 	}
 	
-	free(files);
-}
+	free(FILES);
+}
+
+void *vfs_client_data_create(void)
+{
+	vfs_client_data_t *vfs_data;
+
+	vfs_data = malloc(sizeof(vfs_client_data_t));
+	if (vfs_data) {
+		fibril_mutex_initialize(&vfs_data->lock);
+		vfs_data->files = NULL;
+	}
+	
+	return vfs_data;
+}
+
+void vfs_client_data_destroy(void *data)
+{
+	vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
+
+	vfs_files_done();
+	free(vfs_data);
+}
+
+/** Increment reference count of VFS file structure.
+ *
+ * @param file		File structure that will have reference count
+ *			incremented.
+ */
+static void vfs_file_addref(vfs_file_t *file)
+{
+	assert(fibril_mutex_is_locked(&VFS_DATA->lock));
+
+	file->refcnt++;
+}
+
+/** Decrement reference count of VFS file structure.
+ *
+ * @param file		File structure that will have reference count
+ *			decremented.
+ */
+static void vfs_file_delref(vfs_file_t *file)
+{
+	assert(fibril_mutex_is_locked(&VFS_DATA->lock));
+
+	if (file->refcnt-- == 1) {
+		/*
+		 * Lost the last reference to a file, need to drop our reference
+		 * to the underlying VFS node.
+		 */
+		vfs_node_delref(file->node);
+		free(file);
+	}
+}
+
 
 /** Allocate a file descriptor.
@@ -111,13 +159,17 @@
 		i = 0;
 	
+	fibril_mutex_lock(&VFS_DATA->lock);
 	while (true) {
-		if (!files[i]) {
-			files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
-			if (!files[i])
+		if (!FILES[i]) {
+			FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
+			if (!FILES[i]) {
+				fibril_mutex_unlock(&VFS_DATA->lock);
 				return ENOMEM;
+			}
 			
-			memset(files[i], 0, sizeof(vfs_file_t));
-			fibril_mutex_initialize(&files[i]->lock);
-			vfs_file_addref(files[i]);
+			memset(FILES[i], 0, sizeof(vfs_file_t));
+			fibril_mutex_initialize(&FILES[i]->lock);
+			vfs_file_addref(FILES[i]);
+			fibril_mutex_unlock(&VFS_DATA->lock);
 			return (int) i;
 		}
@@ -135,4 +187,5 @@
 		}
 	}
+	fibril_mutex_unlock(&VFS_DATA->lock);
 	
 	return EMFILE;
@@ -150,10 +203,14 @@
 	if (!vfs_files_init())
 		return ENOMEM;
-	
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] == NULL))
+
+	fibril_mutex_lock(&VFS_DATA->lock);	
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
+		fibril_mutex_unlock(&VFS_DATA->lock);
 		return EBADF;
-	
-	vfs_file_delref(files[fd]);
-	files[fd] = NULL;
+	}
+	
+	vfs_file_delref(FILES[fd]);
+	FILES[fd] = NULL;
+	fibril_mutex_unlock(&VFS_DATA->lock);
 	
 	return EOK;
@@ -173,46 +230,18 @@
 	if (!vfs_files_init())
 		return ENOMEM;
-	
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] != NULL))
+
+	fibril_mutex_lock(&VFS_DATA->lock);	
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
+		fibril_mutex_unlock(&VFS_DATA->lock);
 		return EINVAL;
-	
-	files[fd] = file;
-	vfs_file_addref(files[fd]);
+	}
+	
+	FILES[fd] = file;
+	vfs_file_addref(FILES[fd]);
+	fibril_mutex_unlock(&VFS_DATA->lock);
 	
 	return EOK;
 }
 
-/** Increment reference count of VFS file structure.
- *
- * @param file		File structure that will have reference count
- *			incremented.
- */
-void vfs_file_addref(vfs_file_t *file)
-{
-	/*
-	 * File structures are per-connection, so no-one, except the current
-	 * fibril, should have a reference to them. This is the reason we don't
-	 * do any synchronization here.
-	 */
-	file->refcnt++;
-}
-
-/** Decrement reference count of VFS file structure.
- *
- * @param file		File structure that will have reference count
- *			decremented.
- */
-void vfs_file_delref(vfs_file_t *file)
-{
-	if (file->refcnt-- == 1) {
-		/*
-		 * Lost the last reference to a file, need to drop our reference
-		 * to the underlying VFS node.
-		 */
-		vfs_node_delref(file->node);
-		free(file);
-	}
-}
-
 /** Find VFS file structure for a given file descriptor.
  *
@@ -226,8 +255,25 @@
 		return NULL;
 	
-	if ((fd >= 0) && (fd < MAX_OPEN_FILES))
-		return files[fd];
+	fibril_mutex_lock(&VFS_DATA->lock);
+	if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
+		vfs_file_t *file = FILES[fd];
+		vfs_file_addref(file);
+		fibril_mutex_unlock(&VFS_DATA->lock);
+		return file;
+	}
+	fibril_mutex_unlock(&VFS_DATA->lock);
 	
 	return NULL;
+}
+
+/** Stop using a file structure.
+ *
+ * @param file		VFS file structure.
+ */
+void vfs_file_put(vfs_file_t *file)
+{
+	fibril_mutex_lock(&VFS_DATA->lock);
+	vfs_file_delref(file);
+	fibril_mutex_unlock(&VFS_DATA->lock);
 }
 
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision ef8d6558c58526391170f038efdfc4dfa25d034f)
+++ uspace/srv/vfs/vfs_ops.c	(revision 2b9646335943ad9872daddeaffee9b749d2830c1)
@@ -491,9 +491,4 @@
 void vfs_open(ipc_callid_t rid, ipc_call_t *request)
 {
-	if (!vfs_files_init()) {
-		ipc_answer_0(rid, ENOMEM);
-		return;
-	}
-	
 	/*
 	 * The POSIX interface is open(path, oflag, mode).
@@ -609,4 +604,5 @@
 	vfs_node_addref(node);
 	vfs_node_put(node);
+	vfs_file_put(file);
 	
 	/* Success! Return the new file descriptor to the client. */
@@ -617,9 +613,4 @@
 {
 	// FIXME: check for sanity of the supplied fs, dev and index
-	
-	if (!vfs_files_init()) {
-		ipc_answer_0(rid, ENOMEM);
-		return;
-	}
 	
 	/*
@@ -686,4 +677,5 @@
 	vfs_node_addref(node);
 	vfs_node_put(node);
+	vfs_file_put(file);
 	
 	/* Success! Return the new file descriptor to the client. */
@@ -721,5 +713,6 @@
 	vfs_release_phone(file->node->fs_handle, fs_phone);
 	fibril_mutex_unlock(&file->lock);
-	
+
+	vfs_file_put(file);
 	ipc_answer_0(rid, rc);
 }
@@ -775,4 +768,5 @@
 		ipc_answer_0(rid, ret);
 	
+	vfs_file_put(file);
 	ret = vfs_fd_free(fd);
 	ipc_answer_0(rid, ret);
@@ -875,5 +869,6 @@
 		file->pos += bytes;
 	fibril_mutex_unlock(&file->lock);
-	
+	vfs_file_put(file);	
+
 	/*
 	 * FS server's reply is the final result of the whole operation we
@@ -915,4 +910,5 @@
 			file->pos = (aoff64_t) off;
 			fibril_mutex_unlock(&file->lock);
+			vfs_file_put(file);
 			ipc_answer_1(rid, EOK, off);
 			return;
@@ -922,4 +918,5 @@
 		if ((off >= 0) && (file->pos + off < file->pos)) {
 			fibril_mutex_unlock(&file->lock);
+			vfs_file_put(file);
 			ipc_answer_0(rid, EOVERFLOW);
 			return;
@@ -928,4 +925,5 @@
 		if ((off < 0) && (file->pos < (aoff64_t) -off)) {
 			fibril_mutex_unlock(&file->lock);
+			vfs_file_put(file);
 			ipc_answer_0(rid, EOVERFLOW);
 			return;
@@ -936,4 +934,5 @@
 		
 		fibril_mutex_unlock(&file->lock);
+		vfs_file_put(file);
 		ipc_answer_2(rid, EOK, LOWER32(newoff),
 		    UPPER32(newoff));
@@ -946,4 +945,5 @@
 			fibril_rwlock_read_unlock(&file->node->contents_rwlock);
 			fibril_mutex_unlock(&file->lock);
+			vfs_file_put(file);
 			ipc_answer_0(rid, EOVERFLOW);
 			return;
@@ -953,4 +953,5 @@
 			fibril_rwlock_read_unlock(&file->node->contents_rwlock);
 			fibril_mutex_unlock(&file->lock);
+			vfs_file_put(file);
 			ipc_answer_0(rid, EOVERFLOW);
 			return;
@@ -962,4 +963,5 @@
 		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
 		fibril_mutex_unlock(&file->lock);
+		vfs_file_put(file);
 		ipc_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
 		return;
@@ -967,4 +969,5 @@
 	
 	fibril_mutex_unlock(&file->lock);
+	vfs_file_put(file);
 	ipc_answer_0(rid, EINVAL);
 }
@@ -1005,4 +1008,5 @@
 
 	fibril_mutex_unlock(&file->lock);
+	vfs_file_put(file);
 	ipc_answer_0(rid, (sysarg_t)rc);
 }
@@ -1021,4 +1025,5 @@
 	ipc_callid_t callid;
 	if (!async_data_read_receive(&callid, NULL)) {
+		vfs_file_put(file);
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1038,4 +1043,5 @@
 
 	fibril_mutex_unlock(&file->lock);
+	vfs_file_put(file);
 	ipc_answer_0(rid, rc);
 }
@@ -1339,14 +1345,14 @@
 	int newfd = IPC_GET_ARG2(*request);
 	
+	/* If the file descriptors are the same, do nothing. */
+	if (oldfd == newfd) {
+		ipc_answer_1(rid, EOK, newfd);
+		return;
+	}
+	
 	/* Lookup the file structure corresponding to oldfd. */
 	vfs_file_t *oldfile = vfs_file_get(oldfd);
 	if (!oldfile) {
 		ipc_answer_0(rid, EBADF);
-		return;
-	}
-	
-	/* If the file descriptors are the same, do nothing. */
-	if (oldfd == newfd) {
-		ipc_answer_1(rid, EOK, newfd);
 		return;
 	}
@@ -1365,4 +1371,6 @@
 		if (ret != EOK) {
 			fibril_mutex_unlock(&oldfile->lock);
+			vfs_file_put(oldfile);
+			vfs_file_put(newfile);
 			ipc_answer_0(rid, ret);
 			return;
@@ -1372,7 +1380,10 @@
 		if (ret != EOK) {
 			fibril_mutex_unlock(&oldfile->lock);
+			vfs_file_put(oldfile);
+			vfs_file_put(newfile);
 			ipc_answer_0(rid, ret);
 			return;
 		}
+		vfs_file_put(newfile);
 	}
 	
@@ -1380,4 +1391,5 @@
 	int ret = vfs_fd_assign(oldfile, newfd);
 	fibril_mutex_unlock(&oldfile->lock);
+	vfs_file_put(oldfile);
 	
 	if (ret != EOK)
