Index: generic/include/proc/thread.h
===================================================================
--- generic/include/proc/thread.h	(revision 8adafa085f18d6a6e5ecb3525a4a78d4181cc769)
+++ generic/include/proc/thread.h	(revision fe196117136f8e73cbf82c36f721f7a0e27d83a0)
@@ -52,5 +52,6 @@
 	Ready,		/**< State of threads in a run queue. */
 	Entering,	/**< Threads are in this state before they are first readied. */
-	Exiting		/**< After a thread calls thread_exit(), it is put into Exiting state. */
+	Exiting,	/**< After a thread calls thread_exit(), it is put into Exiting state. */
+	Undead		/**< Threads that were not detached but exited are in the Undead state. */
 };
 
@@ -98,4 +99,6 @@
 	bool in_copy_to_uspace;
 
+	bool detached;				/**< If true, thread_join_timeout() cannot be used on this thread. */
+	waitq_t join_wq;			/**< Waitq for thread_join_timeout(). */
 
 	fpu_context_t *saved_fpu_context;
@@ -152,4 +155,7 @@
 extern void thread_usleep(__u32 usec);
 
+extern int thread_join_timeout(thread_t *t, __u32 usec, int flags);
+extern void thread_detach(thread_t *t);
+
 extern void thread_register_call_me(void (* call_me)(void *), void *call_me_with);
 extern void thread_print_list(void);
Index: generic/src/proc/scheduler.c
===================================================================
--- generic/src/proc/scheduler.c	(revision 8adafa085f18d6a6e5ecb3525a4a78d4181cc769)
+++ generic/src/proc/scheduler.c	(revision fe196117136f8e73cbf82c36f721f7a0e27d83a0)
@@ -41,4 +41,5 @@
 #include <mm/page.h>
 #include <mm/as.h>
+#include <time/delay.h>
 #include <arch/asm.h>
 #include <arch/faddr.h>
@@ -375,5 +376,27 @@
 
 		    case Exiting:
-			thread_destroy(THREAD);
+repeat:
+		    	if (THREAD->detached) {
+				thread_destroy(THREAD);
+			} else {
+				/*
+				 * The thread structure is kept allocated until somebody
+				 * calls thread_detach() on it.
+				 */
+				if (!spinlock_trylock(&THREAD->join_wq.lock)) {
+					/*
+					 * Avoid deadlock.
+					 */
+					spinlock_unlock(&THREAD->lock);
+					delay(10);
+					spinlock_lock(&THREAD->lock);
+					goto repeat;
+				}
+				_waitq_wakeup_unsafe(&THREAD->join_wq, false);
+				spinlock_unlock(&THREAD->join_wq.lock);
+				
+				THREAD->state = Undead;
+				spinlock_unlock(&THREAD->lock);
+			}
 			break;
 			
Index: generic/src/proc/thread.c
===================================================================
--- generic/src/proc/thread.c	(revision 8adafa085f18d6a6e5ecb3525a4a78d4181cc769)
+++ generic/src/proc/thread.c	(revision fe196117136f8e73cbf82c36f721f7a0e27d83a0)
@@ -64,5 +64,15 @@
 #include <errno.h>
 
-char *thread_states[] = {"Invalid", "Running", "Sleeping", "Ready", "Entering", "Exiting"}; /**< Thread states */
+
+/** Thread states */
+char *thread_states[] = {
+	"Invalid",
+	"Running",
+	"Sleeping",
+	"Ready",
+	"Entering",
+	"Exiting",
+	"Undead"
+}; 
 
 /** Lock protecting threads_head list. For locking rules, see declaration thereof. */
@@ -311,4 +321,7 @@
 	t->in_copy_to_uspace = false;
 	
+	t->detached = false;
+	waitq_initialize(&t->join_wq);
+	
 	t->rwlock_holder_type = RWLOCK_NONE;
 		
@@ -372,4 +385,70 @@
 {
 	thread_usleep(sec*1000000);
+}
+
+/** Wait for another thread to exit.
+ *
+ * @param t Thread to join on exit.
+ * @param usec Timeout in microseconds.
+ * @param flags Mode of operation.
+ *
+ * @return An error code from errno.h or an error code from synch.h.
+ */
+int thread_join_timeout(thread_t *t, __u32 usec, int flags)
+{
+	ipl_t ipl;
+	int rc;
+
+	if (t == THREAD)
+		return EINVAL;
+
+	/*
+	 * Since thread join can only be called once on an undetached thread,
+	 * the thread pointer is guaranteed to be still valid.
+	 */
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&t->lock);
+
+	ASSERT(!t->detached);
+	
+	(void) waitq_sleep_prepare(&t->join_wq);
+	spinlock_unlock(&t->lock);
+	
+	rc = waitq_sleep_timeout_unsafe(&t->join_wq, usec, flags);
+	
+	waitq_sleep_finish(&t->join_wq, rc, ipl);
+	
+	return rc;	
+}
+
+/** Detach thread.
+ *
+ * Mark the thread as detached, if the thread is already in the Undead state,
+ * deallocate its resources.
+ *
+ * @param t Thread to be detached.
+ */
+void thread_detach(thread_t *t)
+{
+	ipl_t ipl;
+
+	/*
+	 * Since the thread is expected to not be already detached,
+	 * pointer to it must be still valid.
+	 */
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&t->lock);
+	ASSERT(!t->detached);
+	if (t->state == Undead) {
+		thread_destroy(t);	/* unlocks &t->lock */
+		interrupts_restore(ipl);
+		return;
+	} else {
+		t->detached = true;
+	}
+	spinlock_unlock(&t->lock);
+	interrupts_restore(ipl);
 }
 
