Index: uspace/lib/c/generic/taskman.c
===================================================================
--- uspace/lib/c/generic/taskman.c	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/lib/c/generic/taskman.c	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -45,4 +45,8 @@
 
 async_sess_t *session_taskman = NULL;
+
+/*
+ * Private functions
+ */
 
 void __task_init(async_sess_t *sess)
@@ -119,4 +123,24 @@
 }
 
+/*
+ * Public functions
+ */
+
+int taskman_dump_events(void)
+{
+	assert(session_taskman);
+
+	async_exch_t *exch = async_exchange_begin(session_taskman);
+	int rc = async_req_0_0(exch, TASKMAN_DUMP_EVENTS);
+	taskman_exchange_end(exch);
+
+	return rc;
+}
+
+async_sess_t *taskman_get_session(void)
+{
+	return session_taskman;
+}
+
 /** Introduce as loader to taskman
  *
@@ -158,9 +182,4 @@
 }
 
-async_sess_t *taskman_get_session(void)
-{
-	return session_taskman;
-}
-
 
 
Index: uspace/lib/c/include/ipc/taskman.h
===================================================================
--- uspace/lib/c/include/ipc/taskman.h	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/lib/c/include/ipc/taskman.h	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -44,5 +44,6 @@
 	TASKMAN_EVENT_CALLBACK,
 	TASKMAN_NEW_TASK,
-	TASKMAN_I_AM_NS
+	TASKMAN_I_AM_NS,
+	TASKMAN_DUMP_EVENTS
 } taskman_request_t;
 
Index: uspace/lib/c/include/taskman.h
===================================================================
--- uspace/lib/c/include/taskman.h	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/lib/c/include/taskman.h	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -40,4 +40,6 @@
 #endif
 
+extern int taskman_dump_events(void);
+
 /* Internal functions to be used by loader only */
 #ifndef TASKMAN_DISABLE_ASYNC
Index: uspace/srv/taskman/event.c
===================================================================
--- uspace/srv/taskman/event.c	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/event.c	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -42,4 +42,5 @@
 #include "event.h"
 #include "task.h"
+#include "taskman.h"
 
 /** Pending task wait structure. */
@@ -85,7 +86,6 @@
 }
 
-static void event_notify(task_t *sender)
-{
-	// TODO should rlock task_hash_table?
+static void event_notify(task_t *sender, async_sess_t *sess)
+{
 	int flags = event_flags(sender);
 	if (flags == 0) {
@@ -93,20 +93,34 @@
 	}
 
+	async_exch_t *exch = async_exchange_begin(sess);
+	aid_t req = async_send_5(exch, TASKMAN_EV_TASK,
+	    LOWER32(sender->id),
+	    UPPER32(sender->id),
+	    flags,
+	    sender->exit,
+	    sender->retval,
+	    NULL);
+
+	async_exchange_end(exch);
+
+	/* Just send a notification and don't wait for anything */
+	async_forget(req);
+}
+
+/** Notify all registered listeners about sender's event
+ *
+ * @note Assumes share lock of task_hash_table is held.
+ */
+static void event_notify_all(task_t *sender)
+{
+	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);
-		aid_t req = async_send_5(exch, TASKMAN_EV_TASK,
-		    LOWER32(sender->id),
-		    UPPER32(sender->id),
-		    flags,
-		    sender->exit,
-		    sender->retval,
-		    NULL);
-
-		async_exchange_end(exch);
-
-		/* Just send a notification and don't wait for anything */
-		async_forget(req);
+		event_notify(sender, t->sess);
 	}
 	fibril_rwlock_read_unlock(&listeners_lock);
@@ -195,4 +209,44 @@
 }
 
+static bool dump_walker(task_t *t, void *arg)
+{
+	event_notify(t, arg);
+	return true;
+}
+
+void dump_events(task_id_t receiver_id, ipc_callid_t iid)
+{
+	int rc = EOK;
+	/*
+	 * We have shared lock of tasks structures so that we can guarantee
+	 * that dump receiver will receive tasks correctly ordered (retval,
+	 * exit updates are serialized via exclusive lock).
+	 */
+	fibril_rwlock_read_lock(&task_hash_table_lock);
+
+	task_t *receiver = task_get_by_id(receiver_id);
+	if (receiver == NULL) {
+		rc = ENOENT;
+		goto finish;
+	}
+	if (receiver->sess == NULL) {
+		rc = ENOENT;
+		goto finish;
+	}
+
+	/*
+	 * Answer caller first, so that they are not unnecessarily waiting
+	 * while we dump events.
+	 */
+	async_answer_0(iid, rc);
+	task_foreach(&dump_walker, receiver->sess);
+
+finish:
+	fibril_rwlock_read_unlock(&task_hash_table_lock);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+	}
+}
+
 void wait_for_task(task_id_t id, int flags, ipc_callid_t callid,
      task_id_t waiter_id)
@@ -284,5 +338,5 @@
 	t->retval_type = wait_for_exit ? RVAL_SET_EXIT : RVAL_SET;
 	
-	event_notify(t);
+	event_notify_all(t);
 	process_pending_wait();
 	
@@ -313,12 +367,17 @@
 	}
 
-	event_notify(t);
-	process_pending_wait();
-
-	hash_table_remove_item(&task_hash_table, &t->link);
-
+	/*
+	 * First remove terminated task from listeners and only after that
+	 * notify all others.
+	 */
 	fibril_rwlock_write_lock(&listeners_lock);
 	list_remove(&t->listeners);
 	fibril_rwlock_write_unlock(&listeners_lock);
+
+	event_notify_all(t);
+	process_pending_wait();
+
+	/* Eventually, get rid of task_t. */
+	task_remove(&t);
 
 finish:
Index: uspace/srv/taskman/event.h
===================================================================
--- uspace/srv/taskman/event.h	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/event.h	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -42,4 +42,5 @@
 
 extern int event_register_listener(task_id_t, async_sess_t *);
+extern void dump_events(task_id_t, ipc_callid_t);
 extern void wait_for_task(task_id_t, int, ipc_callid_t, task_id_t);
 extern int task_set_retval(task_id_t, int, bool);
Index: uspace/srv/taskman/main.c
===================================================================
--- uspace/srv/taskman/main.c	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/main.c	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -54,6 +54,4 @@
 #include "taskman.h"
 
-//#define DPRINTF(...) printf(__VA_ARGS__)
-#define DPRINTF(...) /* empty */
 
 typedef struct {
@@ -199,4 +197,11 @@
 }
 
+static void taskman_ctl_dump_events(ipc_callid_t iid, ipc_call_t *icall)
+{
+	DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
+
+	dump_events(icall->in_task_id, iid);
+}
+
 static void task_exit_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
@@ -257,4 +262,7 @@
 	case TASKMAN_EVENT_CALLBACK:
 		taskman_ctl_ev_callback(iid, icall);
+		break;
+	case TASKMAN_DUMP_EVENTS:
+		taskman_ctl_dump_events(iid, icall);
 		break;
 	default:
@@ -340,5 +348,5 @@
 	/* Initialization */
 	prodcons_initialize(&sess_queue);
-	int rc = task_init();
+	int rc = tasks_init();
 	if (rc != EOK) {
 		return rc;
Index: uspace/srv/taskman/task.c
===================================================================
--- uspace/srv/taskman/task.c	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/task.c	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -42,10 +42,25 @@
 #include "taskman.h"
 
-static size_t task_key_hash(void *key)
+typedef struct {
+	task_walker_t walker;
+	void *arg;
+} walker_context_t;
+	
+/*
+ * Forwards
+ */
+
+static void task_destroy(task_t **);
+
+/*
+ * Hash table functions
+ */
+
+static size_t ht_task_key_hash(void *key)
 {
 	return *(task_id_t*)key;
 }
 
-static size_t task_hash(const ht_link_t  *item)
+static size_t ht_task_hash(const ht_link_t  *item)
 {
 	task_t *ht = hash_table_get_inst(item, task_t, link);
@@ -53,5 +68,5 @@
 }
 
-static bool task_key_equal(void *key, const ht_link_t *item)
+static bool ht_task_key_equal(void *key, const ht_link_t *item)
 {
 	task_t *ht = hash_table_get_inst(item, task_t, link);
@@ -60,75 +75,25 @@
 
 /** Perform actions after removal of item from the hash table. */
-static void task_remove(ht_link_t *item)
-{
-	free(hash_table_get_inst(item, task_t, link));
+static void ht_task_remove(ht_link_t *item)
+{
+	task_t *t = hash_table_get_inst(item, task_t, link);
+	task_destroy(&t);
 }
 
 /** Operations for task hash table. */
 static hash_table_ops_t task_hash_table_ops = {
-	.hash = task_hash,
-	.key_hash = task_key_hash,
-	.key_equal = task_key_equal,
+	.hash = ht_task_hash,
+	.key_hash = ht_task_key_hash,
+	.key_equal = ht_task_key_equal,
 	.equal = NULL,
-	.remove_callback = task_remove
+	.remove_callback = ht_task_remove
 };
 
 /** Task hash table structure. */
-hash_table_t task_hash_table;
+static hash_table_t task_hash_table;
 fibril_rwlock_t task_hash_table_lock;
 
-int task_init(void)
-{
-	if (!hash_table_create(&task_hash_table, 0, 0, &task_hash_table_ops)) {
-		printf(NAME ": No memory available for tasks\n");
-		return ENOMEM;
-	}
-
-	fibril_rwlock_initialize(&task_hash_table_lock);
-	
-	return EOK;
-}
-
-/** Find task by its ID
- *
- * Assumes held lock of task_hash_table.
- *
- * @param[in]  id
- * @return task structure
- * @return NULL when no task with given ID exists
- */
-task_t *task_get_by_id(task_id_t id)
-{
-	ht_link_t *link = hash_table_find(&task_hash_table, &id);
-	if (!link) {
-		return NULL;
-	}
-	
-	task_t *t = hash_table_get_inst(link, task_t, link);
-	return t;
-}
-
-int task_intro(task_id_t id)
-{
-	int rc = EOK;
-
-	fibril_rwlock_write_lock(&task_hash_table_lock);
-
-	task_t *t = task_get_by_id(id);
-	if (t != NULL) {
-		rc = EEXISTS;
-		goto finish;
-	}
-	
-	t = malloc(sizeof(task_t));
-	if (t == NULL) {
-		rc = ENOMEM;
-		goto finish;
-	}
-
-	/*
-	 * Insert into the main table.
-	 */
-	t->id = id;
+static void task_init(task_t *t)
+{
 	t->exit = TASK_EXIT_RUNNING;
 	t->failed = false;
@@ -137,7 +102,119 @@
 	link_initialize(&t->listeners);
 	t->sess = NULL;
+}
+
+static void task_destroy(task_t **t_ptr)
+{
+	task_t *t = *t_ptr;
+	if (t == NULL) {
+		return;
+	}
+
+	if (t->sess != NULL) {
+		async_hangup(t->sess);
+	}
+	free(t);
+
+	*t_ptr = NULL;
+}
+
+int tasks_init(void)
+{
+	if (!hash_table_create(&task_hash_table, 0, 0, &task_hash_table_ops)) {
+		printf(NAME ": No memory available for tasks\n");
+		return ENOMEM;
+	}
+
+	fibril_rwlock_initialize(&task_hash_table_lock);
+	
+	return EOK;
+}
+
+/** Find task by its ID
+ *
+ * Assumes held lock of task_hash_table.
+ *
+ * @param[in]  id
+ * @return task structure
+ * @return NULL when no task with given ID exists
+ */
+task_t *task_get_by_id(task_id_t id)
+{
+	ht_link_t *link = hash_table_find(&task_hash_table, &id);
+	if (!link) {
+		return NULL;
+	}
+	
+	task_t *t = hash_table_get_inst(link, task_t, link);
+	return t;
+}
+
+static bool internal_walker(ht_link_t *ht_link, void *arg)
+{
+	task_t *t = hash_table_get_inst(ht_link, task_t, link);
+	walker_context_t *ctx = arg;
+	return ctx->walker(t, ctx->arg);
+}
+
+/** Iterate over all tasks
+ *
+ * @note Assumes task_hash_table lock is held.
+ *
+ * @param[in]  walker
+ * @param[in]  arg     generic argument passed to walker function
+ */
+void task_foreach(task_walker_t walker, void *arg)
+{
+	walker_context_t ctx;
+	ctx.walker = walker;
+	ctx.arg = arg;
+
+	hash_table_apply(&task_hash_table, &internal_walker, &ctx);
+}
+
+/** Remove task from our structures
+ *
+ * @note Assumes task_hash_table exclusive lock is held.
+ *
+ * @param[in|out]  ptr_t  Pointer to task pointer that should be removed, nulls
+ *                        task pointer.
+ */
+void task_remove(task_t **ptr_t)
+{
+	task_t *t = *ptr_t;
+	if (t == NULL) {
+		return;
+	}
+
+	hash_table_remove_item(&task_hash_table, &t->link);
+	*ptr_t = NULL;
+}
+
+int task_intro(task_id_t id)
+{
+	int rc = EOK;
+
+	fibril_rwlock_write_lock(&task_hash_table_lock);
+
+	task_t *t = task_get_by_id(id);
+	if (t != NULL) {
+		rc = EEXISTS;
+		goto finish;
+	}
+	
+	t = malloc(sizeof(task_t));
+	if (t == NULL) {
+		rc = ENOMEM;
+		goto finish;
+	}
+
+	/*
+	 * Insert into the main table.
+	 */
+	task_init(t);
+	t->id = id;
 
 	hash_table_insert(&task_hash_table, &t->link);
-	printf("%s: %llu\n", __func__, t->id);
+	DPRINTF("%s: %llu\n", __func__, t->id);
 	
 finish:
Index: uspace/srv/taskman/task.h
===================================================================
--- uspace/srv/taskman/task.h	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/task.h	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -63,10 +63,15 @@
 } task_t;
 
-extern hash_table_t task_hash_table;
+typedef bool (* task_walker_t)(task_t *, void *);
+
 extern fibril_rwlock_t task_hash_table_lock;
 
-extern int task_init(void);
+extern int tasks_init(void);
 
 extern task_t *task_get_by_id(task_id_t);
+
+extern void task_foreach(task_walker_t, void *);
+
+extern void task_remove(task_t **);
 
 extern int task_intro(task_id_t);
Index: uspace/srv/taskman/taskman.h
===================================================================
--- uspace/srv/taskman/taskman.h	(revision 130ba463e3386c6101b644aaade419f2b11e0a58)
+++ uspace/srv/taskman/taskman.h	(revision 4667b5c778d8547d60131d558541b4ad6fe29c11)
@@ -34,5 +34,10 @@
 #define TASKMAN_TASKMAN_H__
 
+#include <stdio.h>
+
 #define NAME  "taskman"
+
+//#define DPRINTF(...) printf(__VA_ARGS__)
+#define DPRINTF(...) /* empty */
 
 #endif
