Index: Makefile
===================================================================
--- Makefile	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ Makefile	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -36,6 +36,6 @@
 	softint \
 	softfloat \
-	libadt \
 	init \
+	test \
 	ns \
 	fb
Index: fb/fb.c
===================================================================
--- fb/fb.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ fb/fb.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -45,11 +45,7 @@
 
 #include <kernel/errno.h>
-
+#include <async.h>
 
 #include "fb.h"
-
-
-
-#define pl /*printf("FB:L:%d\n",(int)__LINE__);*/
 
 #define EFB (-1)
@@ -80,9 +76,6 @@
 
 
-
-
-int main(int argc, char *argv[])
-{
-	
+static int init_fb(void)
+{
 	__address fb_ph_addr;
 	unsigned int fb_width;
@@ -92,8 +85,8 @@
 	__address fb_addr;
 	int a=0;
-
-
-	if(!sysinfo_value("fb")) return -1;
-	
+	int i,j,k;
+	int w;
+	char text[]="HelenOS Framebuffer driver\non Virtual Framebuffer\nVFB ";
+
 	fb_ph_addr=sysinfo_value("fb.address.physical");
 	fb_width=sysinfo_value("fb.width");
@@ -105,7 +98,7 @@
 
 
-
+	
 	map_physmem(task_get_id(),(void *)((__address)fb_ph_addr),(void *)fb_addr,
-		(fb_scanline*fb_height+PAGE_SIZE-1)>>PAGE_WIDTH,1);
+		    (fb_scanline*fb_height+PAGE_SIZE-1)>>PAGE_WIDTH,1);
 	
 	fb_init(0,fb_addr, fb_width, fb_height, fb_bpp, fb_scanline,
@@ -115,31 +108,55 @@
 	fb_putchar(0,' ');
 
-
-	{
-		int i,j;
-
-		for(i=0;i<H_NO_VFBS;i++)
-			for(j=0;j<V_NO_VFBS;j++)
-			{
-	
-				int w=create_window(0,(fb_width/H_NO_VFBS)*i+SPACING,
-					(fb_height/V_NO_VFBS)*j+SPACING,(fb_width/H_NO_VFBS)-2*SPACING ,
-						(fb_height/V_NO_VFBS)-2*SPACING,mod_col(DEFAULT_BGCOLOR,/*i+j*H_NO_VFBS*/0),
-							mod_col(DEFAULT_FGCOLOR,/*i+j*H_NO_VFBS*/0),
-								mod_col(DEFAULT_LOGOCOLOR,/*i+j*H_NO_VFBS)*/0));
-
-				if(w==EFB) return -1;
-
-				{
-					char text[]="Hello, World from\nHelenOS Framebuffer driver\non Virtual Framebuffer\nVFB ";
-					int i;
-					for(i=0;text[i];i++) fb_putchar(w,text[i]);
-					fb_putchar(w,w+'0');
-					fb_putchar(w,'\n');
-				}
-			}
+	for(i=0;i<H_NO_VFBS;i++)
+		for(j=0;j<V_NO_VFBS;j++) {
+			w = create_window(0,(fb_width/H_NO_VFBS)*i+SPACING,
+					  (fb_height/V_NO_VFBS)*j+SPACING,(fb_width/H_NO_VFBS)-2*SPACING ,
+					  (fb_height/V_NO_VFBS)-2*SPACING,mod_col(DEFAULT_BGCOLOR,/*i+j*H_NO_VFBS*/0),
+					  mod_col(DEFAULT_FGCOLOR,/*i+j*H_NO_VFBS*/0),
+					  mod_col(DEFAULT_LOGOCOLOR,/*i+j*H_NO_VFBS)*/0));
+			
+			if( w== EFB)
+				return -1;
+			
+			for(k=0;text[k];k++) 
+				fb_putchar(w,text[k]);
+			fb_putchar(w,w+'0');
+			fb_putchar(w,'\n');
+		}
+	return 0;
+}
+
+int vfb_no = 1;
+void client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	int vfb = vfb_no++;
+
+	if (vfb > 9) {
+		ipc_answer_fast(iid, ELIMIT, 0,0);
+		return;
 	}
-
-
+	ipc_answer_fast(iid, 0, 0, 0);
+
+	while (1) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			ipc_answer_fast(callid,0,0,0);
+			return; /* Exit thread */
+
+		case FB_PUTCHAR:
+			ipc_answer_fast(callid,0,0,0);
+			fb_putchar(vfb,IPC_GET_ARG2(call));
+			break;
+		default:
+			ipc_answer_fast(callid,ENOENT,0,0);
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
 	ipc_call_t call;
 	ipc_callid_t callid;
@@ -151,51 +168,14 @@
 	ipcarg_t retval, arg1, arg2;
 
+	if(!sysinfo_value("fb")) return -1;
 
 
 	if ((res = ipc_connect_to_me(PHONE_NS, SERVICE_VIDEO, 0, &phonead)) != 0) 
-	{
 		return -1;
-	};
-
-		
-	while (1) {
-		static int vfb_no=1;
-
-		callid = ipc_wait_for_call(&call);
-	//	printf("%s:Call phone=%lX..", NAME, call.in_phone_hash);
-		switch (IPC_GET_METHOD(call)&((1<<METHOD_WIDTH)-1)) {
-			case IPC_M_PHONE_HUNGUP:
-//				fb_putchar(4,((a++)&15)+'A');
-				
-				retval = 0;
-				break;
-			case IPC_M_CONNECT_ME_TO:
-					retval = 0;
-//				fb_putchar(1,((a++)&15)+'A');
-				break;
-			case FB_GET_VFB:
-				retval = 0;
-				arg1 = vfb_no++;	
-//				fb_putchar(2,((a++)&15)+'A');
-				
-				break;
-
-			case FB_PUTCHAR:
-				retval = 0;
-				fb_putchar(IPC_GET_ARG1(call),IPC_GET_ARG2(call));
-//				fb_putchar(2,((a++)&15)+'A');
-				break;
-
-			default:
-				retval = ENOENT;
-//				fb_putchar(3,((a++)&15)+'A');
-				break;
-		}
-
-		if (! (callid & IPC_CALLID_NOTIFICATION)) {
-			ipc_answer_fast(callid, retval, arg1, arg2);
-		}
-	}
-
+	
+	init_fb();
+
+	async_manager();
+	/* Never reached */
 	return 0;
 }
@@ -310,5 +290,4 @@
 	FB(item,fbaddress)[startbyte + 0] = BLUE(color, 8);
 #endif
-																								
 
 }
@@ -372,5 +351,5 @@
 	for (y = 0; y < FB(item,yres); y++)
 	{
-		clear_line(item,y); pl
+		clear_line(item,y);
 	}	
 }
@@ -554,12 +533,12 @@
 
 		
-	FB(item,fbaddress) = (unsigned char *) addr; pl
-	FB(item,xres) = x; pl
-	FB(item,yres) = y; pl
-	FB(item,scanline) = scan; pl
-	
-	
-	FB(item,rows) = y / FONT_SCANLINES; pl
-	FB(item,columns) = x / COL_WIDTH; pl
+	FB(item,fbaddress) = (unsigned char *) addr;
+	FB(item,xres) = x;
+	FB(item,yres) = y;
+	FB(item,scanline) = scan;
+	
+	
+	FB(item,rows) = y / FONT_SCANLINES;
+	FB(item,columns) = x / COL_WIDTH;
 
 	FB(item,BGCOLOR)=BGCOLOR;
@@ -568,7 +547,7 @@
 
 
-	clear_screen(item); pl
-	draw_logo(item,FB(item,xres) - helenos_width, 0); pl
-	invert_cursor(item); pl
+	clear_screen(item);
+	draw_logo(item,FB(item,xres) - helenos_width, 0);
+	invert_cursor(item);
 
 }
Index: kbd/generic/kbd.c
===================================================================
--- kbd/generic/kbd.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ kbd/generic/kbd.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -37,5 +37,5 @@
 #include <kbd.h>
 #include <key_buffer.h>
-#include <fifo.h>
+#include <libadt/fifo.h>
 
 #define NAME "KBD"
Index: kbd/generic/key_buffer.c
===================================================================
--- kbd/generic/key_buffer.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ kbd/generic/key_buffer.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -28,5 +28,5 @@
 
 #include <key_buffer.h>
-#include <fifo.h>
+#include <libadt/fifo.h>
 
 #define KBD_BUFFER_SIZE 128 /**< Size of buffer for pressed keys */
Index: badt/Makefile
===================================================================
--- libadt/Makefile	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,72 +1,0 @@
-#
-# Copyright (C) 2005 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.
-#
-
-## Common compiler flags
-#
-
-LIBC_PREFIX = ../libc
-## Setup toolchain
-#
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -Iinclude
-
-## Sources
-#
-
-GENERIC_SOURCES = \
-	generic/list.c \
-	generic/hash_table.c
-
-GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES)))
-
-.PHONY: all clean depend
-
-all: libadt.a
-
--include Makefile.depend
-
-clean:
-	-rm -f libadt.a Makefile.depend
-	find generic/ -name '*.o' -follow -exec rm \{\} \;
-
-depend:
-	-makedepend $(DEFS) $(CFLAGS) -f - $(GENERIC_SOURCES) > Makefile.depend 2> /dev/null
-
-libadt.a: depend $(ARCH_OBJECTS) $(GENERIC_OBJECTS)
-	$(AR) rc libadt.a $(ARCH_OBJECTS) $(GENERIC_OBJECTS)
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
Index: badt/generic/hash_table.c
===================================================================
--- libadt/generic/hash_table.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,170 +1,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/*
- * This is an implementation of generic chained hash table.
- */
-
-#include <hash_table.h>
-#include <list.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-/** Create chained hash table.
- *
- * @param h Hash table structure. Will be initialized by this call.
- * @param m Number of slots in the hash table.
- * @param max_keys Maximal number of keys needed to identify an item.
- * @param op Hash table operations structure.
- * @return true on success
- */
-int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op)
-{
-	hash_count_t i;
-
-	assert(h);
-	assert(op && op->hash && op->compare);
-	assert(max_keys > 0);
-	
-	h->entry = malloc(m * sizeof(link_t));
-	if (!h->entry) {
-		printf("cannot allocate memory for hash table\n");
-		return false;
-	}
-	memset((void *) h->entry, 0,  m * sizeof(link_t));
-	
-	for (i = 0; i < m; i++)
-		list_initialize(&h->entry[i]);
-	
-	h->entries = m;
-	h->max_keys = max_keys;
-	h->op = op;
-	return true;
-}
-
-/** Insert item into hash table.
- *
- * @param h Hash table.
- * @param hey Array of all keys necessary to compute hash index.
- * @param item Item to be inserted into the hash table.
- */
-void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item)
-{
-	hash_index_t chain;
-
-	assert(item);
-	assert(h && h->op && h->op->hash && h->op->compare);
-
-	chain = h->op->hash(key);
-	assert(chain < h->entries);
-	
-	list_append(item, &h->entry[chain]);
-}
-
-/** Search hash table for an item matching keys.
- *
- * @param h Hash table.
- * @param key Array of all keys needed to compute hash index.
- *
- * @return Matching item on success, NULL if there is no such item.
- */
-link_t *hash_table_find(hash_table_t *h, unsigned long key[])
-{
-	link_t *cur;
-	hash_index_t chain;
-
-	assert(h && h->op && h->op->hash && h->op->compare);
-
-	chain = h->op->hash(key);
-	assert(chain < h->entries);
-	
-	for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
-		if (h->op->compare(key, h->max_keys, cur)) {
-			/*
-			 * The entry is there.
-			 */
-			return cur;
-		}
-	}
-	
-	return NULL;
-}
-
-/** Remove all matching items from hash table.
- *
- * For each removed item, h->remove_callback() is called.
- *
- * @param h Hash table.
- * @param key Array of keys that will be compared against items of the hash table.
- * @param keys Number of keys in the 'key' array.
- */
-void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys)
-{
-	hash_index_t chain;
-	link_t *cur;
-
-	assert(h && h->op && h->op->hash && h->op->compare && h->op->remove_callback);
-	assert(keys <= h->max_keys);
-	
-	if (keys == h->max_keys) {
-
-		/*
-		 * All keys are known, hash_table_find() can be used to find the entry.
-		 */
-	
-		cur = hash_table_find(h, key);
-		if (cur) {
-			list_remove(cur);
-			h->op->remove_callback(cur);
-		}
-		return;
-	}
-	
-	/*
-	 * Fewer keys were passed.
-	 * Any partially matching entries are to be removed.
-	 */
-	for (chain = 0; chain < h->entries; chain++) {
-		for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
-			if (h->op->compare(key, keys, cur)) {
-				link_t *hlp;
-				
-				hlp = cur;
-				cur = cur->prev;
-				
-				list_remove(hlp);
-				h->op->remove_callback(hlp);
-				
-				continue;
-			}
-		}
-	}
-}
Index: badt/generic/list.c
===================================================================
--- libadt/generic/list.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/*
- * Copyright (C) 2004 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.
- */
-
-#include <list.h>
-
-
-/** Check for membership
- *
- * Check whether link is contained in the list head.
- * The membership is defined as pointer equivalence.
- *
- * @param link Item to look for.
- * @param head List to look in.
- *
- * @return true if link is contained in head, false otherwise.
- *
- */
-int list_member(const link_t *link, const link_t *head)
-{
-	int found = false;
-	link_t *hlp = head->next;
-	
-	while (hlp != head) {
-		if (hlp == link) {
-			found = true;
-			break;
-		}
-		hlp = hlp->next;
-	}
-	
-	return found;
-}
-
-
-/** Concatenate two lists
- *
- * Concatenate lists head1 and head2, producing a single
- * list head1 containing items from both (in head1, head2
- * order) and empty list head2.
- *
- * @param head1 First list and concatenated output
- * @param head2 Second list and empty output.
- *
- */
-void list_concat(link_t *head1, link_t *head2)
-{
-	if (list_empty(head2))
-		return;
-
-	head2->next->prev = head1->prev;
-	head2->prev->next = head1;	
-	head1->prev->next = head2->next;
-	head1->prev = head2->prev;
-	list_initialize(head2);
-}
Index: badt/include/fifo.h
===================================================================
--- libadt/include/fifo.h	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,115 +1,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/*
- * This implementation of FIFO stores values in an array
- * (static or dynamic). As such, these FIFOs have upper bound
- * on number of values they can store. Push and pop operations
- * are done via accessing the array through head and tail indices.
- * Because of better operation ordering in fifo_pop(), the access
- * policy for these two indices is to 'increment (mod size of FIFO)
- * and use'.
- */
-
-#ifndef __FIFO_H__
-#define __FIFO_H__
-
-#include <malloc.h>
-
-typedef unsigned long fifo_count_t;
-typedef unsigned long fifo_index_t;
-
-/** Create and initialize static FIFO.
- *
- * FIFO is allocated statically.
- * This macro is suitable for creating smaller FIFOs.
- *
- * @param name Name of FIFO.
- * @param t Type of values stored in FIFO.
- * @param itms Number of items that can be stored in FIFO.
- */
-#define FIFO_INITIALIZE_STATIC(name, t, itms)		\
-	struct {					\
-		t fifo[(itms)];				\
-		fifo_count_t items;			\
-		fifo_index_t head;			\
-		fifo_index_t tail;			\
-	} name = {					\
-		.items = (itms),			\
-		.head = 0,				\
-		.tail = 0				\
-	}
-
-/** Create and prepare dynamic FIFO.
- *
- * FIFO is allocated dynamically.
- * This macro is suitable for creating larger FIFOs. 
- *
- * @param name Name of FIFO.
- * @param t Type of values stored in FIFO.
- * @param itms Number of items that can be stored in FIFO.
- */
-#define FIFO_INITIALIZE_DYNAMIC(name, t, itms)		\
-	struct {					\
-		t *fifo;				\
-		fifo_count_t items;			\
-		fifo_index_t head;			\
-		fifo_index_t tail;			\
-	} name = {					\
-		.fifo = NULL,				\
-		.items = (itms),			\
-		.head = 0,				\
-		.tail = 0				\
-	}
-
-/** Pop value from head of FIFO.
- *
- * @param name FIFO name.
- *
- * @return Leading value in FIFO.
- */
-#define fifo_pop(name) \
-	name.fifo[name.head = (name.head + 1) < name.items ? (name.head + 1) : 0]
-
-/** Push value to tail of FIFO.
- *
- * @param name FIFO name.
- * @param value Value to be appended to FIFO.
- *
- */
-#define fifo_push(name, value) \
-	name.fifo[name.tail = (name.tail + 1) < name.items ? (name.tail + 1) : 0] = (value) 
-
-/** Allocate memory for dynamic FIFO.
- *
- * @param name FIFO name.
- */
-#define fifo_create(name) \
-	name.fifo = malloc(sizeof(*name.fifo) * name.items)
-
-#endif
Index: badt/include/hash_table.h
===================================================================
--- libadt/include/hash_table.h	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifndef __HASH_TABLE_H__
-#define __HASH_TABLE_H__
-
-#include <libadt/list.h>
-#include <unistd.h>
-
-typedef unsigned long hash_count_t;
-typedef unsigned long hash_index_t;
-typedef struct hash_table hash_table_t;
-typedef struct hash_table_operations hash_table_operations_t;
-
-/** Hash table structure. */
-struct hash_table {
-	link_t *entry;
-	hash_count_t entries;
-	hash_count_t max_keys;
-	hash_table_operations_t *op;
-};
-
-/** Set of operations for hash table. */
-struct hash_table_operations {
-	/** Hash function.
-	 *
-	 * @param key Array of keys needed to compute hash index. All keys must be passed.
-	 *
-	 * @return Index into hash table.
-	 */
-	hash_index_t (* hash)(unsigned long key[]);
-	
-	/** Hash table item comparison function.
-	 *
-	 * @param key Array of keys that will be compared with item. It is not necessary to pass all keys.
-	 *
-	 * @return true if the keys match, false otherwise.
-	 */
-	int (*compare)(unsigned long key[], hash_count_t keys, link_t *item);
-
-	/** Hash table item removal callback.
-	 *
-	 * @param item Item that was removed from the hash table.
-	 */
-	void (*remove_callback)(link_t *item);
-};
-
-#define hash_table_get_instance(item, type, member)	list_get_instance((item), type, member)
-
-extern int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op);
-extern void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item);
-extern link_t *hash_table_find(hash_table_t *h, unsigned long key[]);
-extern void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys);
-
-#endif
Index: badt/include/list.h
===================================================================
--- libadt/include/list.h	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ 	(revision )
@@ -1,185 +1,0 @@
-/*
- * Copyright (C) 2001-2004 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.
- */
-
-#ifndef __LIST_H__
-#define __LIST_H__
-
-#include<unistd.h>
-
-#ifndef true
-# define true 1
-#endif
-#ifndef false
-# define false 0
-#endif
-
-typedef struct link link_t;
-
-/** Doubly linked list head and link type. */
-struct link {
-	link_t *prev;	/**< Pointer to the previous item in the list. */
-	link_t *next;	/**< Pointer to the next item in the list. */
-};
-
-/** Declare and initialize statically allocated list.
- *
- * @param name Name of the new statically allocated list.
- */
-#define LIST_INITIALIZE(name)		link_t name = { .prev = &name, .next = &name }
-
-/** Initialize doubly-linked circular list link
- *
- * Initialize doubly-linked list link.
- *
- * @param link Pointer to link_t structure to be initialized.
- */
-static inline void link_initialize(link_t *link)
-{
-	link->prev = NULL;
-	link->next = NULL;
-}
-
-/** Initialize doubly-linked circular list
- *
- * Initialize doubly-linked circular list.
- *
- * @param head Pointer to link_t structure representing head of the list.
- */
-static inline void list_initialize(link_t *head)
-{
-	head->prev = head;
-	head->next = head;
-}
-
-/** Add item to the beginning of doubly-linked circular list
- *
- * Add item to the beginning of doubly-linked circular list.
- *
- * @param link Pointer to link_t structure to be added.
- * @param head Pointer to link_t structure representing head of the list.
- */
-static inline void list_prepend(link_t *link, link_t *head)
-{
-	link->next = head->next;
-	link->prev = head;
-	head->next->prev = link;
-	head->next = link;
-}
-
-/** Add item to the end of doubly-linked circular list
- *
- * Add item to the end of doubly-linked circular list.
- *
- * @param link Pointer to link_t structure to be added.
- * @param head Pointer to link_t structure representing head of the list.
- */
-static inline void list_append(link_t *link, link_t *head)
-{
-	link->prev = head->prev;
-	link->next = head;
-	head->prev->next = link;
-	head->prev = link;
-}
-
-/** Remove item from doubly-linked circular list
- *
- * Remove item from doubly-linked circular list.
- *
- * @param link Pointer to link_t structure to be removed from the list it is contained in.
- */
-static inline void list_remove(link_t *link)
-{
-	link->next->prev = link->prev;
-	link->prev->next = link->next;
-	link_initialize(link);
-}
-
-/** Query emptiness of doubly-linked circular list
- *
- * Query emptiness of doubly-linked circular list.
- *
- * @param head Pointer to link_t structure representing head of the list.
- */
-static inline int list_empty(link_t *head)
-{
-	return head->next == head ? true : false;
-}
-
-
-/** Split or concatenate headless doubly-linked circular list
- *
- * Split or concatenate headless doubly-linked circular list.
- *
- * Note that the algorithm works both directions:
- * concatenates splitted lists and splits concatenated lists.
- *
- * @param part1 Pointer to link_t structure leading the first (half of the headless) list.
- * @param part2 Pointer to link_t structure leading the second (half of the headless) list. 
- */
-static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
-{
-	link_t *hlp;
-
-	part1->prev->next = part2;
-	part2->prev->next = part1;	
-	hlp = part1->prev;
-	part1->prev = part2->prev;
-	part2->prev = hlp;
-}
-
-
-/** Split headless doubly-linked circular list
- *
- * Split headless doubly-linked circular list.
- *
- * @param part1 Pointer to link_t structure leading the first half of the headless list.
- * @param part2 Pointer to link_t structure leading the second half of the headless list. 
- */
-static inline void headless_list_split(link_t *part1, link_t *part2)
-{
-	headless_list_split_or_concat(part1, part2);
-}
-
-/** Concatenate two headless doubly-linked circular lists
- *
- * Concatenate two headless doubly-linked circular lists.
- *
- * @param part1 Pointer to link_t structure leading the first headless list.
- * @param part2 Pointer to link_t structure leading the second headless list. 
- */
-static inline void headless_list_concat(link_t *part1, link_t *part2)
-{
-	headless_list_split_or_concat(part1, part2);
-}
-
-#define list_get_instance(link,type,member) (type *)(((char *)(link))-((char *)&(((type *)NULL)->member)))
-
-extern int list_member(const link_t *link, const link_t *head);
-extern void list_concat(link_t *head1, link_t *head2);
-
-#endif
Index: libc/Makefile
===================================================================
--- libc/Makefile	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/Makefile	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -63,5 +63,8 @@
 	generic/psthread.c \
 	generic/sysinfo.c \
-	generic/ipc.c
+	generic/ipc.c \
+	generic/async.c \
+	generic/libadt/list.o \
+	generic/libadt/hash_table.o
 
 ARCH_SOURCES += \
@@ -80,10 +83,9 @@
 	ln -sfn kernel/arch include/arch
 	ln -sfn ../arch/$(ARCH)/include include/libarch
-	ln -sfn ../../libadt/include include/libadt
 
 -include Makefile.depend
 
 clean:
-	-rm -f include/kernel include/arch include/libarch include/libadt libc.a arch/$(ARCH)/_link.ld Makefile.depend
+	-rm -f include/kernel include/arch include/libarch libc.a arch/$(ARCH)/_link.ld Makefile.depend
 	find generic/ arch/$(ARCH)/ -name '*.o' -follow -exec rm \{\} \;
 
@@ -92,5 +94,5 @@
 
 libc.a: depend $(ARCH_OBJECTS) $(GENERIC_OBJECTS)
-	$(AR) rc libc.a $(ARCH_OBJECTS) $(GENERIC_OBJECTS)
+	$(AR) rc libc.a $(LIBS) $(ARCH_OBJECTS) $(GENERIC_OBJECTS)
 
 arch/$(ARCH)/_link.ld: arch/$(ARCH)/_link.ld.in
Index: libc/generic/async.c
===================================================================
--- libc/generic/async.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/generic/async.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -27,51 +27,304 @@
  */ 
 
-ipc_wait_t call_func(args)
-{
-}
-
-ipc_wait_t fire_function(args)
-{
-	stack = malloc(stacksize);
-	setup(stack);
-	add_to_list_of_ready_funcs(stack);
-	if (threads_waiting_for_message)
-		send_message_to_self_to_one_up();
-}
-
-void discard_result(ipc_wait_t funcid)
-{
-}
-
-int wait_result(ipc_wait_t funcid);
-{
-	save_context(self);
-restart:
-	if result_available() {
-		if in_list_of_ready(self):
-			tear_off_list(self);
-		return retval;
-	}
-	add_to_waitlist_of(funcid);
-
-	take_something_from_list_of_ready();
-	if something {
-		
-		restore_context(something);
-        } else { /* nothing */
-		wait_for_call();
-		if (answer) {
-			mark_result_ready();
-			put_waiting_thread_to_waitlist();
-
-			goto restart;
+/**
+ * Asynchronous library
+ *
+ * The aim of this library is facilitating writing programs utilizing 
+ * the asynchronous nature of Helenos IPC, yet using a normal way
+ * of programming. 
+ *
+ * You should be able to write very simple multithreaded programs, 
+ * the async framework will automatically take care of most synchronization
+ * problems.
+ *
+ * Default semantics:
+ * - send() - send asynchronously. If the kernel refuses to send more
+ *            messages, [ try to get responses from kernel, if nothing
+ *            found, might try synchronous ]
+ *
+ * Example of use:
+ * 
+ * 1) Multithreaded client application
+ *  create_thread(thread1);
+ *  create_thread(thread2);
+ *  ...
+ *  
+ *  thread1() {
+ *        conn = ipc_connect_me_to();
+ *        c1 = send(conn);
+ *        c2 = send(conn);
+ *        wait_for(c1);
+ *        wait_for(c2);
+ *  }
+ *
+ *
+ * 2) Multithreaded server application
+ * main() {
+ *      wait_for_connection(new_connection);
+ * }
+ * 
+ *
+ * new_connection(int connection) {
+ *       accept(connection);
+ *       msg = get_msg();
+ *       handle(msg);
+ *       answer(msg);
+ *
+ *       msg = get_msg();
+ *       ....
+ * }
+ */
+#include <futex.h>
+#include <async.h>
+#include <psthread.h>
+#include <stdio.h>
+#include <libadt/hash_table.h>
+#include <libadt/list.h>
+#include <ipc/ipc.h>
+#include <assert.h>
+#include <errno.h>
+
+static atomic_t conn_futex = FUTEX_INITIALIZER;
+static hash_table_t conn_hash_table;
+
+typedef struct {
+	link_t link;
+	ipc_callid_t callid;
+	ipc_call_t call;
+} msg_t;
+
+typedef struct {
+	link_t link;
+	ipcarg_t in_phone_hash;		/**< Incoming phone hash. */
+	link_t msg_queue;              /**< Messages that should be delivered to this thread */
+	pstid_t ptid;                /**< Thread associated with this connection */
+	int active;                     /**< If this thread is currently active */
+	int opened;                    /* If the connection was accepted */
+	/* Structures for connection opening packet */
+	ipc_callid_t callid;
+	ipc_call_t call;
+} connection_t;
+
+__thread connection_t *PS_connection;
+
+/* Hash table functions */
+
+#define ASYNC_HASH_TABLE_CHAINS	32
+
+static hash_index_t conn_hash(unsigned long *key)
+{
+	assert(key);
+	return ((*key) >> 4) % ASYNC_HASH_TABLE_CHAINS;
+}
+
+static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	connection_t *hs;
+
+	hs = hash_table_get_instance(item, connection_t, link);
+	
+	return key[0] == hs->in_phone_hash;
+}
+
+static void conn_remove(link_t *item)
+{
+	free(hash_table_get_instance(item, connection_t, link));
+}
+
+
+/** Operations for NS hash table. */
+static hash_table_operations_t conn_hash_table_ops = {
+	.hash = conn_hash,
+	.compare = conn_compare,
+	.remove_callback = conn_remove
+};
+
+/** Try to route a call to an appropriate connection thread
+ *
+ */
+static int route_call(ipc_callid_t callid, ipc_call_t *call)
+{
+	connection_t *conn;
+	msg_t *msg;
+	link_t *hlp;
+	unsigned long key;
+
+	futex_down(&conn_futex);
+
+	key = call->in_phone_hash;
+	hlp = hash_table_find(&conn_hash_table, &key);
+	if (!hlp) {
+		futex_up(&conn_futex);
+		return 0;
+	}
+	conn = hash_table_get_instance(hlp, connection_t, link);
+
+	msg = malloc(sizeof(*msg));
+	msg->callid = callid;
+	msg->call = *call;
+	list_append(&msg->link, &conn->msg_queue);
+	
+	if (!conn->active) {
+		conn->active = 1;
+		psthread_add_ready(conn->ptid);
+	}
+
+	futex_up(&conn_futex);
+
+	return 1;
+}
+
+ipc_callid_t async_get_call(ipc_call_t *call)
+{
+	msg_t *msg;
+	ipc_callid_t callid;
+	connection_t *conn;
+	
+	futex_down(&conn_futex);
+
+	conn = PS_connection;
+	/* If nothing in queue, wait until something appears */
+	if (list_empty(&conn->msg_queue)) {
+		conn->active = 0;
+		psthread_schedule_next_adv(PS_TO_MANAGER);
+	}
+	
+	msg = list_get_instance(conn->msg_queue.next, msg_t, link);
+	list_remove(&msg->link);
+	callid = msg->callid;
+	*call = msg->call;
+	free(msg);
+	
+	futex_up(&conn_futex);
+	return callid;
+}
+
+void client_connection(ipc_callid_t callid, ipc_call_t *call)
+{
+	printf("Got connection - no handler.\n");
+	_exit(1);
+}
+
+static int connection_thread(void  *arg)
+{
+	/* Setup thread local connection pointer */
+	PS_connection = (connection_t *)arg;
+	client_connection(PS_connection->callid, &PS_connection->call);
+
+	futex_down(&conn_futex);
+	/* TODO: remove myself from connection hash table */
+	futex_up(&conn_futex);
+	/* TODO: answer all unanswered messages in queue with
+	 *       EHANGUP */
+}
+
+/** Create new thread for a new connection 
+ *
+ * Creates new thread for connection, fills in connection
+ * structures and inserts it into the hash table, so that
+ * later we can easily do routing of messages to particular
+ * threads.
+ */
+static void new_connection(ipc_callid_t callid, ipc_call_t *call)
+{
+	pstid_t ptid;
+	connection_t *conn;
+	unsigned long key;
+
+	conn = malloc(sizeof(*conn));
+	if (!conn) {
+		ipc_answer_fast(callid, ENOMEM, 0, 0);
+		return;
+	}
+	conn->in_phone_hash = IPC_GET_ARG3(*call);
+	list_initialize(&conn->msg_queue);
+	conn->opened = 0;
+	conn->ptid = psthread_create(connection_thread, conn);
+	conn->callid = callid;
+	conn->call = *call;
+	conn->active = 1; /* We will activate it asap */
+	list_initialize(&conn->link);
+	if (!conn->ptid) {
+		free(conn);
+		ipc_answer_fast(callid, ENOMEM, 0, 0);
+		return;
+	}
+	key = conn->in_phone_hash;
+	futex_down(&conn_futex);
+	/* Add connection to hash table */
+	hash_table_insert(&conn_hash_table, &key, &conn->link);
+	futex_up(&conn_futex);
+
+	psthread_add_ready(conn->ptid);
+}
+
+/** Handle call to a task */
+static void handle_call(ipc_callid_t callid, ipc_call_t *call)
+{
+	if (route_call(callid, call))
+		return;
+
+	switch (IPC_GET_METHOD(*call)) {
+	case IPC_M_INTERRUPT:
+		break;
+	case IPC_M_CONNECT_ME_TO:
+		/* Open new connection with thread etc. */
+		new_connection(callid, call);
+		break;
+	default:
+		ipc_answer_fast(callid, EHANGUP, 0, 0);
+	}
+}
+
+/** Endless loop dispatching incoming calls and answers */
+int async_manager()
+{
+	ipc_call_t call;
+	ipc_callid_t callid;
+
+	while (1) {
+		if (psthread_schedule_next_adv(PS_FROM_MANAGER)) {
+			futex_up(&conn_futex); /* conn_futex is always held
+						* when entering manager thread
+						*/
+			continue;
 		}
-	}
-	
-}
-
-
-int ipc_call_sync(args)
-{
-	return ipc_wait(call_func(args));
-}
+		callid = ipc_wait_cycle(&call,SYNCH_NO_TIMEOUT,SYNCH_BLOCKING);
+
+		if (callid & IPC_CALLID_ANSWERED)
+			continue;
+		handle_call(callid, &call);
+	}
+}
+
+static int async_manager_thread(void *arg)
+{
+	futex_up(&conn_futex); /* conn_futex is always locked when entering
+				* manager */
+	async_manager();
+}
+
+/** Add one manager to manager list */
+void async_create_manager(void)
+{
+	pstid_t ptid;
+
+	ptid = psthread_create(async_manager_thread, NULL);
+	psthread_add_manager(ptid);
+}
+
+/** Remove one manager from manager list */
+void async_destroy_manager(void)
+{
+	psthread_remove_manager();
+}
+
+/** Initialize internal structures needed for async manager */
+int _async_init(void)
+{
+	if (!hash_table_create(&conn_hash_table, ASYNC_HASH_TABLE_CHAINS, 1, &conn_hash_table_ops)) {
+		printf("%s: cannot create hash table\n", "async");
+		return ENOMEM;
+	}
+	
+}
Index: libc/generic/ipc.c
===================================================================
--- libc/generic/ipc.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/generic/ipc.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -58,10 +58,5 @@
 LIST_INITIALIZE(queued_calls);
 
-static atomic_t ipc_futex;
-
-void _ipc_init(void)
-{
-	futex_initialize(&ipc_futex, 1);
-}
+static atomic_t ipc_futex = FUTEX_INITIALIZER;
 
 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, 
@@ -253,22 +248,22 @@
 
 
-/** Unconditionally wait for an IPC call.
+/** One cycle of ipc wait for call call
  *
  * - dispatch ASYNC reoutines in the background
  * @param call Space where the message is stored
+ * @param usec Timeout in microseconds
+ * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking)
  * @return Callid of the answer.
  */
-ipc_callid_t ipc_wait_for_call(ipc_call_t *call)
-{
-	ipc_callid_t callid;
-
-	do {
-		try_dispatch_queued_calls();
-
-		callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, SYNCH_NO_TIMEOUT, SYNCH_BLOCKING);
-		/* Handle received answers */
-		if (callid & IPC_CALLID_ANSWERED)
-			handle_answer(callid, call);
-	} while (callid & IPC_CALLID_ANSWERED);
+ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
+{
+	ipc_callid_t callid;
+
+	try_dispatch_queued_calls();
+	
+	callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
+	/* Handle received answers */
+	if (callid & IPC_CALLID_ANSWERED)
+		handle_answer(callid, call);
 
 	return callid;
@@ -287,10 +282,5 @@
 
 	do {
-		try_dispatch_queued_calls();
-
-		callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, SYNCH_BLOCKING);
-		/* Handle received answers */
-		if (callid & IPC_CALLID_ANSWERED)
-			handle_answer(callid, call);
+		callid = ipc_wait_cycle(call, usec, SYNCH_BLOCKING);
 	} while (callid & IPC_CALLID_ANSWERED);
 
@@ -309,10 +299,5 @@
 
 	do {
-		try_dispatch_queued_calls();
-
-		callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t)call, SYNCH_NO_TIMEOUT, SYNCH_NON_BLOCKING);
-		/* Handle received answers */
-		if (callid & IPC_CALLID_ANSWERED)
-			handle_answer(callid, call);
+		callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_NON_BLOCKING);
 	} while (callid & IPC_CALLID_ANSWERED);
 
Index: libc/generic/libadt/hash_table.c
===================================================================
--- libc/generic/libadt/hash_table.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
+++ libc/generic/libadt/hash_table.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/*
+ * This is an implementation of generic chained hash table.
+ */
+
+#include <libadt/hash_table.h>
+#include <libadt/list.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+/** Create chained hash table.
+ *
+ * @param h Hash table structure. Will be initialized by this call.
+ * @param m Number of slots in the hash table.
+ * @param max_keys Maximal number of keys needed to identify an item.
+ * @param op Hash table operations structure.
+ * @return true on success
+ */
+int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op)
+{
+	hash_count_t i;
+
+	assert(h);
+	assert(op && op->hash && op->compare);
+	assert(max_keys > 0);
+	
+	h->entry = malloc(m * sizeof(link_t));
+	if (!h->entry) {
+		printf("cannot allocate memory for hash table\n");
+		return false;
+	}
+	memset((void *) h->entry, 0,  m * sizeof(link_t));
+	
+	for (i = 0; i < m; i++)
+		list_initialize(&h->entry[i]);
+	
+	h->entries = m;
+	h->max_keys = max_keys;
+	h->op = op;
+	return true;
+}
+
+/** Insert item into hash table.
+ *
+ * @param h Hash table.
+ * @param hey Array of all keys necessary to compute hash index.
+ * @param item Item to be inserted into the hash table.
+ */
+void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item)
+{
+	hash_index_t chain;
+
+	assert(item);
+	assert(h && h->op && h->op->hash && h->op->compare);
+
+	chain = h->op->hash(key);
+	assert(chain < h->entries);
+	
+	list_append(item, &h->entry[chain]);
+}
+
+/** Search hash table for an item matching keys.
+ *
+ * @param h Hash table.
+ * @param key Array of all keys needed to compute hash index.
+ *
+ * @return Matching item on success, NULL if there is no such item.
+ */
+link_t *hash_table_find(hash_table_t *h, unsigned long key[])
+{
+	link_t *cur;
+	hash_index_t chain;
+
+	assert(h && h->op && h->op->hash && h->op->compare);
+
+	chain = h->op->hash(key);
+	assert(chain < h->entries);
+	
+	for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
+		if (h->op->compare(key, h->max_keys, cur)) {
+			/*
+			 * The entry is there.
+			 */
+			return cur;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Remove all matching items from hash table.
+ *
+ * For each removed item, h->remove_callback() is called.
+ *
+ * @param h Hash table.
+ * @param key Array of keys that will be compared against items of the hash table.
+ * @param keys Number of keys in the 'key' array.
+ */
+void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys)
+{
+	hash_index_t chain;
+	link_t *cur;
+
+	assert(h && h->op && h->op->hash && h->op->compare && h->op->remove_callback);
+	assert(keys <= h->max_keys);
+	
+	if (keys == h->max_keys) {
+
+		/*
+		 * All keys are known, hash_table_find() can be used to find the entry.
+		 */
+	
+		cur = hash_table_find(h, key);
+		if (cur) {
+			list_remove(cur);
+			h->op->remove_callback(cur);
+		}
+		return;
+	}
+	
+	/*
+	 * Fewer keys were passed.
+	 * Any partially matching entries are to be removed.
+	 */
+	for (chain = 0; chain < h->entries; chain++) {
+		for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
+			if (h->op->compare(key, keys, cur)) {
+				link_t *hlp;
+				
+				hlp = cur;
+				cur = cur->prev;
+				
+				list_remove(hlp);
+				h->op->remove_callback(hlp);
+				
+				continue;
+			}
+		}
+	}
+}
Index: libc/generic/libadt/list.c
===================================================================
--- libc/generic/libadt/list.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
+++ libc/generic/libadt/list.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2004 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.
+ */
+
+#include <libadt/list.h>
+
+
+/** Check for membership
+ *
+ * Check whether link is contained in the list head.
+ * The membership is defined as pointer equivalence.
+ *
+ * @param link Item to look for.
+ * @param head List to look in.
+ *
+ * @return true if link is contained in head, false otherwise.
+ *
+ */
+int list_member(const link_t *link, const link_t *head)
+{
+	int found = false;
+	link_t *hlp = head->next;
+	
+	while (hlp != head) {
+		if (hlp == link) {
+			found = true;
+			break;
+		}
+		hlp = hlp->next;
+	}
+	
+	return found;
+}
+
+
+/** Concatenate two lists
+ *
+ * Concatenate lists head1 and head2, producing a single
+ * list head1 containing items from both (in head1, head2
+ * order) and empty list head2.
+ *
+ * @param head1 First list and concatenated output
+ * @param head2 Second list and empty output.
+ *
+ */
+void list_concat(link_t *head1, link_t *head2)
+{
+	if (list_empty(head2))
+		return;
+
+	head2->next->prev = head1->prev;
+	head2->prev->next = head1;	
+	head1->prev->next = head2->next;
+	head1->prev = head2->prev;
+	list_initialize(head2);
+}
Index: libc/generic/libc.c
===================================================================
--- libc/generic/libc.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/generic/libc.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -34,4 +34,5 @@
 #include <io/stream.h>
 #include <ipc/ipc.h>
+#include <async.h>
 
 void _exit(int status) {
@@ -40,10 +41,9 @@
 
 void __main(void) {
-	tcb_t *tcb;
-	
-	tcb = __make_tls();
-	__tcb_set(tcb);
-	psthread_setup(tcb);
-	_ipc_init();
+	psthread_data_t *pt;
+
+	_async_init();
+	pt = psthread_setup();
+	__tcb_set(pt->tcb);
 }
 
@@ -55,9 +55,5 @@
 
 void __exit(void) {
-	tcb_t *tcb;
-
-	tcb = __tcb_get();
-	psthread_teardown(tcb->pst_data);
-	__free_tls(tcb);
+	psthread_teardown(__tcb_get()->pst_data);
 	_exit(0);
 }
Index: libc/generic/psthread.c
===================================================================
--- libc/generic/psthread.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/generic/psthread.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -34,5 +34,6 @@
 #include <stdio.h>
 #include <kernel/arch/faddr.h>
-
+#include <futex.h>
+#include <assert.h>
 
 #ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
@@ -41,15 +42,24 @@
 
 static LIST_INITIALIZE(ready_list);
+static LIST_INITIALIZE(manager_list);
 
 static void psthread_exit(void) __attribute__ ((noinline));
 static void psthread_main(void);
 
+static atomic_t psthread_futex = FUTEX_INITIALIZER;
+
 /** Setup PSthread information into TCB structure */
-psthread_data_t * psthread_setup(tcb_t *tcb)
-{
-	psthread_data_t *pt;
+psthread_data_t * psthread_setup()
+{
+	psthread_data_t *pt;
+	tcb_t *tcb;
+
+	tcb = __make_tls();
+	if (!tcb)
+		return NULL;
 
 	pt = malloc(sizeof(*pt));
 	if (!pt) {
+		__free_tls(tcb);
 		return NULL;
 	}
@@ -63,4 +73,5 @@
 void psthread_teardown(psthread_data_t *pt)
 {
+	__free_tls(pt->tcb);
 	free(pt);
 }
@@ -73,12 +84,19 @@
 	psthread_data_t *pt;
 
-	if (list_empty(&ready_list)) {
-		/* Wait on IPC queue etc... */
-		printf("Cannot exit!!!\n");
+	futex_down(&psthread_futex);
+
+	if (!list_empty(&ready_list))
+		pt = list_get_instance(ready_list.next, psthread_data_t, link);
+	else if (!list_empty(&manager_list)) 
+		pt = list_get_instance(manager_list.next, psthread_data_t, link);
+	else {
+		printf("Cannot find suitable psthread to run.\n");
 		_exit(0);
 	}
-	pt = list_get_instance(ready_list.next, psthread_data_t, link);
 	list_remove(&pt->link);
+	futex_up(&psthread_futex);
+
 	context_restore(&pt->ctx);
+	/* Never reached */
 }
 
@@ -99,22 +117,45 @@
 /** Schedule next userspace pseudo thread.
  *
+ * @param tomanager If true, we are switching to next ready manager thread
+ *                  (if none is found, thread is exited)
+ * @param frommanager If true, we are switching from manager thread
  * @return 0 if there is no ready pseudo thread, 1 otherwise.
  */
-int psthread_schedule_next(void)
-{
-	psthread_data_t *pt;
-
-	if (list_empty(&ready_list))
-		return 0;
+int psthread_schedule_next_adv(pschange_type ctype)
+{
+	psthread_data_t *pt;
+	int retval = 0;
+	
+	futex_down(&psthread_futex);
+
+	if (ctype == PS_PREEMPT && list_empty(&ready_list))
+		goto ret_0;
+
+	if (ctype == PS_FROM_MANAGER && list_empty(&ready_list)) {
+		goto ret_0;
+	}
+	assert(!(ctype == PS_TO_MANAGER && list_empty(&manager_list)));
 
 	pt = __tcb_get()->pst_data;
-	if (!context_save(&pt->ctx))
-		return 1;
+	if (!context_save(&pt->ctx)) 
+		return 1; // futex_up already done here
+
+	if (ctype == PS_PREEMPT)
+		list_append(&pt->link, &ready_list);
+	else if (ctype == PS_FROM_MANAGER)
+		list_append(&pt->link, &manager_list);
 	
-	list_append(&pt->link, &ready_list);
-	pt = list_get_instance(ready_list.next, psthread_data_t, link);
+	if (ctype == PS_TO_MANAGER)
+		pt = list_get_instance(manager_list.next,psthread_data_t, link);
+	else
+		pt = list_get_instance(ready_list.next, psthread_data_t, link);
 	list_remove(&pt->link);
 
+	futex_up(&psthread_futex);
 	context_restore(&pt->ctx);
+
+ret_0:
+	futex_up(&psthread_futex);
+	return retval;
 }
 
@@ -143,5 +184,4 @@
 
 	free(pt->stack);
-	__free_tls(pt->tcb);
 	psthread_teardown((void *)pt);
 
@@ -150,5 +190,5 @@
 
 /**
- * Create a userspace thread and append it to ready list.
+ * Create a userspace thread
  *
  * @param func Pseudo thread function.
@@ -160,19 +200,11 @@
 {
 	psthread_data_t *pt;
-	tcb_t *tcb;
-
-	tcb = __make_tls();
-	if (!tcb)
+
+	pt = psthread_setup();
+	if (!pt) 
 		return 0;
-
-	pt = psthread_setup(tcb);
-	if (!pt) {
-		__free_tls(tcb);
-		return 0;
-	}
 	pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
 
 	if (!pt->stack) {
-		__free_tls(tcb);
 		psthread_teardown(pt);
 		return 0;
@@ -186,8 +218,42 @@
 	context_save(&pt->ctx);
 	context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
-		    tcb);
-
+		    pt->tcb);
+
+	return (pstid_t )pt;
+}
+
+/** Add a thread to ready list */
+void psthread_add_ready(pstid_t psthrid)
+{
+	psthread_data_t *pt;
+
+	pt = (psthread_data_t *) psthrid;
+	futex_down(&psthread_futex);
 	list_append(&pt->link, &ready_list);
-
-	return (pstid_t )pt;
-}
+	futex_up(&psthread_futex);
+}
+
+/** Add a thread to manager list */
+void psthread_add_manager(pstid_t psthrid)
+{
+	psthread_data_t *pt;
+
+	pt = (psthread_data_t *) psthrid;
+
+	futex_down(&psthread_futex);
+	list_append(&pt->link, &manager_list);
+	futex_up(&psthread_futex);
+}
+
+/** Remove one manager from manager list */
+void psthread_remove_manager()
+{
+	futex_down(&psthread_futex);
+	if (list_empty(&manager_list)) {
+		printf("No manager found!.\n");
+		futex_up(&psthread_futex);
+		return;
+	}
+	list_remove(manager_list.next);
+	futex_up(&psthread_futex);
+}
Index: libc/generic/thread.c
===================================================================
--- libc/generic/thread.c	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/generic/thread.c	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -34,4 +34,5 @@
 #include <psthread.h>
 #include <string.h>
+#include <async.h>
 
 #include <stdio.h>
@@ -81,12 +82,15 @@
  *
  * @param uarg Pointer to userspace argument structure.
+ *
+ * TODO: Thread stack pages memory leak
  */
 void __thread_main(uspace_arg_t *uarg)
 {
-	tcb_t *tcb;
-	/* This should initialize the area according to TLS specicification */
-	tcb = __make_tls();
-	__tcb_set(tcb);
-	psthread_setup(tcb);
+	psthread_data_t *pt;
+
+	pt = psthread_setup();
+	__tcb_set(pt->tcb);
+	
+	async_create_manager();
 
 	uarg->uspace_thread_function(uarg->uspace_thread_arg);
@@ -94,6 +98,6 @@
 	free(uarg);
 
-	psthread_teardown(tcb->pst_data);
-	__free_tls(tcb);
+	async_destroy_manager();
+	psthread_teardown(pt);
 
 	thread_exit(0);
Index: libc/include/ipc/ipc.h
===================================================================
--- libc/include/ipc/ipc.h	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/include/ipc/ipc.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -34,4 +34,5 @@
 #include <libc.h>
 #include <types.h>
+#include <kernel/synch/synch.h>
 
 typedef sysarg_t ipcarg_t;
@@ -54,6 +55,10 @@
 extern int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
 			 ipcarg_t *result);
-extern ipc_callid_t ipc_wait_for_call(ipc_call_t *data);
+extern ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags);
 extern ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *data, uint32_t usec);
+static inline ipc_callid_t ipc_wait_for_call(ipc_call_t *data)
+{
+	return ipc_wait_for_call_timeout(data, SYNCH_NO_TIMEOUT);
+}
 extern ipc_callid_t ipc_trywait_for_call(ipc_call_t *data);
 
@@ -72,5 +77,4 @@
 extern int ipc_unregister_irq(int irq);
 extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1);
-extern void _ipc_init(void);
 
 #endif
Index: libc/include/libadt/fifo.h
===================================================================
--- libc/include/libadt/fifo.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
+++ libc/include/libadt/fifo.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/*
+ * This implementation of FIFO stores values in an array
+ * (static or dynamic). As such, these FIFOs have upper bound
+ * on number of values they can store. Push and pop operations
+ * are done via accessing the array through head and tail indices.
+ * Because of better operation ordering in fifo_pop(), the access
+ * policy for these two indices is to 'increment (mod size of FIFO)
+ * and use'.
+ */
+
+#ifndef __FIFO_H__
+#define __FIFO_H__
+
+#include <malloc.h>
+
+typedef unsigned long fifo_count_t;
+typedef unsigned long fifo_index_t;
+
+/** Create and initialize static FIFO.
+ *
+ * FIFO is allocated statically.
+ * This macro is suitable for creating smaller FIFOs.
+ *
+ * @param name Name of FIFO.
+ * @param t Type of values stored in FIFO.
+ * @param itms Number of items that can be stored in FIFO.
+ */
+#define FIFO_INITIALIZE_STATIC(name, t, itms)		\
+	struct {					\
+		t fifo[(itms)];				\
+		fifo_count_t items;			\
+		fifo_index_t head;			\
+		fifo_index_t tail;			\
+	} name = {					\
+		.items = (itms),			\
+		.head = 0,				\
+		.tail = 0				\
+	}
+
+/** Create and prepare dynamic FIFO.
+ *
+ * FIFO is allocated dynamically.
+ * This macro is suitable for creating larger FIFOs. 
+ *
+ * @param name Name of FIFO.
+ * @param t Type of values stored in FIFO.
+ * @param itms Number of items that can be stored in FIFO.
+ */
+#define FIFO_INITIALIZE_DYNAMIC(name, t, itms)		\
+	struct {					\
+		t *fifo;				\
+		fifo_count_t items;			\
+		fifo_index_t head;			\
+		fifo_index_t tail;			\
+	} name = {					\
+		.fifo = NULL,				\
+		.items = (itms),			\
+		.head = 0,				\
+		.tail = 0				\
+	}
+
+/** Pop value from head of FIFO.
+ *
+ * @param name FIFO name.
+ *
+ * @return Leading value in FIFO.
+ */
+#define fifo_pop(name) \
+	name.fifo[name.head = (name.head + 1) < name.items ? (name.head + 1) : 0]
+
+/** Push value to tail of FIFO.
+ *
+ * @param name FIFO name.
+ * @param value Value to be appended to FIFO.
+ *
+ */
+#define fifo_push(name, value) \
+	name.fifo[name.tail = (name.tail + 1) < name.items ? (name.tail + 1) : 0] = (value) 
+
+/** Allocate memory for dynamic FIFO.
+ *
+ * @param name FIFO name.
+ */
+#define fifo_create(name) \
+	name.fifo = malloc(sizeof(*name.fifo) * name.items)
+
+#endif
Index: libc/include/libadt/hash_table.h
===================================================================
--- libc/include/libadt/hash_table.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
+++ libc/include/libadt/hash_table.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef __HASH_TABLE_H__
+#define __HASH_TABLE_H__
+
+#include <libadt/list.h>
+#include <unistd.h>
+
+typedef unsigned long hash_count_t;
+typedef unsigned long hash_index_t;
+typedef struct hash_table hash_table_t;
+typedef struct hash_table_operations hash_table_operations_t;
+
+/** Hash table structure. */
+struct hash_table {
+	link_t *entry;
+	hash_count_t entries;
+	hash_count_t max_keys;
+	hash_table_operations_t *op;
+};
+
+/** Set of operations for hash table. */
+struct hash_table_operations {
+	/** Hash function.
+	 *
+	 * @param key Array of keys needed to compute hash index. All keys must be passed.
+	 *
+	 * @return Index into hash table.
+	 */
+	hash_index_t (* hash)(unsigned long key[]);
+	
+	/** Hash table item comparison function.
+	 *
+	 * @param key Array of keys that will be compared with item. It is not necessary to pass all keys.
+	 *
+	 * @return true if the keys match, false otherwise.
+	 */
+	int (*compare)(unsigned long key[], hash_count_t keys, link_t *item);
+
+	/** Hash table item removal callback.
+	 *
+	 * @param item Item that was removed from the hash table.
+	 */
+	void (*remove_callback)(link_t *item);
+};
+
+#define hash_table_get_instance(item, type, member)	list_get_instance((item), type, member)
+
+extern int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op);
+extern void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item);
+extern link_t *hash_table_find(hash_table_t *h, unsigned long key[]);
+extern void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys);
+
+#endif
Index: libc/include/libadt/list.h
===================================================================
--- libc/include/libadt/list.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
+++ libc/include/libadt/list.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2001-2004 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.
+ */
+
+#ifndef __LIST_H__
+#define __LIST_H__
+
+#include<unistd.h>
+
+#ifndef true
+# define true 1
+#endif
+#ifndef false
+# define false 0
+#endif
+
+typedef struct link link_t;
+
+/** Doubly linked list head and link type. */
+struct link {
+	link_t *prev;	/**< Pointer to the previous item in the list. */
+	link_t *next;	/**< Pointer to the next item in the list. */
+};
+
+/** Declare and initialize statically allocated list.
+ *
+ * @param name Name of the new statically allocated list.
+ */
+#define LIST_INITIALIZE(name)		link_t name = { .prev = &name, .next = &name }
+
+/** Initialize doubly-linked circular list link
+ *
+ * Initialize doubly-linked list link.
+ *
+ * @param link Pointer to link_t structure to be initialized.
+ */
+static inline void link_initialize(link_t *link)
+{
+	link->prev = NULL;
+	link->next = NULL;
+}
+
+/** Initialize doubly-linked circular list
+ *
+ * Initialize doubly-linked circular list.
+ *
+ * @param head Pointer to link_t structure representing head of the list.
+ */
+static inline void list_initialize(link_t *head)
+{
+	head->prev = head;
+	head->next = head;
+}
+
+/** Add item to the beginning of doubly-linked circular list
+ *
+ * Add item to the beginning of doubly-linked circular list.
+ *
+ * @param link Pointer to link_t structure to be added.
+ * @param head Pointer to link_t structure representing head of the list.
+ */
+static inline void list_prepend(link_t *link, link_t *head)
+{
+	link->next = head->next;
+	link->prev = head;
+	head->next->prev = link;
+	head->next = link;
+}
+
+/** Add item to the end of doubly-linked circular list
+ *
+ * Add item to the end of doubly-linked circular list.
+ *
+ * @param link Pointer to link_t structure to be added.
+ * @param head Pointer to link_t structure representing head of the list.
+ */
+static inline void list_append(link_t *link, link_t *head)
+{
+	link->prev = head->prev;
+	link->next = head;
+	head->prev->next = link;
+	head->prev = link;
+}
+
+/** Remove item from doubly-linked circular list
+ *
+ * Remove item from doubly-linked circular list.
+ *
+ * @param link Pointer to link_t structure to be removed from the list it is contained in.
+ */
+static inline void list_remove(link_t *link)
+{
+	link->next->prev = link->prev;
+	link->prev->next = link->next;
+	link_initialize(link);
+}
+
+/** Query emptiness of doubly-linked circular list
+ *
+ * Query emptiness of doubly-linked circular list.
+ *
+ * @param head Pointer to link_t structure representing head of the list.
+ */
+static inline int list_empty(link_t *head)
+{
+	return head->next == head ? true : false;
+}
+
+
+/** Split or concatenate headless doubly-linked circular list
+ *
+ * Split or concatenate headless doubly-linked circular list.
+ *
+ * Note that the algorithm works both directions:
+ * concatenates splitted lists and splits concatenated lists.
+ *
+ * @param part1 Pointer to link_t structure leading the first (half of the headless) list.
+ * @param part2 Pointer to link_t structure leading the second (half of the headless) list. 
+ */
+static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
+{
+	link_t *hlp;
+
+	part1->prev->next = part2;
+	part2->prev->next = part1;	
+	hlp = part1->prev;
+	part1->prev = part2->prev;
+	part2->prev = hlp;
+}
+
+
+/** Split headless doubly-linked circular list
+ *
+ * Split headless doubly-linked circular list.
+ *
+ * @param part1 Pointer to link_t structure leading the first half of the headless list.
+ * @param part2 Pointer to link_t structure leading the second half of the headless list. 
+ */
+static inline void headless_list_split(link_t *part1, link_t *part2)
+{
+	headless_list_split_or_concat(part1, part2);
+}
+
+/** Concatenate two headless doubly-linked circular lists
+ *
+ * Concatenate two headless doubly-linked circular lists.
+ *
+ * @param part1 Pointer to link_t structure leading the first headless list.
+ * @param part2 Pointer to link_t structure leading the second headless list. 
+ */
+static inline void headless_list_concat(link_t *part1, link_t *part2)
+{
+	headless_list_split_or_concat(part1, part2);
+}
+
+#define list_get_instance(link,type,member) (type *)(((char *)(link))-((char *)&(((type *)NULL)->member)))
+
+extern int list_member(const link_t *link, const link_t *head);
+extern void list_concat(link_t *head1, link_t *head2);
+
+#endif
Index: libc/include/psthread.h
===================================================================
--- libc/include/psthread.h	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ libc/include/psthread.h	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -41,4 +41,10 @@
 #endif /* context_set */
 
+typedef enum {
+	PS_TO_MANAGER,
+	PS_FROM_MANAGER,
+	PS_PREEMPT
+} pschange_type;
+
 typedef sysarg_t pstid_t;
 
@@ -62,8 +68,15 @@
 
 pstid_t psthread_create(int (*func)(void *), void *arg);
-int psthread_schedule_next(void);
 int psthread_join(pstid_t psthrid);
-psthread_data_t * psthread_setup(tcb_t *tcb);
+psthread_data_t * psthread_setup(void);
 void psthread_teardown(psthread_data_t *pt);
+int psthread_schedule_next_adv(pschange_type ctype);
+void psthread_add_ready(pstid_t ptid);
+void psthread_add_manager(pstid_t psthrid);
+void psthread_remove_manager(void);
+
+static inline int psthread_schedule_next() {
+	return psthread_schedule_next_adv(PS_PREEMPT);
+}
 
 
Index: ns/Makefile
===================================================================
--- ns/Makefile	(revision 1ee11f4012cb68a874bb756d54e7d501cf252ee9)
+++ ns/Makefile	(revision 80649a918469c5ca98f3d4d45041e6aa029a4514)
@@ -31,9 +31,8 @@
 
 LIBC_PREFIX = ../libc
-LIBADT_PREFIX = ../libadt
 SOFTINT_PREFIX = ../softint
 include $(LIBC_PREFIX)/Makefile.toolchain
 
-LIBS = $(LIBADT_PREFIX)/libadt.a $(LIBC_PREFIX)/libc.a
+LIBS = $(LIBC_PREFIX)/libc.a
 
 ## Sources
