Index: uspace/lib/libc/generic/task.c
===================================================================
--- uspace/lib/libc/generic/task.c	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/lib/libc/generic/task.c	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -163,9 +163,5 @@
 int task_retval(int val)
 {
-	task_id_t id;
-
-	id = task_get_id();
-	return (int) async_req_3_0(PHONE_NS, NS_RETVAL, LOWER32(id),
-	    UPPER32(id), val);
+	return (int) async_req_1_0(PHONE_NS, NS_RETVAL, val);
 }
 
Index: uspace/lib/libc/include/ipc/ns.h
===================================================================
--- uspace/lib/libc/include/ipc/ns.h	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/lib/libc/include/ipc/ns.h	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -41,4 +41,5 @@
 	NS_PING = IPC_FIRST_USER_METHOD,
 	NS_TASK_WAIT,
+	NS_ID_INTRO,
 	NS_RETVAL
 } ns_request_t;
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/srv/loader/main.c	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -53,4 +53,6 @@
 #include <ipc/services.h>
 #include <ipc/loader.h>
+#include <ipc/ns.h>
+#include <macros.h>
 #include <loader/pcb.h>
 #include <errno.h>
@@ -438,7 +440,15 @@
 {
 	ipcarg_t phonead;
-	
+	task_id_t id;
+	int rc;
+
 	connected = false;
-	
+
+	/* Introduce this task to the NS (give it our task ID). */
+	id = task_get_id();
+	rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
+	if (rc != EOK)
+		return -1;
+
 	/* Set a handler of incomming connections. */
 	async_set_client_connection(ldr_connection);
@@ -446,6 +456,6 @@
 	/* Register at naming service. */
 	if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) 
-		return -1;
-	
+		return -2;
+
 	async_manager();
 	
Index: uspace/srv/ns/ns.c
===================================================================
--- uspace/srv/ns/ns.c	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/srv/ns/ns.c	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -134,5 +134,5 @@
 			continue;
 		case IPC_M_PHONE_HUNGUP:
-			retval = EOK;
+			retval = ns_task_disconnect(&call);
 			break;
 		case IPC_M_CONNECT_TO_ME:
@@ -171,4 +171,7 @@
 			wait_for_task(id, &call, callid);
 			continue;
+		case NS_ID_INTRO:
+			retval = ns_task_id_intro(&call);
+			break;
 		case NS_RETVAL:
 			retval = ns_task_retval(&call);
Index: uspace/srv/ns/task.c
===================================================================
--- uspace/srv/ns/task.c	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/srv/ns/task.c	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Martin Decky
+ * Copyright (c) 2009 Jiri Svoboda
  * All rights reserved.
  *
@@ -42,14 +43,12 @@
 
 #define TASK_HASH_TABLE_CHAINS  256
+#define P2I_HASH_TABLE_CHAINS  256
+
+static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id);
 
 /* TODO:
  *
  * The current implementation of waiting on a task is not perfect. If somebody
- * wants to wait on a task which has already finished before the NS asked
- * the kernel to receive notifications, it would block indefinitively.
- *
- * A solution to this is to fail immediately on a task for which no creation
- * notification was received yet. However, there is a danger of a race condition
- * in this solution -- the caller has to make sure that it is not trying to wait
+ * The caller has to make sure that it is not trying to wait
  * before the NS has a change to receive the task creation notification. This
  * can be assured by waiting for this event in task_spawn().
@@ -85,5 +84,5 @@
  *
  * @param key  Array of keys.
- * @param keys Must be lesser or equal to 2.
+ * @param keys Must be less than or equal to 2.
  * @param item Pointer to a hash table item.
  *
@@ -127,4 +126,63 @@
 static hash_table_t task_hash_table;
 
+typedef struct {
+	link_t link;
+	ipcarg_t phash;    /**< Task ID. */
+	task_id_t id;    /**< Task ID. */
+} p2i_entry_t;
+
+/** Compute hash index into task hash table.
+ *
+ * @param key Array of keys.
+ * @return Hash index corresponding to key[0].
+ *
+ */
+static hash_index_t p2i_hash(unsigned long *key)
+{
+	assert(key);
+	return (*key % TASK_HASH_TABLE_CHAINS);
+}
+
+/** Compare a key with hashed item.
+ *
+ * @param key  Array of keys.
+ * @param keys Must be less than or equal to 1.
+ * @param item Pointer to a hash table item.
+ *
+ * @return Non-zero if the key matches the item, zero otherwise.
+ *
+ */
+static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	assert(key);
+	assert(keys == 1);
+	assert(item);
+
+	p2i_entry_t *e = hash_table_get_instance(item, p2i_entry_t, link);
+
+	return (key[0] == e->phash);
+}
+
+/** Perform actions after removal of item from the hash table.
+ *
+ * @param item Item that was removed from the hash table.
+ *
+ */
+static void p2i_remove(link_t *item)
+{
+	assert(item);
+	free(hash_table_get_instance(item, p2i_entry_t, link));
+}
+
+/** Operations for task hash table. */
+static hash_table_operations_t p2i_ops = {
+	.hash = p2i_hash,
+	.compare = p2i_compare,
+	.remove_callback = p2i_remove
+};
+
+/** Map phone hash to task ID */
+static hash_table_t phone_to_id;
+
 /** Pending task wait structure. */
 typedef struct {
@@ -140,4 +198,10 @@
 	if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
 	    2, &task_hash_table_ops)) {
+		printf(NAME ": No memory available for tasks\n");
+		return ENOMEM;
+	}
+
+	if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS,
+	    1, &p2i_ops)) {
 		printf(NAME ": No memory available for tasks\n");
 		return ENOMEM;
@@ -239,10 +303,15 @@
 		UPPER32(id)
 	};
-	
+
 	link_t *link = hash_table_find(&task_hash_table, keys);
 	hashed_task_t *ht = (link != NULL) ?
 	    hash_table_get_instance(link, hashed_task_t, link) : NULL;
-	
-	if ((ht == NULL) || (!ht->destroyed)) {
+
+	if (ht == NULL) {
+		retval = ENOENT;
+		goto out;
+	}
+
+	if (!ht->destroyed) {
 		/* Add to pending list */
 		pending_wait_t *pr =
@@ -267,10 +336,40 @@
 }
 
+int ns_task_id_intro(ipc_call_t *call)
+{
+	task_id_t id;
+	unsigned long keys[1];
+	link_t *link;
+	p2i_entry_t *e;
+
+	id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
+
+	keys[0] = call->in_phone_hash;
+
+	link = hash_table_find(&phone_to_id, keys);
+	if (link != NULL)
+		return EEXISTS;
+
+	e = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
+	if (e == NULL)
+		return ENOMEM;
+
+	link_initialize(&e->link);
+	e->phash = call->in_phone_hash;
+	e->id = id;
+	hash_table_insert(&phone_to_id, keys, &e->link);
+
+	return EOK;
+}
+
 int ns_task_retval(ipc_call_t *call)
 {
 	task_id_t id;
 	unsigned long keys[2];
-
-	id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
+	int rc;
+
+	rc = get_id_by_phone(call->in_phone_hash, &id);
+	if (rc != EOK)
+		return rc;
 
 	keys[0] = LOWER32(id);
@@ -284,5 +383,32 @@
 		return EINVAL;
 
-	ht->retval = IPC_GET_ARG3(*call);
+	ht->retval = IPC_GET_ARG1(*call);
+
+	return EOK;
+}
+
+int ns_task_disconnect(ipc_call_t *call)
+{
+	unsigned long keys[1];
+
+	keys[0] = call->in_phone_hash;
+	hash_table_remove(&phone_to_id, keys, 1);
+	
+	return EOK;
+}
+
+static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id)
+{
+	unsigned long keys[1];
+	link_t *link;
+	p2i_entry_t *e;
+
+	keys[0] = phone_hash;
+	link = hash_table_find(&phone_to_id, keys);
+	if (link == NULL)
+		return ENOENT;
+
+	e = hash_table_get_instance(link, p2i_entry_t, link);
+	*id = e->id;
 
 	return EOK;
Index: uspace/srv/ns/task.h
===================================================================
--- uspace/srv/ns/task.h	(revision 7114d836ff84c10f98376e50246b4d5e34146131)
+++ uspace/srv/ns/task.h	(revision 5d96851b8924322db82eed0dc7032e7f6817c983)
@@ -43,5 +43,8 @@
 extern void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid);
 
+extern int ns_task_id_intro(ipc_call_t *call);
+extern int ns_task_disconnect(ipc_call_t *call);
 extern int ns_task_retval(ipc_call_t *call);
+
 
 #endif
