Index: uspace/libc/generic/thread.c
===================================================================
--- uspace/libc/generic/thread.c	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/libc/generic/thread.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -161,4 +161,35 @@
 }
 
+/** Detach thread.
+ *
+ * Currently not implemented.
+ *
+ * @param thread TID.
+ */
+void thread_detach(int thread)
+{
+}
+
+/** Join thread.
+ *
+ * Currently not implemented.
+ *
+ * @param thread TID.
+ *
+ * @return Thread exit status.
+ */
+int thread_join(int thread)
+{
+}
+
+/** Get current thread ID.
+ *
+ * @return Current thread ID.
+ */
+int thread_get_id(void)
+{
+	return __SYSCALL0(SYS_THREAD_GET_ID);
+}
+
 /** @}
  */
Index: uspace/libc/generic/time.c
===================================================================
--- uspace/libc/generic/time.c	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/libc/generic/time.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -109,11 +109,28 @@
 }
 
-/** Wait unconditionally for specified microseconds */
+/** Wait unconditionally for specified number of microseconds */
 void usleep(unsigned long usec)
 {
 	atomic_t futex = FUTEX_INITIALIZER;
 
-	futex_initialize(&futex,0);
+	futex_initialize(&futex, 0);
 	futex_down_timeout(&futex, usec, 0);
+}
+
+/** Wait unconditionally for specified number of seconds */
+unsigned int sleep(unsigned int seconds)
+{
+	atomic_t futex = FUTEX_INITIALIZER;
+
+	futex_initialize(&futex, 0);
+	
+	/* Sleep in 1000 second steps to support
+	   full argument range */
+	while (seconds > 0) {
+		unsigned int period = (seconds > 1000) ? 1000 : seconds;
+	
+		futex_down_timeout(&futex, period * 1000000, 0);
+		seconds -= period;
+	}
 }
 
Index: uspace/libc/include/thread.h
===================================================================
--- uspace/libc/include/thread.h	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/libc/include/thread.h	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -45,4 +45,7 @@
 extern int thread_create(void (* function)(void *arg), void *arg, char *name);
 extern void thread_exit(int status);
+extern void thread_detach(int thread);
+extern int thread_join(int thread);
+extern int thread_get_id(void);
 extern tcb_t * __make_tls(void);
 extern tcb_t * __alloc_tls(void **data, size_t size);
Index: uspace/libc/include/unistd.h
===================================================================
--- uspace/libc/include/unistd.h	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/libc/include/unistd.h	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -45,6 +45,7 @@
 extern ssize_t read(int fd, void * buf, size_t count);
 extern void _exit(int status);
-void *sbrk(ssize_t incr);
-void usleep(unsigned long usec);
+extern void *sbrk(ssize_t incr);
+extern void usleep(unsigned long usec);
+extern unsigned int sleep(unsigned int seconds);
 
 #endif
Index: uspace/tester/Makefile
===================================================================
--- uspace/tester/Makefile	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/tester/Makefile	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -42,5 +42,9 @@
 
 OUTPUT = tester
-SOURCES = tester.c
+SOURCES = tester.c \
+	thread/thread1.c \
+	print/print1.c \
+	ipc/register.c \
+	ipc/connect.c
 
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
Index: uspace/tester/ipc/connect.c
===================================================================
--- uspace/tester/ipc/connect.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/ipc/connect.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+
+char * test_connect(bool quiet)
+{
+	char c;
+	int svc;
+	int phid;
+
+	printf("Choose one service: 0:10000....9:10009\n");
+	do {
+		c = getchar();
+	} while (c < '0' || c > '9');
+	
+	svc = IPC_TEST_START + c - '0';
+	if (svc == myservice)
+		return "Currently cannot connect to myself, update test";
+	
+	printf("Connecting to %d..", svc);
+	phid = ipc_connect_me_to(PHONE_NS, svc, 0);
+	if (phid > 0) {
+		printf("phoneid: %d\n", phid);
+		phones[phid] = 1;
+	} else
+		return "Error";
+	
+	return NULL;
+}
Index: uspace/tester/ipc/connect.def
===================================================================
--- uspace/tester/ipc/connect.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/ipc/connect.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,6 @@
+{
+	"connect",
+	"IPC connection test (connect to other service)",
+	&test_connect,
+	true
+},
Index: uspace/tester/ipc/register.c
===================================================================
--- uspace/tester/ipc/register.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/ipc/register.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <async.h>
+#include "../tester.h"
+
+static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	ipcarg_t phonehash = icall->in_phone_hash;
+	int retval;
+	int i;
+
+	printf("Connected phone: %P, accepting\n", icall->in_phone_hash);
+	ipc_answer_fast(iid, 0, 0, 0);
+	for (i = 0; i < 1024; i++)
+		if (!connections[i]) {
+			connections[i] = phonehash;
+			break;
+		}
+	
+	while (1) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			printf("Phone (%P) hung up.\n", phonehash);
+			retval = 0;
+			break;
+		default:
+			printf("Received message from %P: %X\n", phonehash,callid);
+			for (i = 0; i < 1024; i++)
+				if (!callids[i]) {
+					callids[i] = callid;
+					break;
+				}
+			continue;
+		}
+		ipc_answer_fast(callid, retval, 0, 0);
+	}
+}
+
+char * test_register(bool quiet)
+{
+	int i;
+	
+	async_set_client_connection(client_connection);
+
+	for (i = IPC_TEST_START; i < IPC_TEST_START + 10; i++) {
+		ipcarg_t phonead;
+		int res = ipc_connect_to_me(PHONE_NS, i, 0, &phonead);
+		if (!res)
+			break;
+		printf("Failed registering as %d..:%d\n", i, res);
+	}
+	printf("Registered as service: %d\n", i);
+	myservice = i;
+	
+	return NULL;
+}
Index: uspace/tester/ipc/register.def
===================================================================
--- uspace/tester/ipc/register.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/ipc/register.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,6 @@
+{
+	"register",
+	"IPC registration test",
+	&test_register,
+	true
+},
Index: uspace/tester/print/print1.c
===================================================================
--- uspace/tester/print/print1.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/print/print1.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+
+#define BUFFER_SIZE 32
+
+char * test_print1(bool quiet)
+{
+	if (!quiet) {
+		int retval;
+		unsigned int nat = 0x12345678u;
+		
+		char buffer[BUFFER_SIZE];
+		
+		printf(" text 10.8s %*.*s \n", 5, 3, "text");
+		printf(" very long text 10.8s %10.8s \n", "very long text");
+		printf(" text 8.10s %8.10s \n", "text");
+		printf(" very long text 8.10s %8.10s \n", "very long text");
+		
+		printf(" char: c '%c', 3.2c '%3.2c', -3.2c '%-3.2c', 2.3c '%2.3c', -2.3c '%-2.3c' \n",'a', 'b', 'c', 'd', 'e' );
+		printf(" int: d '%d', 3.2d '%3.2d', -3.2d '%-3.2d', 2.3d '%2.3d', -2.3d '%-2.3d' \n",1, 1, 1, 1, 1 );
+		printf(" -int: d '%d', 3.2d '%3.2d', -3.2d '%-3.2d', 2.3d '%2.3d', -2.3d '%-2.3d' \n",-1, -1, -1, -1, -1 );
+		printf(" 0xint: x '%#x', 5.3x '%#5.3x', -5.3x '%#-5.3x', 3.5x '%#3.5x', -3.5x '%#-3.5x' \n",17, 17, 17, 17, 17 );
+		
+		printf("'%#llx' 64bit, '%#x' 32bit, '%#hhx' 8bit, '%#hx' 16bit, unative_t '%#zx'. '%#llx' 64bit and '%s' string.\n", 0x1234567887654321ll, 0x12345678, 0x12, 0x1234, nat, 0x1234567887654321ull, "Lovely string" );
+		
+		printf(" Print to NULL '%s'\n", NULL);
+		
+		retval = snprintf(buffer, BUFFER_SIZE, "Short text without parameters.");
+		printf("Result is: '%s', retval = %d\n", buffer, retval);
+		
+		retval = snprintf(buffer, BUFFER_SIZE, "Very very very long text without parameters.");
+		printf("Result is: '%s', retval = %d\n", buffer, retval);
+		
+		printf("Print short text to %d char long buffer via snprintf.\n", BUFFER_SIZE);
+		retval = snprintf(buffer, BUFFER_SIZE, "Short %s", "text");
+		printf("Result is: '%s', retval = %d\n", buffer, retval);
+		
+		printf("Print long text to %d char long buffer via snprintf.\n", BUFFER_SIZE);
+		retval = snprintf(buffer, BUFFER_SIZE, "Very long %s. This text`s length is more than %d. We are interested in the result.", "text" , BUFFER_SIZE);
+		printf("Result is: '%s', retval = %d\n", buffer, retval);
+	}
+	
+	return NULL;
+}
Index: uspace/tester/print/print1.def
===================================================================
--- uspace/tester/print/print1.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/print/print1.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,6 @@
+{
+	"print1",
+	"Printf test",
+	&test_print1,
+	true
+},
Index: uspace/tester/tester.c
===================================================================
--- uspace/tester/tester.c	(revision c9d2075542045c84bee4acd4517ca69262d86867)
+++ uspace/tester/tester.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2007 Martin Decky
  * All rights reserved.
  *
@@ -27,6 +28,6 @@
  */
 
-/** @addtogroup ippc IPC Tester
- * @brief	IPC tester and task faulter.
+/** @addtogroup tester User space Tester
+ * @brief	User space testing infrastructure.
  * @{
  */ 
@@ -35,242 +36,77 @@
  */
 
+#include <unistd.h>
 #include <stdio.h>
-#include <async.h>
-#include <ipc/ipc.h>
-#include <ipc/services.h>
-#include <errno.h>
+#include "tester.h"
 
-#define TEST_START       10000
-#define MAXLIST          4
+int myservice = 0;
+int phones[MAX_PHONES];
+int connections[MAX_CONNECTIONS];
+ipc_callid_t callids[MAX_CONNECTIONS];
 
-#define MSG_HANG_ME_UP   2000
+test_t tests[] = {
+#include "thread/thread1.def"
+#include "print/print1.def"
+#include "ipc/register.def"
+#include "ipc/connect.def"
+	{NULL, NULL, NULL}
+};
 
-static int connections[50];
-static ipc_callid_t callids[50];
-static int phones[20];
-static int myservice = 0;
+static bool run_test(test_t *test)
+{
+	printf("%s\t\t%s\n", test->name, test->desc);
+	
+	/* Execute the test */
+	char * ret = test->entry(false);
+	
+	if (ret == NULL) {
+		printf("Test passed\n\n");
+		return true;
+	}
 
-static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	ipc_call_t call;
-	ipcarg_t phonehash = icall->in_phone_hash;
-	int retval;
-	int i;
-
-	printf("Connected phone: %P, accepting\n", icall->in_phone_hash);
-	ipc_answer_fast(iid, 0, 0, 0);
-	for (i=0;i < 1024;i++)
-		if (!connections[i]) {
-			connections[i] = phonehash;
-			break;
-		}
-	
-	while (1) {
-		callid = async_get_call(&call);
-		switch (IPC_GET_METHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			printf("Phone (%P) hung up.\n", phonehash);
-			retval = 0;
-			break;
-		default:
-			printf("Received message from %P: %X\n", phonehash,callid);
-			for (i = 0; i < 1024; i++)
-				if (!callids[i]) {
-					callids[i] = callid;
-					break;
-				}
-			continue;
-		}
-		ipc_answer_fast(callid, retval, 0, 0);
-	}
+	printf("%s\n\n", ret);
+	return false;
 }
 
-static void printhelp(void)
+static void run_safe_tests(void)
 {
-	printf("? - help\n");
-	printf("c - connect to other service\n");
-	printf("h - hangup connection\n");
-	printf("a - send async message to other service\n");
-	printf("s - send sync message to other service\n");
-	printf("d - answer message that we have received\n");
-	printf("j - jump to endless loop\n");
-	printf("p - page fault\n");
-	printf("u - unaligned read\n");
 }
 
-static void callback(void *private, int retval, ipc_call_t *data)
+static void list_tests(void)
 {
-	printf("Received response to msg %d - retval: %d.\n", private,
-	       retval);
-}
-
-static void do_answer_msg(void)
-{
-	int i,cnt, errn = 0;
-	char c;
-
-	cnt = 0;
-	for (i = 0;i < 50; i++) {
-		if (callids[i]) {
-			printf("%d: %P\n", cnt, callids[i]);
-			cnt++;
-		}
-		if (cnt >= 10)
-			break;
-	}
-	if (!cnt)
-		return;
-	printf("Choose message:\n");
-	do {
-		c = getchar();
-	} while (c < '0' || (c-'0') >= cnt);
-	cnt = c - '0' + 1;
+	test_t *test;
+	char c = 'a';
 	
-	for (i = 0; cnt; i++)
-		if (callids[i])
-			cnt--;
-	i -= 1;
-
-	printf("Normal (n) or hangup (h) or error(e) message?\n");
-	do {
-		c = getchar();
-	} while (c != 'n' && c != 'h' && c != 'e');
-	if (c == 'n')
-		errn = 0;
-	else if (c == 'h')
-		errn = EHANGUP;
-	else if (c == 'e')
-		errn = ENOENT;
-	printf("Answering %P\n", callids[i]);
-	ipc_answer_fast(callids[i], errn, 0, 0);
-	callids[i] = 0;
-}
-
-static void do_send_msg(int async)
-{
-	int phoneid;
-	int res;
-	static int msgid = 1;
-	char c;
-
-	printf("Select phoneid to send msg: 2-9\n");
-	do {
-		c = getchar();
-	} while (c < '2' || c > '9');
-	phoneid = c - '0';
-
-	if (async) {
-		ipc_call_async(phoneid, 2000, 0, (void *)msgid, callback, 1);
-		printf("Async sent - msg %d\n", msgid);
-		msgid++;
-	} else {
-		printf("Sending msg...");
-		res = ipc_call_sync_2(phoneid, 2000, 0, 0, NULL, NULL);
-		printf("done: %d\n", res);
-	}
-}
-
-static void do_hangup(void)
-{
-	char c;
-	int res;
-	int phoneid;
-
-	printf("Select phoneid to hangup: 2-9\n");
-	do {
-		c = getchar();
-	} while (c < '2' || c > '9');
-	phoneid = c - '0';
+	for (test = tests; test->name != NULL; test++, c++)
+		printf("%c\t%s\t\t%s%s\n", c, test->name, test->desc, (test->safe ? "" : " (unsafe)"));
 	
-	printf("Hanging up...");
-	res = ipc_hangup(phoneid);
-	printf("done: %d\n", phoneid);
-}
-
-static void do_connect(void)
-{
-	char c;
-	int svc;
-	int phid;
-
-	printf("Choose one service: 0:10000....9:10009\n");
-	do {
-		c = getchar();
-	} while (c < '0' || c > '9');
-	svc = TEST_START + c - '0';
-	if (svc == myservice) {
-		printf("Currently cannot connect to myself, update test\n");
-		return;
-	}
-	printf("Connecting to %d..", svc);
-	phid = ipc_connect_me_to(PHONE_NS, svc, 0);
-	if (phid > 0) {
-		printf("phoneid: %d\n", phid);
-		phones[phid] = 1;
-	} else
-		printf("error: %d\n", phid);
+	printf("*\t\t\tRun all safe tests\n");
 }
 
 int main(void)
 {
-	ipcarg_t phonead;
-	int i;
-	char c;
-	int res;
-	volatile long long var;
-	volatile int var1;
-	
-	printf("********************************\n");
-	printf("***********IPC Tester***********\n");
-	printf("********************************\n");
-	
-	async_set_client_connection(client_connection);
-
-	for (i = TEST_START; i < TEST_START + 10; i++) {
-		res = ipc_connect_to_me(PHONE_NS, i, 0, &phonead);
-		if (!res)
-			break;
-		printf("Failed registering as %d..:%d\n", i, res);
-	}
-	printf("Registered as service: %d\n", i);
-	myservice = i;
-
-	printhelp();
 	while (1) {
+		char c;
+		test_t *test;
+		
+		list_tests();
+		printf("> ");
+		
 		c = getchar();
-		switch (c) {
-		case '?':
-			printhelp();
-			break;
-		case 'h':
-			do_hangup();
-			break;
-		case 'c':
-			do_connect();
-			break;
-		case 'a':
-			do_send_msg(1);
-			break;
-		case 's':
-			do_send_msg(0);
-			break;
-		case 'd':
-			do_answer_msg();
-			break;
-		case 'j':
-			printf("Entering infinite loop\n");
-			while (1)
-				;
-			break;
-		case 'p':
-			printf("Doing page fault\n");
-			*((char *)0) = 1;
-			printf("done\n");
-			break;
-		case 'u':
-			var1=*( (int *) ( ( (char *)(&var) ) + 1 ) );
-			break;
-		}
+		printf("%c\n", c);
+		
+		if ((c >= 'a') && (c <= 'z')) {
+			for (test = tests; test->name != NULL; test++, c--)
+				if (c == 'a')
+					break;
+			
+			if (c > 'a')
+				printf("Unknown test\n\n");
+			else
+				run_test(test);
+		} else if (c == '*')
+			run_safe_tests();
+		else
+			printf("Invalid test\n\n");
 	}
 }
@@ -278,3 +114,2 @@
 /** @}
  */
-
Index: uspace/tester/tester.h
===================================================================
--- uspace/tester/tester.h	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/tester.h	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007 Martin Decky
+ * 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 tester
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TESTER_H_
+#define TESTER_H_
+
+#include <types.h>
+#include <bool.h>
+#include <ipc/ipc.h>
+
+#define IPC_TEST_START	10000
+#define MAX_PHONES		20
+#define MAX_CONNECTIONS 50
+
+extern int myservice;
+extern int phones[MAX_PHONES];
+extern int connections[MAX_CONNECTIONS];
+extern ipc_callid_t callids[MAX_CONNECTIONS];
+
+typedef char * (* test_entry_t)(bool);
+
+typedef struct {
+	char * name;
+	char * desc;
+	test_entry_t entry;
+	bool safe;
+} test_t;
+
+extern char * test_thread1(bool quiet);
+extern char * test_print1(bool quiet);
+extern char * test_register(bool quiet);
+extern char * test_connect(bool quiet);
+
+extern test_t tests[];
+
+#endif
+
+/** @}
+ */
Index: uspace/tester/thread/thread1.c
===================================================================
--- uspace/tester/thread/thread1.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/thread/thread1.c	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005 Jakub Vana
+ * Copyright (c) 2005 Jakub Jermar
+ * 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.
+ */
+
+#define THREADS 5
+
+#include <atomic.h>
+#include <thread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+
+static atomic_t finish;
+static atomic_t threads_finished;
+static bool sh_quiet;
+
+static void threadtest(void *data)
+{
+	thread_detach(thread_get_id());
+
+	while (atomic_get(&finish)) {
+		if (!sh_quiet)
+			printf("%d\n", thread_get_id());
+		usleep(100);
+	}
+	atomic_inc(&threads_finished);
+}
+
+char * test_thread1(bool quiet)
+{
+	unsigned int i, total = 0;
+	sh_quiet = quiet;
+	
+	atomic_set(&finish, 1);
+	atomic_set(&threads_finished, 0);
+
+	for (i = 0; i < THREADS; i++) {  
+		int t;
+		if ((t = thread_create(threadtest, NULL, "threadtest")) < 0) {
+			if (!quiet)
+				printf("Could not create thread %d\n", i);
+			break;
+		}
+		total++;
+	}
+	
+	if (!quiet)
+		printf("Running threads for 10 seconds...\n");
+	sleep(10);
+	
+	atomic_set(&finish, 0);
+	while (atomic_get(&threads_finished) < total) {
+		if (!quiet)
+			printf("Threads left: %d\n", total - atomic_get(&threads_finished));
+		sleep(1);
+	}
+	
+	return NULL;
+}
Index: uspace/tester/thread/thread1.def
===================================================================
--- uspace/tester/thread/thread1.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
+++ uspace/tester/thread/thread1.def	(revision dd655970297ee2f6828bb8e35ef9b3c181b18b45)
@@ -0,0 +1,6 @@
+{
+	"thread1",
+	"Thread test",
+	&test_thread1,
+	true
+},
