Index: uspace/srv/taskman/Makefile
===================================================================
--- uspace/srv/taskman/Makefile	(revision c675ab1ebb159b7e38a64765f63096588f7d9ff1)
+++ uspace/srv/taskman/Makefile	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -32,4 +32,5 @@
 
 SOURCES = \
+	event.c \
 	main.c \
 	task.c
Index: uspace/srv/taskman/event.c
===================================================================
--- uspace/srv/taskman/event.c	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
+++ uspace/srv/taskman/event.c	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -0,0 +1,340 @@
+/*
+ * 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 taskman
+ * @{
+ */
+
+#include <adt/list.h>
+#include <assert.h>
+#include <errno.h>
+#include <ipc/taskman.h>
+#include <stdlib.h>
+#include <task.h>
+
+#include "event.h"
+#include "task.h"
+
+/** Pending task wait structure. */
+typedef struct {
+	link_t link;
+	task_id_t id;         /**< Task ID who we wait for. */
+	task_id_t waiter_id;  /**< Task ID who waits. */
+	ipc_callid_t callid;  /**< Call ID waiting for the event. */
+	int flags;            /**< Wait flags. */
+} pending_wait_t;
+
+static list_t pending_waits;
+static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock);
+
+static list_t listeners;
+static FIBRIL_RWLOCK_INITIALIZE(listeners_lock);
+
+int event_init(void)
+{
+	list_initialize(&pending_waits);
+	list_initialize(&listeners);
+
+	return EOK;
+}
+
+static int event_flags(task_t *task)
+{
+	int flags = 0;
+	if (task->exit != TASK_EXIT_RUNNING) {
+		flags |= TASK_WAIT_EXIT;
+		if (task->retval_type == RVAL_SET_EXIT) {
+			flags |= TASK_WAIT_RETVAL;
+		}
+	}
+	if (task->retval_type == RVAL_SET) {
+		flags |= TASK_WAIT_RETVAL;
+	}
+
+	return flags;
+}
+
+static void event_notify(task_t *sender)
+{
+	// TODO should rlock task_hash_table?
+	int flags = event_flags(sender);
+	if (flags == 0) {
+		return;
+	}
+
+	fibril_rwlock_read_lock(&listeners_lock);
+	list_foreach(listeners, listeners, task_t, t) {
+		assert(t->sess);
+		async_exch_t *exch = async_exchange_begin(t->sess);
+		/* Just send a notification and don't wait for anything */
+		async_send_5(exch, TASKMAN_EV_TASK,
+		    LOWER32(sender->id),
+		    UPPER32(sender->id),
+		    flags,
+		    sender->exit,
+		    sender->retval,
+		    NULL);
+
+		async_exchange_end(exch);
+	}
+	fibril_rwlock_read_unlock(&listeners_lock);
+}
+
+/** Process pending wait requests
+ *
+ * Assumes task_hash_table_lock is hold (at least read)
+ */
+static void process_pending_wait(void)
+{
+	fibril_rwlock_write_lock(&pending_wait_lock);
+loop:
+	list_foreach(pending_waits, link, pending_wait_t, pr) {
+		task_t *t = task_get_by_id(pr->id);
+		if (t == NULL) {
+			continue; // TODO really when does this happen?
+		}
+		int notify_flags = event_flags(t);
+
+		/*
+		 * In current implementation you can wait for single retval,
+		 * thus it can be never present in rest flags.
+		 */
+		int rest = (~notify_flags & pr->flags) & ~TASK_WAIT_RETVAL;
+		rest &= ~TASK_WAIT_BOTH;
+		int match = notify_flags & pr->flags;
+		// TODO why do I even accept such calls?
+		bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);
+
+		if (match == 0) {
+			if (notify_flags & TASK_WAIT_EXIT) {
+				/* Nothing to wait for anymore */
+				if (answer) {
+					async_answer_0(pr->callid, EINVAL);
+				}
+			} else {
+				/* Maybe later */
+				continue;
+			}
+		} else if (answer) {
+			if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {
+				async_answer_1(pr->callid, EINVAL, t->exit);
+			} else {
+				/* Send both exit status and retval, caller
+				 * should know what is valid */
+				async_answer_3(pr->callid, EOK, t->exit,
+				    t->retval, rest);
+			}
+
+			/* Pending wait has one more chance  */
+			if (rest && (pr->flags & TASK_WAIT_BOTH)) {
+				pr->flags = rest | TASK_WAIT_BOTH;
+				continue;
+			}
+		}
+
+		
+		list_remove(&pr->link);
+		free(pr);
+		goto loop;
+	}
+	fibril_rwlock_write_unlock(&pending_wait_lock);
+}
+
+int event_register_listener(task_id_t id, async_sess_t *sess)
+{
+	int rc = EOK;
+	fibril_rwlock_write_lock(&task_hash_table_lock);
+	fibril_rwlock_write_lock(&listeners_lock);
+
+	task_t *t = task_get_by_id(id);
+	if (t == NULL) {
+		rc = ENOENT;
+		goto finish;
+	}
+	assert(t->sess == NULL);
+	list_append(&t->listeners, &listeners);
+	t->sess = sess;
+
+finish:
+	fibril_rwlock_write_unlock(&listeners_lock);
+	fibril_rwlock_write_unlock(&task_hash_table_lock);
+	return rc;
+}
+
+void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(!(flags & TASK_WAIT_BOTH) ||
+	    ((flags & TASK_WAIT_RETVAL) && (flags & TASK_WAIT_EXIT)));
+
+	fibril_rwlock_read_lock(&task_hash_table_lock);
+	task_t *t = task_get_by_id(id);
+	fibril_rwlock_read_unlock(&task_hash_table_lock);
+
+	if (t == NULL) {
+		/* No such task exists. */
+		async_answer_0(callid, ENOENT);
+		return;
+	}
+	
+	if (t->exit != TASK_EXIT_RUNNING) {
+		//TODO are flags BOTH processed correctly here?
+		async_answer_3(callid, EOK, t->exit, t->retval, 0);
+		return;
+	}
+	
+	/*
+	 * Add request to pending list or reuse existing item for a second
+	 * wait.
+	 */
+	task_id_t waiter_id = call->in_task_id;
+	fibril_rwlock_write_lock(&pending_wait_lock);
+	pending_wait_t *pr = NULL;
+	list_foreach(pending_waits, link, pending_wait_t, it) {
+		if (it->id == id && it->waiter_id == waiter_id) {
+			pr = it;
+			break;
+		}
+	}
+
+	int rc = EOK;
+	if (pr == NULL) {
+		pr = malloc(sizeof(pending_wait_t));
+		if (!pr) {
+			rc = ENOMEM;
+			goto finish;
+		}
+	
+		link_initialize(&pr->link);
+		pr->id = id;
+		pr->waiter_id = waiter_id;
+		pr->flags = flags;
+		pr->callid = callid;
+
+		list_append(&pr->link, &pending_waits);
+		rc = EOK;
+	} else if (!(pr->flags & TASK_WAIT_BOTH)) {
+		/*
+		 * One task can wait for another task only once (per task, not
+		 * fibril).
+		 */
+		rc = EEXISTS;
+	} else {
+		/*
+		 * Reuse pending wait for the second time.
+		 */
+		pr->flags &= ~TASK_WAIT_BOTH; // TODO maybe new flags should be set?
+		pr->callid = callid;
+	}
+	// TODO remove printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse);
+
+finish:
+	fibril_rwlock_write_unlock(&pending_wait_lock);
+	// TODO why IPC_CALLID_NOTIFICATION? explain!
+	if (rc != EOK && !(callid & IPC_CALLID_NOTIFICATION)) {
+		async_answer_0(callid, rc);
+	}
+}
+
+
+int task_set_retval(ipc_call_t *call)
+{
+	int rc = EOK;
+	task_id_t id = call->in_task_id;
+	
+	fibril_rwlock_write_lock(&task_hash_table_lock);
+	task_t *t = task_get_by_id(id);
+
+	if ((t == NULL) || (t->exit != TASK_EXIT_RUNNING)) {
+		rc = EINVAL;
+		goto finish;
+	}
+	
+	t->retval = IPC_GET_ARG1(*call);
+	t->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET;
+	
+	event_notify(t);
+	process_pending_wait();
+	
+finish:
+	fibril_rwlock_write_unlock(&task_hash_table_lock);
+	return rc;
+}
+
+void task_terminated(task_id_t id, exit_reason_t exit_reason)
+{
+	/* Mark task as finished. */
+	fibril_rwlock_write_lock(&task_hash_table_lock);
+	task_t *t = task_get_by_id(id);
+	if (t == NULL) {
+		goto finish;
+	}
+
+	/*
+	 * If daemon returns a value and then fails/is killed, it's an
+	 * unexpected termination.
+	 */
+	if (t->retval_type == RVAL_UNSET || exit_reason == EXIT_REASON_KILLED) {
+		t->exit = TASK_EXIT_UNEXPECTED;
+	} else if (t->failed) {
+		t->exit = TASK_EXIT_UNEXPECTED;
+	} else  {
+		t->exit = TASK_EXIT_NORMAL;
+	}
+
+	event_notify(t);
+	process_pending_wait();
+
+	hash_table_remove_item(&task_hash_table, &t->link);
+	// TODO remove from listeners too!
+
+finish:
+	fibril_rwlock_write_unlock(&task_hash_table_lock);
+}
+
+void task_failed(task_id_t id)
+{
+	/* Mark task as failed. */
+	fibril_rwlock_write_lock(&task_hash_table_lock);
+	task_t *t = task_get_by_id(id);
+	if (t == NULL) {
+		goto finish;
+	}
+
+	t->failed = true;
+	// TODO design substitution for taskmon (monitoring) = invoke dump
+	// utility or pass event to registered tasks
+
+finish:
+	fibril_rwlock_write_unlock(&task_hash_table_lock);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/taskman/event.h
===================================================================
--- uspace/srv/taskman/event.h	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
+++ uspace/srv/taskman/event.h	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * 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 taskman
+ * @{
+ */
+
+#ifndef TASKMAN_EVENT_H__
+#define TASKMAN_EVENT_H__
+
+#include <async.h>
+#include <ipc/common.h>
+#include <abi/proc/task.h>
+
+extern int event_init(void);
+
+
+// TODO unify this API for all call/connection handlers
+extern int event_register_listener(task_id_t, async_sess_t *);
+extern void wait_for_task(task_id_t, int, ipc_callid_t, ipc_call_t *);
+extern int task_set_retval(ipc_call_t *);
+
+extern void task_terminated(task_id_t, exit_reason_t);
+extern void task_failed(task_id_t);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/taskman/main.c
===================================================================
--- uspace/srv/taskman/main.c	(revision c675ab1ebb159b7e38a64765f63096588f7d9ff1)
+++ uspace/srv/taskman/main.c	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -39,4 +39,5 @@
 #include <stdlib.h>
 
+#include "event.h"
 #include "task.h"
 #include "taskman.h"
@@ -63,4 +64,5 @@
 	
 	if (rc != EOK) {
+		printf(NAME ": %s -> %i\n", __func__, rc);
 		async_answer_0(iid, rc);
 		return;
@@ -125,5 +127,13 @@
 {
 	printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
-	async_answer_0(iid, ENOTSUP); // TODO interrupt here
+	/* Atomic -- will be used for notifications only */
+	async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
+	if (sess == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	int rc = event_register_listener(icall->in_task_id, sess);
+	async_answer_0(iid, rc);
 }
 
@@ -268,4 +278,8 @@
 		return rc;
 	}
+	rc = event_init();
+	if (rc != EOK) {
+		return rc;
+	}
 
 	rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
Index: uspace/srv/taskman/task.c
===================================================================
--- uspace/srv/taskman/task.c	(revision c675ab1ebb159b7e38a64765f63096588f7d9ff1)
+++ uspace/srv/taskman/task.c	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -30,7 +30,8 @@
 
 /**
- * locking order:
+ * locking order: (TODO move to main?)
  * - task_hash_table_lock,
  * - pending_wait_lock.
+ * - listeners_lock
  *
  * @addtogroup taskman
@@ -38,9 +39,7 @@
  */
 
-#include <adt/hash_table.h>
 #include <assert.h>
 #include <async.h>
 #include <errno.h>
-#include <fibril_synch.h>
 #include <macros.h>
 #include <malloc.h>
@@ -53,23 +52,4 @@
 #include "taskman.h"
 
-/** what type of retval from the task we have */
-typedef enum {
-	RVAL_UNSET,     /**< unset */
-	RVAL_SET,       /**< retval set, e.g. by server */
-	RVAL_SET_EXIT   /**< retval set, wait for expected task exit */
-} retval_t;
-
-/** Task hash table item. */
-typedef struct {
-	ht_link_t link;
-	
-	task_id_t id;          /**< Task id. */
-	task_exit_t exit;      /**< Task's uspace exit status. */
-	bool failed;           /**< Task failed. */
-	retval_t retval_type;  /**< Task returned a value. */
-	int retval;            /**< The return value. */
-} hashed_task_t;
-
-
 static size_t task_key_hash(void *key)
 {
@@ -79,5 +59,5 @@
 static size_t task_hash(const ht_link_t  *item)
 {
-	hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
+	task_t *ht = hash_table_get_inst(item, task_t, link);
 	return ht->id;
 }
@@ -85,5 +65,5 @@
 static bool task_key_equal(void *key, const ht_link_t *item)
 {
-	hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
+	task_t *ht = hash_table_get_inst(item, task_t, link);
 	return ht->id == *(task_id_t*)key;
 }
@@ -92,5 +72,5 @@
 static void task_remove(ht_link_t *item)
 {
-	free(hash_table_get_inst(item, hashed_task_t, link));
+	free(hash_table_get_inst(item, task_t, link));
 }
 
@@ -105,18 +85,6 @@
 
 /** Task hash table structure. */
-static hash_table_t task_hash_table;
-static FIBRIL_RWLOCK_INITIALIZE(task_hash_table_lock);
-
-/** Pending task wait structure. */
-typedef struct {
-	link_t link;
-	task_id_t id;         /**< Task ID who we wait for. */
-	task_id_t waiter_id;  /**< Task ID who waits. */
-	ipc_callid_t callid;  /**< Call ID waiting for the connection */
-	int flags;            /**< Wait flags */
-} pending_wait_t;
-
-static list_t pending_wait;
-static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock);
+hash_table_t task_hash_table;
+fibril_rwlock_t task_hash_table_lock;
 
 int task_init(void)
@@ -126,156 +94,27 @@
 		return ENOMEM;
 	}
+
+	fibril_rwlock_initialize(&task_hash_table_lock);
 	
-	list_initialize(&pending_wait);
 	return EOK;
 }
 
-/** Process pending wait requests
+/** Find task by its ID
  *
- * Assumes task_hash_table_lock is hold (at least read)
+ * Assumes held lock of task_hash_table.
+ *
+ * @param[in]  id
+ * @return task structure
+ * @return NULL when no task with given ID exists
  */
-void process_pending_wait(void)
+task_t *task_get_by_id(task_id_t id)
 {
-	fibril_rwlock_write_lock(&pending_wait_lock);
-loop:
-	list_foreach(pending_wait, link, pending_wait_t, pr) {
-		ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
-		if (!link)
-			continue;
-		
-		hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
-		int notify_flags = 0;
-		if (ht->exit != TASK_EXIT_RUNNING) {
-			notify_flags |= TASK_WAIT_EXIT;
-			if (ht->retval_type == RVAL_SET_EXIT) {
-				notify_flags |= TASK_WAIT_RETVAL;
-			}
-		}
-		if (ht->retval_type == RVAL_SET) {
-			notify_flags |= TASK_WAIT_RETVAL;
-		}
-
-		/*
-		 * In current implementation you can wait for single retval,
-		 * thus it can be never present in rest flags.
-		 */
-		int rest = (~notify_flags & pr->flags) & ~TASK_WAIT_RETVAL;
-		rest &= ~TASK_WAIT_BOTH;
-		int match = notify_flags & pr->flags;
-		bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);
-		printf("%s: %x; %x, %x\n", __func__, pr->flags, rest, match);
-
-		if (match == 0) {
-			if (notify_flags & TASK_WAIT_EXIT) {
-				/* Nothing to wait for anymore */
-				if (answer) {
-					async_answer_0(pr->callid, EINVAL);
-				}
-			} else {
-				/* Maybe later */
-				continue;
-			}
-		} else if (answer) {
-			if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {
-				async_answer_1(pr->callid, EINVAL, ht->exit);
-			} else {
-				/* Send both exit status and retval, caller
-				 * should know what is valid */
-				async_answer_3(pr->callid, EOK, ht->exit,
-				    ht->retval, rest);
-			}
-
-			/* Pending wait has one more chance  */
-			if (rest && (pr->flags & TASK_WAIT_BOTH)) {
-				pr->flags = rest | TASK_WAIT_BOTH;
-				continue;
-			}
-		}
-
-		
-		list_remove(&pr->link);
-		free(pr);
-		goto loop;
-	}
-	fibril_rwlock_write_unlock(&pending_wait_lock);
-}
-
-void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)
-{
-	assert(!(flags & TASK_WAIT_BOTH) ||
-	    ((flags & TASK_WAIT_RETVAL) && (flags & TASK_WAIT_EXIT)));
-
-	fibril_rwlock_read_lock(&task_hash_table_lock);
 	ht_link_t *link = hash_table_find(&task_hash_table, &id);
-	fibril_rwlock_read_unlock(&task_hash_table_lock);
-
-	hashed_task_t *ht = (link != NULL) ?
-	    hash_table_get_inst(link, hashed_task_t, link) : NULL;
-	
-	if (ht == NULL) {
-		/* No such task exists. */
-		async_answer_0(callid, ENOENT);
-		return;
+	if (!link) {
+		return NULL;
 	}
 	
-	if (ht->exit != TASK_EXIT_RUNNING) {
-		//TODO are flags BOTH processed correctly here?
-		async_answer_3(callid, EOK, ht->exit, ht->retval, 0);
-		return;
-	}
-	
-	/*
-	 * Add request to pending list or reuse existing item for a second
-	 * wait.
-	 */
-	task_id_t waiter_id = call->in_task_id;
-	fibril_rwlock_write_lock(&pending_wait_lock);
-	pending_wait_t *pr = NULL;
-	list_foreach(pending_wait, link, pending_wait_t, it) {
-		if (it->id == id && it->waiter_id == waiter_id) {
-			pr = it;
-			break;
-		}
-	}
-
-	int rc = EOK;
-	bool reuse = false;
-	if (pr == NULL) {
-		pr = malloc(sizeof(pending_wait_t));
-		if (!pr) {
-			rc = ENOMEM;
-			goto finish;
-		}
-	
-		link_initialize(&pr->link);
-		pr->id = id;
-		pr->waiter_id = waiter_id;
-		pr->flags = flags;
-		pr->callid = callid;
-
-		list_append(&pr->link, &pending_wait);
-		rc = EOK;
-	} else if (!(pr->flags & TASK_WAIT_BOTH)) {
-		/*
-		 * One task can wait for another task only once (per task, not
-		 * fibril).
-		 */
-		rc = EEXISTS;
-	} else {
-		/*
-		 * Reuse pending wait for the second time.
-		 */
-		pr->flags &= ~TASK_WAIT_BOTH; // TODO maybe new flags should be set?
-		pr->callid = callid;
-		reuse = true;
-	}
-	printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse);
-
-finish:
-	fibril_rwlock_write_unlock(&pending_wait_lock);
-	// TODO why IPC_CALLID_NOTIFICATION? explain!
-	if (rc != EOK && !(callid & IPC_CALLID_NOTIFICATION))
-		async_answer_0(callid, rc);
-
+	task_t *t = hash_table_get_inst(link, task_t, link);
+	return t;
 }
 
@@ -286,12 +125,12 @@
 	fibril_rwlock_write_lock(&task_hash_table_lock);
 
-	ht_link_t *link = hash_table_find(&task_hash_table, &call->in_task_id);
-	if (link != NULL) {
+	task_t *t = task_get_by_id(call->in_task_id);
+	if (t != NULL) {
 		rc = EEXISTS;
 		goto finish;
 	}
 	
-	hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
-	if (ht == NULL) {
+	t = malloc(sizeof(task_t));
+	if (t == NULL) {
 		rc = ENOMEM;
 		goto finish;
@@ -301,12 +140,14 @@
 	 * Insert into the main table.
 	 */
-	ht->id = call->in_task_id;
-	ht->exit = TASK_EXIT_RUNNING;
-	ht->failed = false;
-	ht->retval_type = RVAL_UNSET;
-	ht->retval = -1;
+	t->id = call->in_task_id;
+	t->exit = TASK_EXIT_RUNNING;
+	t->failed = false;
+	t->retval_type = RVAL_UNSET;
+	t->retval = -1;
+	link_initialize(&t->listeners);
+	t->sess = NULL;
 
-	hash_table_insert(&task_hash_table, &ht->link);
-	printf("%s: %llu\n", __func__, ht->id);
+	hash_table_insert(&task_hash_table, &t->link);
+	printf("%s: %llu\n", __func__, t->id);
 	
 finish:
@@ -315,76 +156,4 @@
 }
 
-int task_set_retval(ipc_call_t *call)
-{
-	int rc = EOK;
-	task_id_t id = call->in_task_id;
-	
-	fibril_rwlock_write_lock(&task_hash_table_lock);
-	ht_link_t *link = hash_table_find(&task_hash_table, &id);
-
-	hashed_task_t *ht = (link != NULL) ?
-	    hash_table_get_inst(link, hashed_task_t, link) : NULL;
-	
-	if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) {
-		rc = EINVAL;
-		goto finish;
-	}
-	
-	ht->retval = IPC_GET_ARG1(*call);
-	ht->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET;
-	
-	process_pending_wait();
-	
-finish:
-	fibril_rwlock_write_unlock(&task_hash_table_lock);
-	return rc;
-}
-
-void task_terminated(task_id_t id, exit_reason_t exit_reason)
-{
-	/* Mark task as finished. */
-	fibril_rwlock_write_lock(&task_hash_table_lock);
-	ht_link_t *link = hash_table_find(&task_hash_table, &id);
-	if (link == NULL) {
-		goto finish;
-	}
-
-	hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
-	
-	/*
-	 * If daemon returns a value and then fails/is killed, it's an
-	 * unexpected termination.
-	 */
-	if (ht->retval_type == RVAL_UNSET || exit_reason == EXIT_REASON_KILLED) {
-		ht->exit = TASK_EXIT_UNEXPECTED;
-	} else if (ht->failed) {
-		ht->exit = TASK_EXIT_UNEXPECTED;
-	} else  {
-		ht->exit = TASK_EXIT_NORMAL;
-	}
-	process_pending_wait();
-
-	hash_table_remove_item(&task_hash_table, &ht->link);
-finish:
-	fibril_rwlock_write_unlock(&task_hash_table_lock);
-}
-
-void task_failed(task_id_t id)
-{
-	/* Mark task as failed. */
-	fibril_rwlock_write_lock(&task_hash_table_lock);
-	ht_link_t *link = hash_table_find(&task_hash_table, &id);
-	if (link == NULL) {
-		goto finish;
-	}
-
-	hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
-	
-	ht->failed = true;
-	// TODO design substitution for taskmon (monitoring) = invoke dump utility
-
-finish:
-	fibril_rwlock_write_unlock(&task_hash_table_lock);
-}
 
 /**
Index: uspace/srv/taskman/task.h
===================================================================
--- uspace/srv/taskman/task.h	(revision c675ab1ebb159b7e38a64765f63096588f7d9ff1)
+++ uspace/srv/taskman/task.h	(revision 2aaccd3307dcc5f0d64d0bf382939871466c33b9)
@@ -35,16 +35,40 @@
 #define TASKMAN_TASK_H__
 
+#include <abi/proc/task.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <fibril_synch.h>
 #include <ipc/common.h>
-#include <abi/proc/task.h>
+
+/** What type of retval from the task we have */
+typedef enum {
+	RVAL_UNSET,     /**< unset */
+	RVAL_SET,       /**< retval set, e.g. by server */
+	RVAL_SET_EXIT   /**< retval set, wait for expected task exit */
+} retval_t;
+
+/** Holds necessary information of each (registered) task. */
+typedef struct {
+	ht_link_t link;
+	
+	task_id_t id;          /**< Task id. */
+	task_exit_t exit;      /**< Task's uspace exit status. */
+	bool failed;           /**< Task failed (task can exit unexpectedly
+				    even w/out failure). */
+	retval_t retval_type;  /**< Task returned a value. */
+	int retval;            /**< The return value. */
+
+	link_t listeners;      /**< Link to listeners list. */
+	async_sess_t *sess;    /**< Session for notifications to task. */
+} task_t;
+
+extern hash_table_t task_hash_table;
+extern fibril_rwlock_t task_hash_table_lock;
 
 extern int task_init(void);
-extern void process_pending_wait(void);
 
-extern void wait_for_task(task_id_t, int, ipc_callid_t, ipc_call_t *);
-extern int task_set_retval(ipc_call_t *);
+extern task_t *task_get_by_id(task_id_t);
 
 extern int task_intro(ipc_call_t *, bool);
-extern void task_terminated(task_id_t, exit_reason_t);
-extern void task_failed(task_id_t);
 
 #endif
