Index: kernel/generic/include/adt/list.h
===================================================================
--- kernel/generic/include/adt/list.h	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/include/adt/list.h	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -181,5 +181,5 @@
 }
 
-#define list_get_instance(link,type,member) \
+#define list_get_instance(link, type, member) \
 	((type *)(((uint8_t *)(link)) - ((uint8_t *)&(((type *)NULL)->member))))
 
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/include/proc/task.h	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -65,6 +65,4 @@
 	
 	char *name;
-	/** Pointer to the main thread. */
-	struct thread *main_thread;
 	/** List of threads contained in this task. */
 	link_t th_head;
@@ -76,8 +74,8 @@
 	context_id_t context;	
 
-	/** If this is true, new threads can become part of the task. */
-	bool accept_new_threads;
 	/** Number of references (i.e. threads). */
-	count_t refcount;	
+	atomic_t refcount;
+	/** Number of threads that haven't exited yet. */
+	atomic_t lifecount;
 
 	/** Task capabilities. */
@@ -123,5 +121,4 @@
 extern cap_t cap_get(task_t *t);
 
-
 #ifndef task_create_arch
 extern void task_create_arch(task_t *t);
Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/include/proc/thread.h	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2001-2004 Jakub Jermar
+ * Copyright (c) 2001-2007 Jakub Jermar
  * All rights reserved.
  *
@@ -41,4 +41,5 @@
 #include <cpu.h>
 #include <synch/rwlock.h>
+#include <synch/spinlock.h>
 #include <adt/btree.h>
 #include <mm/slab.h>
@@ -81,14 +82,7 @@
 	/** After a thread calls thread_exit(), it is put into Exiting state. */
 	Exiting,
-	/** Threads that were not detached but exited are in the Undead state. */
-	Undead
+	/** Threads that were not detached but exited are in the JoinMe state. */
+	JoinMe
 } state_t;
-
-/** Join types. */
-typedef enum {
-	None,
-	TaskClnp,	/**< The thread will be joined by ktaskclnp thread. */
-	TaskGC		/**< The thread will be joined by ktaskgc thread. */
-} thread_join_type_t;
 
 /** Thread structure. There is one per thread. */
@@ -153,10 +147,10 @@
 	bool interrupted;			
 	
-	/** Who joinins the thread. */
-	thread_join_type_t join_type;
 	/** If true, thread_join_timeout() cannot be used on this thread. */
 	bool detached;
 	/** Waitq for thread_join_timeout(). */
 	waitq_t join_wq;
+	/** Link used in the joiner_head list. */
+	link_t joiner_link;
 
 	fpu_context_t *saved_fpu_context;
Index: kernel/generic/src/main/uinit.c
===================================================================
--- kernel/generic/src/main/uinit.c	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/src/main/uinit.c	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -46,4 +46,5 @@
 #include <userspace.h>
 #include <mm/slab.h>
+#include <arch.h>
 
 /** Thread used to bring up userspace thread.
@@ -55,10 +56,19 @@
 {
 	uspace_arg_t uarg;
+
+	/*
+	 * So far, we don't have a use for joining userspace threads so we
+	 * immediately detach each uinit thread. If joining of userspace threads
+	 * is required, some userspace API based on the kernel mechanism will
+	 * have to be implemented. Moreover, garbage collecting of threads that
+	 * didn't detach themselves and nobody else joined them will have to be
+	 * deployed for the event of forceful task termination.
+	 */
+	thread_detach(THREAD);
 	
 	uarg.uspace_entry = ((uspace_arg_t *) arg)->uspace_entry;
 	uarg.uspace_stack = ((uspace_arg_t *) arg)->uspace_stack;
 	uarg.uspace_uarg = ((uspace_arg_t *) arg)->uspace_uarg;
-	uarg.uspace_thread_function = NULL;
-	uarg.uspace_thread_arg = NULL;
+	uarg.uspace_thread_function = NULL; uarg.uspace_thread_arg = NULL;
 
 	free((uspace_arg_t *) arg);
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/src/proc/scheduler.c	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -406,5 +406,5 @@
 					 */
 					spinlock_unlock(&THREAD->lock);
-					delay(10);
+					delay(HZ);
 					spinlock_lock(&THREAD->lock);
 					DEADLOCK_PROBE(p_joinwq,
@@ -416,5 +416,5 @@
 				spinlock_unlock(&THREAD->join_wq.lock);
 				
-				THREAD->state = Undead;
+				THREAD->state = JoinMe;
 				spinlock_unlock(&THREAD->lock);
 			}
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/src/proc/task.c	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -57,5 +57,4 @@
 #include <func.h>
 #include <syscall/copy.h>
-#include <console/klog.h>
 
 #ifndef LOADED_PROG_STACK_PAGES_NO
@@ -79,7 +78,4 @@
 
 static task_id_t task_counter = 0;
-
-static void ktaskclnp(void *arg);
-static void ktaskgc(void *arg);
 
 /** Initialize tasks
@@ -165,10 +161,9 @@
 	ta->as = as;
 	ta->name = name;
-	ta->main_thread = NULL;
-	ta->refcount = 0;
+	atomic_set(&ta->refcount, 0);
+	atomic_set(&ta->lifecount, 0);
 	ta->context = CONTEXT;
 
 	ta->capabilities = 0;
-	ta->accept_new_threads = true;
 	ta->cycles = 0;
 	
@@ -192,8 +187,6 @@
 
 	spinlock_lock(&tasks_lock);
-
 	ta->taskid = ++task_counter;
 	btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL);
-
 	spinlock_unlock(&tasks_lock);
 	interrupts_restore(ipl);
@@ -208,7 +201,24 @@
 void task_destroy(task_t *t)
 {
+	/*
+	 * Remove the task from the task B+tree.
+	 */
+	spinlock_lock(&tasks_lock);
+	btree_remove(&tasks_btree, t->taskid, NULL);
+	spinlock_unlock(&tasks_lock);
+
+	/*
+	 * Perform architecture specific task destruction.
+	 */
 	task_destroy_arch(t);
+
+	/*
+	 * Free up dynamically allocated state.
+	 */
 	btree_destroy(&t->futexes);
 
+	/*
+	 * Drop our reference to the address space.
+	 */
 	if (atomic_predec(&t->as->refcount) == 0) 
 		as_destroy(t->as);
@@ -230,5 +240,5 @@
 	as_area_t *a;
 	int rc;
-	thread_t *t1, *t2;
+	thread_t *t;
 	task_t *task;
 	uspace_arg_t *kernel_uarg;
@@ -264,16 +274,9 @@
 	 * Create the main thread.
 	 */
-	t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
+	t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
 	    "uinit", false);
-	ASSERT(t1);
-	
-	/*
-	 * Create killer thread for the new task.
-	 */
-	t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc", true);
-	ASSERT(t2);
-	thread_ready(t2);
-
-	thread_ready(t1);
+	ASSERT(t);
+	
+	thread_ready(t);
 
 	return task;
@@ -348,4 +351,7 @@
 /** Kill task.
  *
+ * This function is idempotent.
+ * It signals all the task's threads to bail it out.
+ *
  * @param id ID of the task to be killed.
  *
@@ -356,5 +362,4 @@
 	ipl_t ipl;
 	task_t *ta;
-	thread_t *t;
 	link_t *cur;
 
@@ -364,5 +369,4 @@
 	ipl = interrupts_disable();
 	spinlock_lock(&tasks_lock);
-
 	if (!(ta = task_find_by_id(id))) {
 		spinlock_unlock(&tasks_lock);
@@ -370,28 +374,15 @@
 		return ENOENT;
 	}
-
+	spinlock_unlock(&tasks_lock);
+	
+	/*
+	 * Interrupt all threads except ktaskclnp.
+	 */
 	spinlock_lock(&ta->lock);
-	ta->refcount++;
-	spinlock_unlock(&ta->lock);
-
-	btree_remove(&tasks_btree, ta->taskid, NULL);
-	spinlock_unlock(&tasks_lock);
-	
-	t = thread_create(ktaskclnp, NULL, ta, 0, "ktaskclnp", true);
-	
-	spinlock_lock(&ta->lock);
-	ta->accept_new_threads = false;
-	ta->refcount--;
-
-	/*
-	 * Interrupt all threads except ktaskclnp.
-	 */	
 	for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
 		thread_t *thr;
-		bool  sleeping = false;
+		bool sleeping = false;
 		
 		thr = list_get_instance(cur, thread_t, th_link);
-		if (thr == t)
-			continue;
 			
 		spinlock_lock(&thr->lock);
@@ -404,11 +395,7 @@
 			waitq_interrupt_sleep(thr);
 	}
-	
 	spinlock_unlock(&ta->lock);
 	interrupts_restore(ipl);
 	
-	if (t)
-		thread_ready(t);
-
 	return 0;
 }
@@ -426,5 +413,6 @@
 	printf("taskid name       ctx address    as         cycles     threads "
 	    "calls  callee\n");
-	printf("------ ---------- --- ---------- ---------- ---------- ------- "	    "------ ------>\n");
+	printf("------ ---------- --- ---------- ---------- ---------- ------- "
+	    "------ ------>\n");
 
 	for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head;
@@ -465,134 +453,4 @@
 }
 
-/** Kernel thread used to cleanup the task after it is killed. */
-void ktaskclnp(void *arg)
-{
-	ipl_t ipl;
-	thread_t *t = NULL, *main_thread;
-	link_t *cur;
-	bool again;
-
-	thread_detach(THREAD);
-
-loop:
-	ipl = interrupts_disable();
-	spinlock_lock(&TASK->lock);
-	
-	main_thread = TASK->main_thread;
-	
-	/*
-	 * Find a thread to join.
-	 */
-	again = false;
-	for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
-		t = list_get_instance(cur, thread_t, th_link);
-
-		spinlock_lock(&t->lock);
-		if (t == THREAD) {
-			spinlock_unlock(&t->lock);
-			continue;
-		} else if (t == main_thread) {
-			spinlock_unlock(&t->lock);
-			continue;
-		} else if (t->join_type != None) {
-			spinlock_unlock(&t->lock);
-			again = true;
-			continue;
-		} else {
-			t->join_type = TaskClnp;
-			spinlock_unlock(&t->lock);
-			again = false;
-			break;
-		}
-	}
-	
-	spinlock_unlock(&TASK->lock);
-	interrupts_restore(ipl);
-	
-	if (again) {
-		/*
-		 * Other cleanup (e.g. ktaskgc) is in progress.
-		 */
-		scheduler();
-		goto loop;
-	}
-	
-	if (t != THREAD) {
-		ASSERT(t != main_thread);	/* uninit is joined and detached
-						 * in ktaskgc */
-		thread_join(t);
-		thread_detach(t);
-		goto loop;			/* go for another thread */
-	}
-	
-	/*
-	 * Now there are no other threads in this task
-	 * and no new threads can be created.
-	 */
-
-	ipc_cleanup();
-	futex_cleanup();
-	klog_printf("Cleanup of task %llu completed.", TASK->taskid);
-}
-
-/** Kernel thread used to kill the userspace task when its main thread exits.
- *
- * This thread waits until the main userspace thread (i.e. uninit) exits.
- * When this happens, the task is killed. In the meantime, exited threads
- * are garbage collected.
- *
- * @param arg Pointer to the thread structure of the task's main thread.
- */
-void ktaskgc(void *arg)
-{
-	thread_t *t = (thread_t *) arg;
-loop:	
-	/*
-	 * Userspace threads cannot detach themselves,
-	 * therefore the thread pointer is guaranteed to be valid.
-	 */
-	if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) ==
-	    ESYNCH_TIMEOUT) {	/* sleep uninterruptibly here! */
-		ipl_t ipl;
-		link_t *cur;
-		thread_t *thr = NULL;
-	
-		/*
-		 * The join timed out. Try to do some garbage collection of
-		 * Undead threads.
-		 */
-more_gc:		
-		ipl = interrupts_disable();
-		spinlock_lock(&TASK->lock);
-		
-		for (cur = TASK->th_head.next; cur != &TASK->th_head;
-		    cur = cur->next) {
-			thr = list_get_instance(cur, thread_t, th_link);
-			spinlock_lock(&thr->lock);
-			if (thr != t && thr->state == Undead &&
-			    thr->join_type == None) {
-				thr->join_type = TaskGC;
-				spinlock_unlock(&thr->lock);
-				break;
-			}
-			spinlock_unlock(&thr->lock);
-			thr = NULL;
-		}
-		spinlock_unlock(&TASK->lock);
-		interrupts_restore(ipl);
-		
-		if (thr) {
-			thread_join(thr);
-			thread_detach(thr);
-			scheduler();
-			goto more_gc;
-		}
-			
-		goto loop;
-	}
-	thread_detach(t);
-	task_kill(TASK->taskid);
-}
-
 /** @}
  */
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision ff3a34b23d37dee4709e858ec1869756a88b4172)
+++ kernel/generic/src/proc/thread.c	(revision ea7890e7d40b57d264d11b6a6ded9dd8c6454424)
@@ -68,4 +68,5 @@
 #include <syscall/copy.h>
 #include <errno.h>
+#include <console/klog.h>
 
 
@@ -78,5 +79,5 @@
 	"Entering",
 	"Exiting",
-	"Undead"
+	"JoinMe"
 }; 
 
@@ -329,5 +330,4 @@
 
 	t->interrupted = false;	
-	t->join_type = None;
 	t->detached = false;
 	waitq_initialize(&t->join_wq);
@@ -343,21 +343,4 @@
 	thread_create_arch(t);	
 
-	ipl = interrupts_disable();	 
-	spinlock_lock(&task->lock);
-	if (!task->accept_new_threads) {
-		spinlock_unlock(&task->lock);
-		slab_free(thread_slab, t);
-		interrupts_restore(ipl);
-		return NULL;
-	} else {
-		/*
-		 * Bump the reference count so that this task cannot be
-		 * destroyed while the new thread is being attached to it.
-		 */
-		task->refcount++;
-	}
-	spinlock_unlock(&task->lock);
-	interrupts_restore(ipl);
-
 	if (!(flags & THREAD_FLAG_NOATTACH))
 		thread_attach(t, task);
@@ -374,7 +357,5 @@
 void thread_destroy(thread_t *t)
 {
-	bool destroy_task = false;
-
-	ASSERT(t->state == Exiting || t->state == Undead);
+	ASSERT(t->state == Exiting || t->state == JoinMe);
 	ASSERT(t->task);
 	ASSERT(t->cpu);
@@ -396,11 +377,11 @@
 	spinlock_lock(&t->task->lock);
 	list_remove(&t->th_link);
-	if (--t->task->refcount == 0) {
-		t->task->accept_new_threads = false;
-		destroy_task = true;
-	}
 	spinlock_unlock(&t->task->lock);	
-	
-	if (destroy_task)
+
+	/*
+	 * t is guaranteed to be the very last thread of its task.
+	 * It is safe to destroy the task.
+	 */
+	if (atomic_predec(&t->task->refcount) == 0)
 		task_destroy(t->task);
 	
@@ -432,10 +413,9 @@
 	 * Attach to the current task.
 	 */
-	ipl = interrupts_disable();	 
+	ipl = interrupts_disable();
 	spinlock_lock(&task->lock);
-	ASSERT(task->refcount);
+	atomic_inc(&task->refcount);
+	atomic_inc(&task->lifecount);
 	list_append(&t->th_link, &task->th_head);
-	if (task->refcount == 1)
-		task->main_thread = t;
 	spinlock_unlock(&task->lock);
 
@@ -459,4 +439,19 @@
 {
 	ipl_t ipl;
+
+	if (atomic_predec(&TASK->lifecount) == 0) {
+		/*
+		 * We are the last thread in the task that still has not exited.
+		 * With the exception of the moment the task was created, new
+		 * threads can only be created by threads of the same task.
+		 * We are safe to perform cleanup.
+		 */
+		if (THREAD->flags & THREAD_FLAG_USPACE) {
+			ipc_cleanup();
+		        futex_cleanup();
+			klog_printf("Cleanup of task %llu completed.",
+			    TASK->taskid);
+		}
+	}
 
 restart:
@@ -469,4 +464,5 @@
 		goto restart;
 	}
+	
 	THREAD->state = Exiting;
 	spinlock_unlock(&THREAD->lock);
@@ -525,5 +521,5 @@
 /** Detach thread.
  *
- * Mark the thread as detached, if the thread is already in the Undead state,
+ * Mark the thread as detached, if the thread is already in the JoinMe state,
  * deallocate its resources.
  *
@@ -541,5 +537,5 @@
 	spinlock_lock(&t->lock);
 	ASSERT(!t->detached);
-	if (t->state == Undead) {
+	if (t->state == JoinMe) {
 		thread_destroy(t);	/* unlocks &t->lock */
 		interrupts_restore(ipl);
@@ -703,6 +699,4 @@
 			    sizeof(t->tid));
 			if (rc != 0) {
-				ipl_t ipl;
-
 				/*
 				 * We have encountered a failure, but the thread
@@ -712,23 +706,10 @@
 
 				/*
-				 * The new thread structure is initialized,
-				 * but is still not visible to the system.
+				 * The new thread structure is initialized, but
+				 * is still not visible to the system.
 				 * We can safely deallocate it.
 				 */
 				slab_free(thread_slab, t);
 			 	free(kernel_uarg);
-
-				/*
-				 * Now we need to decrement the task reference
-				 * counter. Because we are running within the
-				 * same task, thread t is not the last thread
-				 * in the task, so it is safe to merely
-				 * decrement the counter.
-				 */
-				ipl = interrupts_disable();
-				spinlock_lock(&TASK->lock);
-				TASK->refcount--;
-				spinlock_unlock(&TASK->lock);
-				interrupts_restore(ipl);
 
 				return (unative_t) rc;
