Index: abi/include/abi/ipc/methods.h
===================================================================
--- abi/include/abi/ipc/methods.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ abi/include/abi/ipc/methods.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -38,7 +38,4 @@
 #include <abi/cap.h>
 
-/* Well known phone descriptors */
-static cap_phone_handle_t const PHONE_INITIAL = (cap_phone_handle_t) (CAP_NIL + 1);
-
 /** Kernel IPC interfaces
  *
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ boot/Makefile.common	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -68,14 +68,25 @@
 INITRD = initrd
 
-# NOTE: Naming service must be first task in the list
+# NOTE: Order of tasks here is important since kernel connects initial phone of
+# all these tasks to answerbox of the first one in this list (its phone is left
+# untouched).
+# INIT_TASKS = \
+# 	$(USPACE_PATH)/srv/taskman/taskman \
+# 	$(USPACE_PATH)/srv/ns/ns \
+# 	$(USPACE_PATH)/srv/locsrv/locsrv \
+# 	$(USPACE_PATH)/srv/vfs/vfs \
+# 	$(USPACE_PATH)/srv/loader/loader \
+# 	$(USPACE_PATH)/srv/bd/rd/rd
+
 INIT_TASKS = \
+	$(USPACE_PATH)/srv/taskman/taskman \
 	$(USPACE_PATH)/srv/ns/ns \
+	$(USPACE_PATH)/srv/locsrv/locsrv \
+	$(USPACE_PATH)/srv/vfs/vfs \
+	$(USPACE_PATH)/srv/sysman/sysman \
 	$(USPACE_PATH)/srv/loader/loader \
-	$(USPACE_PATH)/srv/sysman/sysman \
-	$(USPACE_PATH)/srv/locsrv/locsrv \
-	$(USPACE_PATH)/srv/bd/rd/rd \
-	$(USPACE_PATH)/srv/vfs/vfs \
 	$(USPACE_PATH)/srv/logger/logger \
-	$(USPACE_PATH)/srv/taskman/taskman
+ 	$(USPACE_PATH)/srv/bd/rd/rd
+
 
 ifeq ($(RDFMT),tmpfs)
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ kernel/generic/src/main/kinit.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -211,4 +211,10 @@
 	}
 
+	/*
+	 * Initialize and prepare init tasks for start.
+	 *
+	 * All tasks' phone no 0 is connected to answerbox of the first of the
+	 * init tasks (except for the first task itself).
+	 */
 	for (i = 0; i < init.cnt; i++) {
 		if (init.tasks[i].paddr % FRAME_SIZE) {
Index: uspace/app/tester/proc/task_wait.c
===================================================================
--- uspace/app/tester/proc/task_wait.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/app/tester/proc/task_wait.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -73,5 +73,5 @@
 	rc = task_wait(&wait, &texit, &retval);
 	TPRINTF("done.\n");
-	TASSERT(rc == EINVAL);
+	TASSERT(rc == EINTR);
 	TASSERT(task_wait_get(&wait) == 0);
 	TPRINTF("OK\n");
@@ -215,5 +215,5 @@
 	rc = task_wait(&wait, &texit, &retval);
 	TPRINTF("done.\n");
-	TASSERT(rc == EINVAL);
+	TASSERT(rc == EINTR);
 	TASSERT(task_wait_get(&wait) == 0);
 	TASSERT(texit == TASK_EXIT_UNEXPECTED);
Index: uspace/lib/c/generic/async/client.c
===================================================================
--- uspace/lib/c/generic/async/client.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/async/client.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -124,7 +124,4 @@
 static fibril_rmutex_t message_mutex;
 
-/** Primary session (spawn parent, later naming service) */
-async_sess_t *session_primary = NULL;
-
 /** Message data */
 typedef struct {
@@ -169,16 +166,21 @@
 
 
-static async_sess_t *create_session_primary(void)
+/** Create session for existing phone
+ *
+ * @return session on success, NULL on error
+ */
+ 
+async_sess_t *create_session(cap_phone_handle_t phone, exch_mgmt_t mgmt,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
 {
 	async_sess_t *session = (async_sess_t *) malloc(sizeof(async_sess_t));
 
 	if (session != NULL) {
-		// TODO extract common part with async_connect_me_to
-		session_ns->iface = 0;
-		session->mgmt = EXCHANGE_ATOMIC;
-		session->phone = PHONE_INITIAL;
-		session->arg1 = 0;
-		session->arg2 = 0;
-		session->arg3 = 0;
+		session->iface = 0;
+		session->mgmt = mgmt;
+		session->phone = phone;
+		session->arg1 = arg1;
+		session->arg2 = arg2;
+		session->arg3 = arg3;
 		
 		fibril_mutex_initialize(&session->remote_state_mtx);
@@ -189,4 +191,6 @@
 		atomic_set(&session->refcnt, 0);
 		&session.exchanges = 0;
+	} else {
+		errno = ENOMEM;
 	}
 
@@ -196,19 +200,9 @@
 
 /** Initialize the async framework.
- * @param arg_session_primary Primary session (to naming service).
- *
- */
-void __async_client_init(async_sess_t *arg_session_primary)
+ *
+ */
+void __async_client_init(void)
 {
 	if (fibril_rmutex_initialize(&message_mutex) != EOK)
-		abort();
-
-	if (arg_session_primary == NULL) {
-		session_primary = create_session_primary();
-	} else {
-		session_primary = arg_session_primary;
-	}
-
-	if (session_primary == NULL)
 		abort();
 }
@@ -832,19 +826,4 @@
 }
 
-/** Injects another session instead of original primary session
- *
- * @param  session  Session to naming service.
- *
- * @return old primary session (to spawn parent)
- */
-async_sess_t *async_session_primary_swap(async_sess_t *session)
-{
-	assert(session_primary->phone == PHONE_INITIAL);
-
-	async_sess_t *old_primary = session_primary;
-	session_primary = session;
-	return old_primary;
-}
-
 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
  *
@@ -865,10 +844,4 @@
 	if (exch == NULL) {
 		errno = ENOENT;
-		return NULL;
-	}
-
-	async_sess_t *sess = calloc(1, sizeof(async_sess_t));
-	if (sess == NULL) {
-		errno = ENOMEM;
 		return NULL;
 	}
@@ -879,17 +852,11 @@
 	if (rc != EOK) {
 		errno = rc;
-		free(sess);
 		return NULL;
 	}
 
-	sess->iface = iface;
-	sess->phone = phone;
-	sess->arg1 = iface;
-	sess->arg2 = arg2;
-	sess->arg3 = arg3;
-
-	fibril_mutex_initialize(&sess->remote_state_mtx);
-	list_initialize(&sess->exch_list);
-	fibril_mutex_initialize(&sess->mutex);
+	async_sess_t *sess = create_session(phone, mgmt, iface, arg2, arg3);
+	if (sess == NULL) {
+		ipc_hangup(phone);
+	}
 
 	return sess;
@@ -933,10 +900,4 @@
 	if (exch == NULL) {
 		errno = ENOENT;
-		return NULL;
-	}
-
-	async_sess_t *sess = calloc(1, sizeof(async_sess_t));
-	if (sess == NULL) {
-		errno = ENOMEM;
 		return NULL;
 	}
@@ -951,13 +912,8 @@
 	}
 
-	sess->iface = iface;
-	sess->phone = phone;
-	sess->arg1 = iface;
-	sess->arg2 = arg2;
-	sess->arg3 = arg3;
-
-	fibril_mutex_initialize(&sess->remote_state_mtx);
-	list_initialize(&sess->exch_list);
-	fibril_mutex_initialize(&sess->mutex);
+	async_sess_t *sess = create_session(phone, mgmt, iface, arg2, arg3);
+	if (sess == NULL) {
+		ipc_hangup(phone);
+	}
 
 	return sess;
@@ -969,25 +925,15 @@
 async_sess_t *async_connect_kbox(task_id_t id)
 {
-	async_sess_t *sess = calloc(1, sizeof(async_sess_t));
-	if (sess == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-
 	cap_phone_handle_t phone;
 	errno_t rc = ipc_connect_kbox(id, &phone);
 	if (rc != EOK) {
 		errno = rc;
-		free(sess);
 		return NULL;
 	}
 
-	sess->iface = 0;
-	sess->mgmt = EXCHANGE_ATOMIC;
-	sess->phone = phone;
-
-	fibril_mutex_initialize(&sess->remote_state_mtx);
-	list_initialize(&sess->exch_list);
-	fibril_mutex_initialize(&sess->mutex);
+	async_sess_t *sess = create_session(phone, EXCHANGE_ATOMIC, 0, 0, 0);
+	if (sess == NULL) {
+		ipc_hangup(phone);
+	}
 
 	return sess;
Index: uspace/lib/c/generic/async/server.c
===================================================================
--- uspace/lib/c/generic/async/server.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/async/server.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -391,8 +391,9 @@
  *                    calls routed through that phone.
  * @param in_task_id  Identification of the incoming connection.
- * @param call        Call data of the opening call. If call is NULL, the
- *                    connection was opened by accepting the
- *                    IPC_M_CONNECT_TO_ME call and this function is called
- *                    directly by the server.
+ * @param call        Call data of the opening call. If call is NULL, it's
+ *                    either a callback connection that was opened by
+ *                    accepting the IPC_M_CONNECT_TO_ME call.
+ *                    Alternatively, it is zero when we are opening
+ *                    implicit connection.
  * @param handler     Connection handler.
  * @param data        Client argument to pass to the connection handler.
@@ -1746,20 +1747,12 @@
 	}
 
-	async_sess_t *sess = calloc(1, sizeof(async_sess_t));
+	async_sess_t *sess = create_session(phandle, mgmt, 0, 0, 0);
 	if (sess == NULL) {
-		async_answer_0(&call, ENOMEM);
-		return NULL;
-	}
-
-	sess->iface = 0;
-	sess->mgmt = mgmt;
-	sess->phone = phandle;
-
-	fibril_mutex_initialize(&sess->remote_state_mtx);
-	list_initialize(&sess->exch_list);
-	fibril_mutex_initialize(&sess->mutex);
-
-	/* Acknowledge the connected phone */
-	async_answer_0(&call, EOK);
+		ipc_hangup(phone);
+		async_answer_0(&call, errno);
+	} else {
+		/* Acknowledge the connected phone */
+		async_answer_0(&call, EOK);
+	}
 
 	return sess;
@@ -1788,17 +1781,5 @@
 		return NULL;
 
-	async_sess_t *sess = calloc(1, sizeof(async_sess_t));
-	if (sess == NULL)
-		return NULL;
-
-	sess->iface = 0;
-	sess->mgmt = mgmt;
-	sess->phone = phandle;
-
-	fibril_mutex_initialize(&sess->remote_state_mtx);
-	list_initialize(&sess->exch_list);
-	fibril_mutex_initialize(&sess->mutex);
-
-	return sess;
+	return create_session(phandle, mgmt, 0, 0, 0);
 }
 
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/libc.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -51,6 +51,6 @@
 #include "private/fibril.h"
 #include "private/malloc.h"
-#include "private/ns.h" // TODO maybe better filename for session_primary
 #include "private/task.h"
+#include "private/taskman.h"
 
 
@@ -63,4 +63,17 @@
 static bool env_setup;
 static fibril_t main_fibril;
+
+static void initialize_taskman(pcb_t *pcb)
+{
+	if (__pcb == NULL) {
+		async_sess_t *session_tm = taskman_connect();
+		if (session_tm == NULL) {
+			abort();
+		}
+		__task_init(session_tm);
+	} else {
+		__task_init(__pcb->session_taskman);
+	}
+}
 
 void __libc_main(void *pcb_ptr)
@@ -107,14 +120,9 @@
 #endif
 	
-	/* Setup async framework */
+	/* Setup async framework and taskman connection */
 	__async_server_init();
-	if (__pcb == NULL) {
-		__async_client_init(NULL);
-		__task_init(NULL);
-	} else {
-		__async_client_init(__pcb->session_primary);
-		__task_init(__pcb->session_taskman);
-	}
+	__async_client_init();
 	__async_ports_init();
+	initialize_taskman(__pcb);
 
 	/* The basic run-time environment is setup */
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/loader.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -45,5 +45,7 @@
 #include <task.h>
 #include <vfs/vfs.h>
+
 #include "private/loader.h"
+#include "private/taskman.h"
 
 /** Connect to a new program loader.
@@ -66,7 +68,6 @@
 	if (ldr == NULL)
 		return NULL;
-
-	async_sess_t *sess =
-	    service_connect_blocking(SERVICE_TASKMAN, TASKMAN_CONNECT_TO_LOADER, 0);
+	
+	async_sess_t *sess = taskman_session_loader();
 	if (sess == NULL) {
 		free(ldr);
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/ns.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -38,5 +38,24 @@
 #include <macros.h>
 #include <errno.h>
-#include "private/ns.h"
+
+#include "private/taskman.h"
+
+static async_sess_t *session_ns = NULL;
+
+static async_exch_t *ns_exchange_begin(void)
+{
+	/* Lazily connect to our NS */
+	if (session_ns == NULL) {
+		session_ns = taskman_session_ns();
+	}
+
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	return exch;
+}
+
+static void ns_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
+}
 
 /*
@@ -49,8 +68,4 @@
     async_port_handler_t handler, void *data)
 {
-	async_sess_t *sess = get_session_primary();
-	if (sess == NULL)
-		return EIO;
-
 	port_id_t port;
 	errno_t rc = async_create_port(iface, handler, data, &port);
@@ -58,5 +73,5 @@
 		return rc;
 
-	async_exch_t *exch = async_exchange_begin(sess);
+	async_exch_t *exch = ns_exchange_begin();
 
 	ipc_call_t answer;
@@ -64,5 +79,5 @@
 	rc = async_connect_to_me(exch, iface, service, 0);
 
-	async_exchange_end(exch);
+	ns_exchange_end(exch);
 
 	if (rc != EOK) {
@@ -105,17 +120,13 @@
 async_sess_t *service_connect(service_t service, iface_t iface, sysarg_t arg3)
 {
-	async_sess_t *sess = get_session_primary();
-	if (sess == NULL)
-		return NULL;
-
-	async_exch_t *exch = async_exchange_begin(sess);
+	async_exch_t *exch = ns_exchange_begin();
 	if (exch == NULL)
 		return NULL;
 
-	async_sess_t *csess =
+	async_sess_t *sess =
 	    async_connect_me_to(exch, iface, service, arg3);
-	async_exchange_end(exch);
+	ns_exchange_end(exch);
 
-	if (csess == NULL)
+	if (sess == NULL)
 		return NULL;
 
@@ -125,5 +136,5 @@
 	 * first argument for non-initial connections.
 	 */
-	async_sess_args_set(csess, iface, arg3, 0);
+	async_sess_args_set(sess, iface, arg3, 0);
 
 	return csess;
@@ -133,14 +144,10 @@
     sysarg_t arg3)
 {
-	async_sess_t *sess = get_session_primary();
+	async_exch_t *exch = ns_exchange_begin();
+	async_sess_t *sess =
+	    async_connect_me_to_blocking(exch, iface, service, arg3);
+	ns_exchange_end(exch);
+
 	if (sess == NULL)
-		return NULL;
-
-	async_exch_t *exch = async_exchange_begin(sess);
-	async_sess_t *csess =
-	    async_connect_me_to_blocking(exch, iface, service, arg3);
-	async_exchange_end(exch);
-
-	if (csess == NULL)
 		return NULL;
 
@@ -150,38 +157,18 @@
 	 * first argument for non-initial connections.
 	 */
-	async_sess_args_set(csess, iface, arg3, 0);
+	async_sess_args_set(sess, iface, arg3, 0);
 
-	return csess;
+	return sess;
 }
 
 errno_t ns_ping(void)
 {
-	async_sess_t *sess = get_session_primary();
-	if (sess == NULL)
-		return EIO;
-
-	async_exch_t *exch = async_exchange_begin(sess);
+	async_exch_t *exch = ns_exchange_begin(sess);
 	errno_t rc = async_req_0_0(exch, NS_PING);
-	async_exchange_end(exch);
+	ns_exchange_end(exch);
 
 	return rc;
 }
 
-
-async_sess_t *get_session_primary(void)
-{
-	async_exch_t *exch;
-
-	if (sess_primary == NULL) {
-		exch = async_exchange_begin(&session_primary);
-		sess_primary = async_connect_me_to(exch, 0, 0, 0);
-		async_exchange_end(exch);
-		if (sess_primary == NULL)
-			return NULL;
-	}
-
-	return sess_primary;
-}
-
 /** @}
  */
Index: uspace/lib/c/generic/private/async.h
===================================================================
--- uspace/lib/c/generic/private/async.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/private/async.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -96,5 +96,5 @@
 extern void __async_server_init(void);
 extern void __async_server_fini(void);
-extern void __async_client_init(async_sess_t *);
+extern void __async_client_init(void);
 extern void __async_client_fini(void);
 extern void __async_ports_init(void);
@@ -106,4 +106,6 @@
 
 extern void async_reply_received(ipc_call_t *);
+extern async_sess_t *create_session(int, exch_mgmt_t,
+	sysarg_t, sysarg_t, sysarg_t);
 
 #endif
Index: pace/lib/c/generic/private/ns.h
===================================================================
--- uspace/lib/c/generic/private/ns.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2011 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 libc
- * @{
- */
-/** @file
- */
-
-#ifndef _LIBC_PRIVATE_NS_H_
-#define _LIBC_PRIVATE_NS_H_
-
-#include <async.h>
-
-extern async_sess_t *session_primary;
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/generic/private/task.h
===================================================================
--- uspace/lib/c/generic/private/task.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/private/task.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -36,13 +36,5 @@
 #define LIBC_PRIVATE_TASK_H_
 
-#include <async.h>
-
-void __task_init(async_sess_t *);
-
 int task_retval_internal(int, bool);
-
-async_exch_t *taskman_exchange_begin(void);
-
-void taskman_exchange_end(async_exch_t *);
 
 #endif
Index: uspace/lib/c/generic/private/taskman.h
===================================================================
--- uspace/lib/c/generic/private/taskman.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
+++ uspace/lib/c/generic/private/taskman.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Michal Koutny
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_PRIVATE_TASKMAN_H_
+#define LIBC_PRIVATE_TASKMAN_H_
+
+#include <async.h>
+
+extern async_sess_t *session_taskman;
+
+void __task_init(async_sess_t *);
+
+async_exch_t *taskman_exchange_begin(void);
+void taskman_exchange_end(async_exch_t *);
+
+extern async_sess_t *taskman_connect(void);
+extern async_sess_t *taskman_session_ns(void);
+extern async_sess_t *taskman_session_loader(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/task.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -49,9 +49,9 @@
 #include <str.h>
 #include <task.h>
+#include <taskman.h>
 #include <vfs/vfs.h>
-#include "private/ns.h"
+
 #include "private/task.h"
-
-static async_sess_t *session_taskman = NULL;
+#include "private/taskman.h"
 
 task_id_t task_get_id(void)
@@ -69,28 +69,4 @@
 }
 
-async_exch_t *taskman_exchange_begin(void)
-{
-	/* Lazy connection */
-	if (session_taskman == NULL) {
-		// TODO unify exchange mgmt with taskman_handshake/__init
-		session_taskman = service_connect_blocking(EXCHANGE_SERIALIZE,
-		    SERVICE_TASKMAN,
-		    TASKMAN_CONTROL,
-		    0);
-	}
-
-	if (session_taskman == NULL) {
-		return NULL;
-	}
-
-	async_exch_t *exch = async_exchange_begin(session_taskman);
-	return exch;
-}
-
-void taskman_exchange_end(async_exch_t *exch)
-{
-	async_exchange_end(exch);
-}
-
 /** Set the task name.
  *
@@ -129,5 +105,4 @@
  *
  * @return EOK on success, else error code.
- * @return TODO check this doesn't return EINVAL -- clash with task_wait
  */
 static errno_t task_setup_wait(task_id_t id, task_wait_t *wait)
@@ -393,10 +368,13 @@
  * (it can be reused, but must be reinitialized with task_setup_wait first)
  *
- * @param wait   task_wait_t previously initialized by task_setup_wait.
- * @param texit  Store type of task exit here.
- * @param retval Store return value of the task here.
+ * @param[in/out] wait   task_wait_t previously initialized by task_setup_wait
+ *                       or returned by task_wait with non-zero flags. the
+ *                       flags are updated so that they represent what can be
+ *                       still waited for.
+ * @param[out]    texit  Store type of task exit here.
+ * @param[out]    retval Store return value of the task here.
  *
  * @return EOK on success
- * @return EINVAL on lost wait TODO other error codes
+ * @return EINTR on lost wait
  */
 errno_t task_wait(task_wait_t *wait, task_exit_t *texit, int *retval)
@@ -405,5 +383,5 @@
 	async_wait_for(wait->aid, &rc);
 
-	if (rc == EOK || rc == EINVAL) {
+	if (rc == EOK || rc == EINTR) {
 		if (wait->flags & TASK_WAIT_EXIT && texit)
 			*texit = ipc_get_arg1(wait->result);
@@ -471,10 +449,4 @@
 }
 
-void __task_init(async_sess_t *sess)
-{
-	assert(session_taskman == NULL);
-	session_taskman = sess;
-}
-
 /** @}
  */
Index: uspace/lib/c/generic/task_event.c
===================================================================
--- uspace/lib/c/generic/task_event.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/task_event.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -38,5 +38,5 @@
 #include <task.h>
 
-#include "private/task.h"
+#include "private/taskman.h"
 
 static task_event_handler_t task_event_handler = NULL;
@@ -65,5 +65,5 @@
 
 		if (!IPC_GET_IMETHOD(call)) {
-			/* Hangup, TODO explain or handle differntly */
+			/* Hangup, end of game */
 			break;
 		}
Index: uspace/lib/c/generic/taskman.c
===================================================================
--- uspace/lib/c/generic/taskman.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/generic/taskman.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -33,16 +33,99 @@
  */
 
+
+#include <async.h>
 #include <errno.h>
+#include <ipc/common.h>
 #include <ipc/taskman.h>
+#include <task.h>
 #include <taskman.h>
 
-#include <stdio.h>
+#include "private/async.h"
+#include "private/taskman.h"
 
-//TODO better filename?
-#include "private/ns.h"
+async_sess_t *session_taskman = NULL;
 
-static int taskman_ask_callback(async_sess_t *session_tm)
+void __task_init(async_sess_t *sess)
 {
-	async_exch_t *exch = async_exchange_begin(session_tm);
+	assert(session_taskman == NULL);
+	session_taskman = sess;
+}
+
+async_exch_t *taskman_exchange_begin(void)
+{
+	assert(session_taskman);
+
+	async_exch_t *exch = async_exchange_begin(session_taskman);
+	return exch;
+}
+
+void taskman_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
+}
+
+/** Wrap PHONE_INITIAL with session and introduce to taskman
+ */
+async_sess_t *taskman_connect(void)
+{
+	/*
+	 *  EXCHANGE_ATOMIC would require single calls only,
+	 *  EXCHANGE_PARALLEL not sure about implementation via multiple phones,
+	 * >EXCHANGE_SERIALIZE perhaphs no harm, except the client serialization
+	 */
+	const exch_mgmt_t mgmt = EXCHANGE_SERIALIZE;
+	async_sess_t *sess = create_session(PHONE_INITIAL, mgmt, 0, 0, 0);
+
+	if (sess != NULL) {
+		/* Introduce ourselves and ignore answer */
+		async_exch_t *exch = async_exchange_begin(sess);
+		aid_t req = async_send_0(exch, TASKMAN_NEW_TASK, NULL);
+		async_exchange_end(exch);
+		
+		if (req) {
+			async_forget(req);
+		}
+	}
+
+	return sess;
+}
+
+/** Ask taskman to pass/share its NS */
+async_sess_t *taskman_session_ns(void)
+{
+	assert(session_taskman);
+
+	async_exch_t *exch = async_exchange_begin(session_taskman);
+	assert(exch);
+
+	async_sess_t *sess = async_connect_me_to(EXCHANGE_ATOMIC,
+	    exch, TASKMAN_CONNECT_TO_NS, 0, 0);
+	async_exchange_end(exch);
+
+	return sess;
+}
+
+/** Ask taskman to connect to (a new) loader instance */
+async_sess_t *taskman_session_loader(void)
+{
+	assert(session_taskman);
+
+	async_exch_t *exch = async_exchange_begin(session_taskman);
+	async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE,
+	    exch, TASKMAN_CONNECT_TO_LOADER, 0, 0);
+	async_exchange_end(exch);
+
+	return sess;
+}
+
+/** Introduce as loader to taskman
+ *
+ * @return EOK on success, otherwise propagated error code
+ */
+int taskman_intro_loader(void)
+{
+	assert(session_taskman);
+
+	async_exch_t *exch = async_exchange_begin(session_taskman);
 	int rc = async_connect_to_me(
 	    exch, TASKMAN_LOADER_CALLBACK, 0, 0, NULL, NULL);
@@ -52,38 +135,33 @@
 }
 
-static async_sess_t *taskman_connect_to_ns(async_sess_t *session_tm)
+/** Tell taskman we are his NS
+ *
+ * @return EOK on success, otherwise propagated error code
+ */
+int taskman_intro_ns(void)
 {
-	async_exch_t *exch = async_exchange_begin(session_tm);
-	async_sess_t *session_ns = async_connect_me_to(EXCHANGE_ATOMIC,
-	    exch, TASKMAN_LOADER_TO_NS, 0, 0);
-	async_exchange_end(exch);
+	assert(session_taskman);
 
-	return session_ns;
+	async_exch_t *exch = async_exchange_begin(session_taskman);
+	aid_t req = async_send_0(exch, TASKMAN_I_AM_NS, NULL);
+
+	int rc = async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
+	taskman_exchange_end(exch);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	return retval;
 }
 
-/** Set up phones upon being spawned by taskman
- *
- * Assumes primary session exists that is connected to taskman.
- * After handshake, taskman is connected to us (see, it's opposite) and broker
- * session is set up according to taskman.
- *
- *
- * @return Session to broker (naming service) or NULL (sets errno).
- */
-async_sess_t *taskman_handshake(void)
+async_sess_t *taskman_get_session(void)
 {
-	int rc = taskman_ask_callback(session_primary);
-	if (rc != EOK) {
-		errno = rc;
-		return NULL;
-	}
+	return session_taskman;
+}
 
-	async_sess_t *session_ns = taskman_connect_to_ns(session_primary);
-	if (session_ns == NULL) {
-		errno = ENOENT;
-	}
 
-	return session_ns;
-}
 
 /** @}
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/async.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -276,5 +276,4 @@
 extern sysarg_t async_get_label(void);
 
-extern async_sess_t *async_session_primary_swap(async_sess_t *);
 extern async_sess_t *async_connect_me_to(async_exch_t *, iface_t, sysarg_t,
     sysarg_t);
Index: uspace/lib/c/include/ipc/common.h
===================================================================
--- uspace/lib/c/include/ipc/common.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/ipc/common.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -39,4 +39,7 @@
 #include <abi/ipc/ipc.h>
 
+/* Well known phone descriptors */
+#define PHONE_INITIAL  0
+
 #define IPC_FLAG_BLOCKING   0x01
 // TODO autostart flag may be united with blocking, this should be later made
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/ipc/services.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -46,5 +46,4 @@
 	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
 	SERVICE_SYSMAN     = FOURCC('s', 'y', 's', 'm'),
-	SERVICE_TASKMAN    = FOURCC('t', 's', 'k', 'm'),
 	SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
Index: uspace/lib/c/include/ipc/taskman.h
===================================================================
--- uspace/lib/c/include/ipc/taskman.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/ipc/taskman.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -42,5 +42,7 @@
 	TASKMAN_WAIT = IPC_FIRST_USER_METHOD,
 	TASKMAN_RETVAL,
-	TASKMAN_EVENT_CALLBACK
+	TASKMAN_EVENT_CALLBACK,
+	TASKMAN_NEW_TASK,
+	TASKMAN_I_AM_NS
 } taskman_request_t;
 
@@ -50,9 +52,8 @@
 
 typedef enum {
-	TASKMAN_CONNECT_TO_LOADER = 0,
-	TASKMAN_LOADER_TO_NS,
-	TASKMAN_LOADER_CALLBACK,
-	TASKMAN_CONTROL
-} taskman_interface_t;
+	TASKMAN_CONNECT_TO_NS = 0,
+	TASKMAN_CONNECT_TO_LOADER,
+	TASKMAN_LOADER_CALLBACK
+} taskman_connect_t;
 
 #endif
Index: uspace/lib/c/include/loader/pcb.h
===================================================================
--- uspace/lib/c/include/loader/pcb.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/loader/pcb.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -61,7 +61,4 @@
 	entry_point_t entry;
 
-	/** Primary session to broker. */
-	async_sess_t *session_primary;
-	
 	/** Session to taskman (typically spawn parent) */
 	async_sess_t *session_taskman;
Index: uspace/lib/c/include/ns.h
===================================================================
--- uspace/lib/c/include/ns.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/ns.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -49,4 +49,6 @@
 extern async_sess_t *ns_session_get(void);
 
+extern async_sess_t *ns_get_session(void);
+
 #endif
 
Index: uspace/lib/c/include/task.h
===================================================================
--- uspace/lib/c/include/task.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/task.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -76,5 +76,5 @@
 extern errno_t task_retval(int);
 
-/* Implemented in task_event.h */
+/* Implemented in task_event.c */
 extern int task_register_event_handler(task_event_handler_t);
 
Index: uspace/lib/c/include/taskman.h
===================================================================
--- uspace/lib/c/include/taskman.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/lib/c/include/taskman.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -36,7 +36,16 @@
 #define LIBC_TASKMAN_H_
 
+#ifndef TASKMAN_DISABLE_ASYNC
 #include <async.h>
+#endif
 
-extern async_sess_t *taskman_handshake(void);
+/* Internal functions to be used by loader only */
+#ifndef TASKMAN_DISABLE_ASYNC
+extern async_sess_t *taskman_get_session(void);
+#endif
+extern int taskman_intro_loader(void);
+
+/* Internal functions to be used by NS only */
+extern int taskman_intro_ns(void);
 
 #endif
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/loader/main.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -35,5 +35,5 @@
  * The program loader is a special init binary. Its image is used
  * to create a new task upon a @c task_spawn syscall. It has a phone connected
- * to the caller of te syscall. The formal caller (taskman) performs a
+ * to the caller of the syscall. The formal caller (taskman) performs a
  * handshake with loader so that apparent caller can communicate with the
  * loader.
@@ -60,6 +60,8 @@
 #include <ipc/loader.h>
 #include <loader/pcb.h>
+#include <ns.h>
 #include <str.h>
 #include <sys/types.h>
+#include <task.h>
 #include <taskman.h>
 #include <unistd.h>
@@ -72,4 +74,5 @@
 #endif
 
+#define NAME "loader"
 #define DPRINTF(...) ((void) 0)
 
@@ -80,10 +83,4 @@
 /** The Program control block */
 static pcb_t pcb;
-
-/** Primary IPC session */
-static async_sess_t *session_primary = NULL;
-
-/** Session to taskman (typically our spawner) */
-static async_sess_t *session_taskman = NULL;
 
 /** Current working directory */
@@ -105,9 +102,4 @@
 /** Used to limit number of connections to one. */
 static bool connected = false;
-
-/** Ensure synchronization of handshake and connection fibrils. */
-static bool handshake_complete = false;
-FIBRIL_MUTEX_INITIALIZE(handshake_mtx);
-FIBRIL_CONDVAR_INITIALIZE(handshake_cv);
 
 static void ldr_get_taskid(ipc_call_t *req)
@@ -337,6 +329,5 @@
 	DPRINTF("PCB set.\n");
 
-	pcb.session_primary = session_primary;
-	pcb.session_taskman = session_taskman;
+	pcb.session_taskman = taskman_get_session();
 
 	pcb.cwd = cwd;
@@ -394,11 +385,4 @@
 static void ldr_connection(ipc_call_t *icall, void *arg)
 {
-	/* Wait for handshake */
-	fibril_mutex_lock(&handshake_mtx);
-	while (!handshake_complete) {
-		fibril_condvar_wait(&handshake_cv, &handshake_mtx);
-	}
-	fibril_mutex_unlock(&handshake_mtx);
-
 	/* Already have a connection? */
 	if (connected) {
@@ -456,37 +440,4 @@
 }
 
-/** Handshake with taskman
- *
- * Taskman is our spawn parent, i.e. PHONE_INITIAL is connected to it.
- * Goal of the handshake is to obtain phone to naming service and also keep the
- * session to taskman.
- *
- * @return EOK on success, for errors see taskman_handshake()
- */
-static errno_t ldr_taskman_handshake(void)
-{
-	assert(session_primary == NULL);
-	assert(session_taskman == NULL);
-
-	errno_t retval = EOK;
-
-	fibril_mutex_lock(&handshake_mtx);
-	session_primary = taskman_handshake();
-	if (session_primary == NULL) {
-		retval = errno;
-		goto finish;
-	}
-
-	session_taskman = async_session_primary_swap(session_primary);
-
-	handshake_complete = true;
-
-finish:
-	fibril_condvar_signal(&handshake_cv);
-	fibril_mutex_unlock(&handshake_mtx);
-
-	return retval;
-}
-
 /** Program loader main function.
  */
@@ -496,14 +447,17 @@
 	async_set_fallback_port_handler(ldr_connection, NULL);
 	
-	/* Handshake with taskman */
-	int rc = ldr_taskman_handshake();
-	if (rc != EOK) {
-		DPRINTF("Failed taskman handshake (%i).\n", errno);
+	/* Announce to taskman. */
+	errno_t rc = taskman_intro_loader();
+	if (rc != EOK) {
+		printf("%s: did not receive connectin from taskman (%i)\n",
+		    NAME, rc);
 		return rc;
 	}
 
-	/* Handle client connections */
+	/*
+	 * We are not a regular server, thus no retval is set, just wait for
+	 * forwarded connections by taskman.
+	 */
 	async_manager();
-	//TODO retval?
 	
 	/* Never reached */
Index: uspace/srv/ns/ns.c
===================================================================
--- uspace/srv/ns/ns.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/ns/ns.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2015 Michal Koutny
  * All rights reserved.
  *
@@ -43,4 +44,8 @@
 #include <stdio.h>
 #include <errno.h>
+#define TASKMAN_DISABLE_ASYNC
+#include <taskman.h>
+#undef TASKMAN_DISABLE_ASYNC
+
 #include "ns.h"
 #include "service.h"
@@ -115,4 +120,10 @@
 	if (rc != EOK)
 		return rc;
+	
+	rc = taskman_intro_ns();
+	if (rc != EOK) {
+		printf("%s: not accepted by taskman (%i)\n", NAME, rc);
+		return rc;
+	}
 
 	async_set_fallback_port_handler(ns_connection, NULL);
Index: uspace/srv/sysman/main.c
===================================================================
--- uspace/srv/sysman/main.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/sysman/main.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -229,4 +229,6 @@
 	fibril_add_ready(event_loop_fibril);
 
+	sysman_log(LVL_DEBUG, "Debugging pause...\n");
+	async_usleep(10 * 1000000);
 	/* Queue first job from sequence */
 	prepare_and_run_job(&target_sequence[0]);
Index: uspace/srv/taskman/event.c
===================================================================
--- uspace/srv/taskman/event.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/taskman/event.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -137,5 +137,5 @@
 				/* Nothing to wait for anymore */
 				if (answer) {
-					async_answer_0(pr->callid, EINVAL);
+					async_answer_0(pr->callid, EINTR);
 				}
 			} else {
@@ -145,5 +145,6 @@
 		} else if (answer) {
 			if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {
-				async_answer_1(pr->callid, EINVAL, t->exit);
+				/* No sense to wait for both anymore */
+				async_answer_1(pr->callid, EINTR, t->exit);
 			} else {
 				/* Send both exit status and retval, caller
@@ -253,5 +254,4 @@
 		pr->callid = callid;
 	}
-	// TODO remove printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse);
 
 finish:
Index: uspace/srv/taskman/main.c
===================================================================
--- uspace/srv/taskman/main.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/taskman/main.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -41,4 +41,5 @@
 #include <async.h>
 #include <errno.h>
+#include <fibril_synch.h>
 #include <ipc/services.h>
 #include <ipc/taskman.h>
@@ -53,6 +54,6 @@
 #include "taskman.h"
 
-//TODO move to appropriate header file
-extern async_sess_t *session_primary;
+//#define DPRINTF(...) printf(__VA_ARGS__)
+#define DPRINTF(...) /* empty */
 
 typedef struct {
@@ -63,4 +64,9 @@
 static prodcons_t sess_queue;
 
+/** We keep session to NS on our own in taskman */
+static async_sess_t *session_ns = NULL;
+
+static FIBRIL_MUTEX_INITIALIZE(session_ns_mtx);
+static FIBRIL_CONDVAR_INITIALIZE(session_ns_cv);
 
 /*
@@ -69,4 +75,5 @@
 static void connect_to_loader(ipc_callid_t iid, ipc_call_t *icall)
 {
+	DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
 	/* We don't accept the connection request, we forward it instead to
 	 * freshly spawned loader. */
@@ -74,5 +81,4 @@
 	
 	if (rc != EOK) {
-		printf(NAME ": %s -> %i\n", __func__, rc);
 		async_answer_0(iid, rc);
 		return;
@@ -91,7 +97,5 @@
 	async_exchange_end(exch);
 
-	/* After forward we can dispose all session-related resources
-	 * TODO later could be recycled for notification API
-	 */
+	/* After forward we can dispose all session-related resources */
 	async_hangup(sess_ref->sess);
 	free(sess_ref);
@@ -105,8 +109,17 @@
 }
 
-static void loader_to_ns(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/* Do no accept connection request, forward it instead. */
-	async_exch_t *exch = async_exchange_begin(session_primary);
+static void connect_to_ns(ipc_callid_t iid, ipc_call_t *icall)
+{
+	DPRINTF("%s, %llu\n", __func__, icall->in_task_id);
+
+	/* Wait until we know NS */
+	fibril_mutex_lock(&session_ns_mtx);
+	while (session_ns == NULL) {
+		fibril_condvar_wait(&session_ns_cv, &session_ns_mtx);
+	}
+	fibril_mutex_unlock(&session_ns_mtx);
+
+	/* Do not accept connection, forward it */
+	async_exch_t *exch = async_exchange_begin(session_ns);
 	int rc = async_forward_fast(iid, exch, 0, 0, 0, IPC_FF_NONE);
 	async_exchange_end(exch);
@@ -116,4 +129,35 @@
 		return;
 	}
+}
+
+static void taskman_new_task(ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc = task_intro(icall->in_task_id);
+	async_answer_0(iid, rc);
+}
+
+static void taskman_i_am_ns(ipc_callid_t iid, ipc_call_t *icall)
+{
+	DPRINTF("%s, %llu\n", __func__, icall->in_task_id);
+	int rc = EOK;
+
+	fibril_mutex_lock(&session_ns_mtx);
+	if (session_ns != NULL) {
+		rc = EEXISTS;
+		goto finish;
+	}
+
+	/* Used only for connection forwarding -- atomic */
+	session_ns = async_callback_receive(EXCHANGE_ATOMIC);
+	
+	if (session_ns == NULL) {
+		rc = ENOENT;
+		printf("%s: Cannot connect to NS\n", NAME);
+	}
+
+	fibril_condvar_signal(&session_ns_cv);
+finish:
+	fibril_mutex_unlock(&session_ns_mtx);
+	async_answer_0(iid, rc);
 }
 
@@ -130,9 +174,10 @@
 static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
 {
-	printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
 	task_id_t sender = icall->in_task_id;
 	int retval = IPC_GET_ARG1(*icall);
 	bool wait_for_exit = IPC_GET_ARG2(*icall);
 
+	DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, sender, retval);
+
 	int rc = task_set_retval(sender, retval, wait_for_exit);
 	async_answer_0(iid, rc);
@@ -141,5 +186,6 @@
 static void taskman_ctl_ev_callback(ipc_callid_t iid, ipc_call_t *icall)
 {
-	printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
+	DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
+
 	/* Atomic -- will be used for notifications only */
 	async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
@@ -157,5 +203,5 @@
 	task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
 	exit_reason_t exit_reason = IPC_GET_ARG3(*icall);
-	printf("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
+	DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
 	task_terminated(id, exit_reason);
 }
@@ -164,56 +210,11 @@
 {
 	task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
-	printf("%s:%i from %llu\n", __func__, __LINE__, id);
+	DPRINTF("%s:%i from %llu\n", __func__, __LINE__, id);
 	task_failed(id);
 }
 
-static void control_connection_loop(void)
-{
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-
-		if (!IPC_GET_IMETHOD(call)) {
-			/* Client disconnected */
-			break;
-		}
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case TASKMAN_WAIT:
-			taskman_ctl_wait(callid, &call);
-			break;
-		case TASKMAN_RETVAL:
-			taskman_ctl_retval(callid, &call);
-			break;
-		case TASKMAN_EVENT_CALLBACK:
-			taskman_ctl_ev_callback(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOENT);
-		}
-	}
-}
-
-static void control_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/* TODO remove/redesign the workaround
-	 * Call task_intro here for boot-time tasks,
-	 * probably they should announce themselves explicitly
-	 * or taskman should detect them from kernel's list of tasks.
-	 */
-	int rc = task_intro(icall, false);
-
-	/* First, accept connection */
-	async_answer_0(iid, rc);
-
-	if (rc != EOK) {
-		return;
-	}
-
-	control_connection_loop();
-}
-
 static void loader_callback(ipc_callid_t iid, ipc_call_t *icall)
 {
+	DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
 	// TODO check that loader is expected, would probably discard prodcons
 	//      scheme
@@ -232,12 +233,4 @@
 	}
 
-	/* Remember task_id */
-	int rc = task_intro(icall, true);
-
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		free(sess_ref);
-		return;
-	}
 	async_answer_0(iid, EOK);
 
@@ -247,36 +240,96 @@
 }
 
+static bool handle_call(ipc_callid_t iid, ipc_call_t *icall)
+{
+	switch (IPC_GET_IMETHOD(*icall)) {
+	case TASKMAN_NEW_TASK:
+		taskman_new_task(iid, icall);
+		break;
+	case TASKMAN_I_AM_NS:
+		taskman_i_am_ns(iid, icall);
+		break;
+	case TASKMAN_WAIT:
+		taskman_ctl_wait(iid, icall);
+		break;
+	case TASKMAN_RETVAL:
+		taskman_ctl_retval(iid, icall);
+		break;
+	case TASKMAN_EVENT_CALLBACK:
+		taskman_ctl_ev_callback(iid, icall);
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static bool handle_implicit_call(ipc_callid_t iid, ipc_call_t *icall)
+{
+	DPRINTF("%s:%i %i(%i) from %llu\n", __func__, __LINE__,
+	    IPC_GET_IMETHOD(*icall),
+	    IPC_GET_ARG1(*icall),
+	    icall->in_task_id);
+
+	if (IPC_GET_IMETHOD(*icall) < IPC_FIRST_USER_METHOD) {
+		switch (IPC_GET_ARG1(*icall)) {
+		case TASKMAN_CONNECT_TO_NS:
+			connect_to_ns(iid, icall);
+			break;
+		case TASKMAN_CONNECT_TO_LOADER:
+			connect_to_loader(iid, icall);
+			break;
+		case TASKMAN_LOADER_CALLBACK:
+			loader_callback(iid, icall);
+			break;
+		default:
+			return false;
+
+		}
+	} else {
+		return handle_call(iid, icall);
+	}
+
+	return true;
+}
+
+static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	if (!handle_implicit_call(iid, icall)) {
+		async_answer_0(iid, ENOTSUP);
+		return;
+	}
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call)) {
+			/* Client disconnected */
+			break;
+		}
+
+		if (!handle_implicit_call(callid, &call)) {
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
 static void taskman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	taskman_interface_t iface = IPC_GET_ARG1(*icall);
-	switch (iface) {
-	case TASKMAN_CONNECT_TO_LOADER:
-		connect_to_loader(iid, icall);
-		break;
-	case TASKMAN_LOADER_TO_NS:
-		loader_to_ns(iid, icall);
-		break;
-	case TASKMAN_CONTROL:
-		control_connection(iid, icall);
-		break;
-	default:
-		/* Unknown interface */
-		async_answer_0(iid, ENOENT);
-	}
-}
-
-static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	taskman_interface_t iface = IPC_GET_ARG1(*icall);
-	switch (iface) {
-	case TASKMAN_LOADER_CALLBACK:
-		loader_callback(iid, icall);
-		control_connection_loop();
-		break;
-	default:
-		/* Unknown interface on implicit connection */
+	/*
+	 * We don't expect (yet) clients to connect, having this function is
+	 * just to adapt to async framework that creates new connection for
+	 * each IPC_M_CONNECT_ME_TO.
+	 * In this case those are to be forwarded, so don't continue
+	 * "listening" on such connections.
+	 */
+	if (!handle_implicit_call(iid, icall)) {
+		/* If cannot handle connection requst, give up trying */
 		async_answer_0(iid, EHANGUP);
-	}
-}
+		return;
+	}
+}
+
 
 
@@ -298,5 +351,5 @@
 	rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
 	if (rc != EOK) {
-		printf("Cannot register for exit events (%i).\n", rc);
+		printf(NAME ": Cannot register for exit events (%i).\n", rc);
 		return rc;
 	}
@@ -304,21 +357,20 @@
 	rc = async_event_subscribe(EVENT_FAULT, task_fault_event, NULL);
 	if (rc != EOK) {
-		printf("Cannot register for fault events (%i).\n", rc);
+		printf(NAME ": Cannot register for fault events (%i).\n", rc);
 		return rc;
 	}
-
-	/* We're service too */
-	rc = service_register(SERVICE_TASKMAN);
-	if (rc != EOK) {
-		printf("Cannot register at naming service (%i).\n", rc);
-		return rc;
+	
+	task_id_t self_id = task_get_id();
+	rc = task_intro(self_id);
+	if (rc != EOK) {
+		printf(NAME ": Cannot register self as task (%i).\n", rc);
 	}
 
 	/* Start sysman server */
+	async_set_implicit_connection(implicit_connection);
 	async_set_client_connection(taskman_connection);
-	async_set_implicit_connection(implicit_connection);
 
 	printf(NAME ": Accepting connections\n");
-	//TODO task_retval(EOK);
+	(void)task_set_retval(self_id, EOK, false);
 	async_manager();
 
Index: uspace/srv/taskman/task.c
===================================================================
--- uspace/srv/taskman/task.c	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/taskman/task.c	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -109,5 +109,5 @@
 }
 
-int task_intro(ipc_call_t *call, bool check_unique)
+int task_intro(task_id_t id)
 {
 	int rc = EOK;
@@ -115,5 +115,5 @@
 	fibril_rwlock_write_lock(&task_hash_table_lock);
 
-	task_t *t = task_get_by_id(call->in_task_id);
+	task_t *t = task_get_by_id(id);
 	if (t != NULL) {
 		rc = EEXISTS;
@@ -130,5 +130,5 @@
 	 * Insert into the main table.
 	 */
-	t->id = call->in_task_id;
+	t->id = id;
 	t->exit = TASK_EXIT_RUNNING;
 	t->failed = false;
Index: uspace/srv/taskman/task.h
===================================================================
--- uspace/srv/taskman/task.h	(revision 780c8ce2b4c584af1b1e84434bc2d7079a4ae6df)
+++ uspace/srv/taskman/task.h	(revision 012dd8ef3ba6b88a27a8406f1cb055389e6363f1)
@@ -70,5 +70,5 @@
 extern task_t *task_get_by_id(task_id_t);
 
-extern int task_intro(ipc_call_t *, bool);
+extern int task_intro(task_id_t);
 
 #endif
