Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ HelenOS.config	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -70,8 +70,8 @@
 @ "pentium4" Pentium 4
 @ "pentium3" Pentium 3
-@ "i486" i486
 @ "core" Core Solo/Duo
 @ "athlon_xp" Athlon XP
 @ "athlon_mp" Athlon MP
+@ "i486" i486
 ! [PLATFORM=ia32] PROCESSOR (choice)
 
Index: abi/include/ipc/methods.h
===================================================================
--- abi/include/ipc/methods.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ abi/include/ipc/methods.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -96,6 +96,4 @@
  *                       error is sent back to caller. Otherwise 
  *                       the call is accepted and the response is sent back.
- *                     - the hash of the client task is passed to userspace
- *                       (on the receiving side) as ARG4 of the call.
  *                     - the hash of the allocated phone is passed to userspace
  *                       (on the receiving side) as ARG5 of the call.
Index: kernel/arch/ia32/Makefile.inc
===================================================================
--- kernel/arch/ia32/Makefile.inc	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/Makefile.inc	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -44,4 +44,8 @@
 #
 
+ifeq ($(PROCESSOR),i486)
+	CMN2 = -march=i486
+endif
+
 ifeq ($(PROCESSOR),athlon_xp)
 	CMN2 = -march=athlon-xp
@@ -62,8 +66,4 @@
 	CMN2 = -march=pentium4
 	SUNCC_CFLAGS += -xarch=sse2
-endif
-
-ifeq ($(PROCESSOR),i486)
-	CMN2 = -march=i486
 endif
 
Index: kernel/arch/ia32/include/asm.h
===================================================================
--- kernel/arch/ia32/include/asm.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/include/asm.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -312,4 +312,5 @@
 
 #ifndef PROCESSOR_i486
+
 /** Write to MSR */
 NO_TRACE static inline void write_msr(uint32_t msr, uint64_t value)
@@ -336,5 +337,6 @@
 	return ((uint64_t) dx << 32) | ax;
 }
-#endif
+
+#endif /* PROCESSOR_i486 */
 
 
Index: kernel/arch/ia32/include/boot/boot.h
===================================================================
--- kernel/arch/ia32/include/boot/boot.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/include/boot/boot.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -43,4 +43,6 @@
 #define MULTIBOOT_HEADER_FLAGS  0x00010003
 
+#define MULTIBOOT_LOADER_MAGIC  0x2BADB002
+
 #ifndef __ASM__
 
Index: kernel/arch/ia32/src/asm.S
===================================================================
--- kernel/arch/ia32/src/asm.S	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/src/asm.S	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -407,6 +407,6 @@
 #ifdef PROCESSOR_i486
 	jz 0f
-	movl %eax, %ebp
-0:
+		movl %eax, %ebp
+	0:
 #else
 	cmovnzl %eax, %ebp
Index: kernel/arch/ia32/src/boot/boot.S
===================================================================
--- kernel/arch/ia32/src/boot/boot.S	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/src/boot/boot.S	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -99,6 +99,32 @@
 #include "vesa_prot.inc"
 	
-	/* Map kernel and turn paging on */
-	call map_kernel
+#ifndef PROCESSOR_i486
+	
+	pm_status $status_prot2
+	
+	movl $(INTEL_CPUID_LEVEL), %eax
+	cpuid
+	cmp $0x0, %eax  /* any function > 0? */
+	jbe pse_unsupported
+	
+	movl $(INTEL_CPUID_STANDARD), %eax
+	cpuid
+	bt $(INTEL_PSE), %edx
+	jnc pse_unsupported
+		
+		/* Map kernel and turn paging on */
+		pm_status $status_pse
+		call map_kernel_pse
+		jmp stack_init
+	
+#endif /* PROCESSOR_i486 */
+	
+	pse_unsupported:
+		
+		/* Map kernel and turn paging on */
+		pm_status $status_non_pse
+		call map_kernel
+	
+	stack_init:
 	
 	/* Create the first stack frame */
@@ -106,5 +132,5 @@
 	movl %esp, %ebp
 	
-	pm2_status $status_prot2
+	pm2_status $status_prot3
 	
 	/* Call arch_pre_main(grub_eax, grub_ebx) */
@@ -124,72 +150,44 @@
 		jmp hlt0
 
-/** Calculate unmapped address of the end of the kernel. */
-calc_end_of_kernel:
-	movl $hardcoded_load_address, %edi
-	andl $0x7fffffff, %edi
-	movl (%edi), %esi
-	andl $0x7fffffff, %esi
-	
-	movl $hardcoded_ktext_size, %edi
-	andl $0x7fffffff, %edi
-	addl (%edi), %esi
-	andl $0x7fffffff, %esi
-	
-	movl $hardcoded_kdata_size, %edi
-	andl $0x7fffffff, %edi
-	addl (%edi), %esi
-	andl $0x7fffffff, %esi
-	movl %esi, end_of_kernel
+/** Setup mapping for the kernel (PSE variant)
+ *
+ * Setup mapping for both the unmapped and mapped sections
+ * of the kernel. For simplicity, we map the entire 4G space.
+ *
+ */
+.global map_kernel_pse
+map_kernel_pse:
+	/* Paging features */
+	movl %cr4, %ecx
+	orl $(1 << 4), %ecx      /* PSE on */
+	andl $(~(1 << 5)), %ecx  /* PAE off */
+	movl %ecx, %cr4
+	
+	movl $(page_directory + 0), %esi
+	movl $(page_directory + 2048), %edi
+	xorl %ecx, %ecx
+	xorl %ebx, %ebx
+	
+	floop_pse:
+		movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax
+		orl %ebx, %eax
+		/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+		movl %eax, (%esi, %ecx, 4)
+		/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+		movl %eax, (%edi, %ecx, 4)
+		addl $(4 * 1024 * 1024), %ebx
+		
+		incl %ecx
+		cmpl $512, %ecx
+		jl floop_pse
+	
+	movl %esi, %cr3
+	
+	movl %cr0, %ebx
+	orl $(1 << 31), %ebx  /* paging on */
+	movl %ebx, %cr0
 	ret
 
-/** Find free 2M (+4k for alignment) region where to store page tables */
-find_mem_for_pt:
-	/* Check if multiboot info is present */
-	cmpl $0x2BADB002, grub_eax
-	je check_multiboot_map
-	ret
-check_multiboot_map:
-	/* Copy address of the multiboot info to ebx */
-	movl grub_ebx, %ebx
-	/* Check if memory map flag is present */
-	movl (%ebx), %edx
-	andl $(1 << 6), %edx
-	jnz use_multiboot_map
-	ret
-use_multiboot_map:
-	/* Copy address of the memory map to edx */
-	movl 48(%ebx), %edx
-	movl %edx, %ecx
-	addl 44(%ebx), %ecx
-	/* Find a free region at least 2M in size */
-	check_memmap_loop:
-		/* Is this a free region? */
-		cmp $1, 20(%edx)
-		jnz next_region
-		/* Check size */
-		cmp $0, 16(%edx)
-		jnz next_region
-		cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
-		jbe next_region
-		cmp $0, 8(%edx)
-		jz found_region
-	next_region:
-		cmp %ecx, %edx
-		jbe next_region_do
-		ret
-	next_region_do:
-		addl (%edx), %edx
-		addl $4, %edx
-		jmp check_memmap_loop
-	found_region:
-		/* Use end of the found region */
-		mov 4(%edx), %ecx
-		add 12(%edx), %ecx
-		sub $(2 * 1024 * 1024), %ecx
-		mov %ecx, free_area
-	ret
-		
-
-/** Setup mapping for the kernel.
+/** Setup mapping for the kernel (non-PSE variant).
  *
  * Setup mapping for both the unmapped and mapped sections
@@ -204,66 +202,165 @@
 	movl %ecx, %cr4
 	
-	call calc_end_of_kernel
+	call calc_kernel_end
 	call find_mem_for_pt
-	mov end_of_kernel, %esi
+	
+	mov kernel_end, %esi
 	mov free_area, %ecx
+	
 	cmpl %esi, %ecx
-	jbe use_end_of_kernel
-	mov %ecx, %esi
-	/* Align address down to 4k */
-	andl $(~4095), %esi
-use_end_of_kernel:
-	
-	/* Align address to 4k */
-	addl $4095, %esi
-	andl $(~4095), %esi
-	
-	/* Allocate space for page tables*/	
-	movl %esi, pt_loc
-	movl $ballocs, %edi
+	jbe use_kernel_end
+		
+		mov %ecx, %esi
+		
+		/* Align address down to 4k */
+		andl $(~4095), %esi
+		
+	use_kernel_end:
+		
+		/* Align address to 4k */
+		addl $4095, %esi
+		andl $(~4095), %esi
+		
+		/* Allocate space for page tables */
+		movl %esi, pt_loc
+		movl $ballocs, %edi
+		andl $0x7fffffff, %edi
+		
+		movl %esi, (%edi)
+		addl $4, %edi
+		movl $(2 * 1024 * 1024), (%edi)
+		
+		/* Fill page tables */
+		xorl %ecx, %ecx
+		xorl %ebx, %ebx
+		
+		floop_pt:
+			movl $((1 << 1) | (1 << 0)), %eax
+			orl %ebx, %eax
+			movl %eax, (%esi, %ecx, 4)
+			addl $(4 * 1024), %ebx
+			
+			incl %ecx
+			cmpl $(512 * 1024), %ecx
+			
+			jl floop_pt
+		
+		/* Fill page directory */
+		movl $(page_directory + 0), %esi
+		movl $(page_directory + 2048), %edi
+		xorl %ecx, %ecx
+		movl pt_loc, %ebx
+		
+		floop:
+			movl $((1 << 1) | (1 << 0)), %eax
+			orl %ebx, %eax
+			
+			/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+			movl %eax, (%esi, %ecx, 4)
+			
+			/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+			movl %eax, (%edi, %ecx, 4)
+			addl $(4 * 1024), %ebx
+			
+			incl %ecx
+			cmpl $512, %ecx
+			
+			jl floop
+		
+		movl %esi, %cr3
+		
+		movl %cr0, %ebx
+		orl $(1 << 31), %ebx  /* paging on */
+		movl %ebx, %cr0
+		
+		ret
+
+/** Calculate unmapped address of the end of the kernel. */
+calc_kernel_end:
+	movl $hardcoded_load_address, %edi
 	andl $0x7fffffff, %edi
-	movl %esi, (%edi)
-	addl $4, %edi
-	movl $(2*1024*1024), (%edi)
-	
-	/* Fill page tables */
-	xorl %ecx, %ecx
-	xorl %ebx, %ebx
-	
-	floop_pt:
-		movl $((1 << 1) | (1 << 0)), %eax
-		orl %ebx, %eax
-		movl %eax, (%esi, %ecx, 4)
-		addl $(4 * 1024), %ebx
-		
-		incl %ecx
-		cmpl $(512 * 1024), %ecx
-		jl floop_pt
-	
-	/* Fill page directory */
-	movl $(page_directory + 0), %esi
-	movl $(page_directory + 2048), %edi
-	xorl %ecx, %ecx
-	movl pt_loc, %ebx
-	
-	floop:
-		movl $((1 << 1) | (1 << 0)), %eax
-		orl %ebx, %eax
-		/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-		movl %eax, (%esi, %ecx, 4)
-		/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-		movl %eax, (%edi, %ecx, 4)
-		addl $(4 * 1024), %ebx
-		
-		incl %ecx
-		cmpl $512, %ecx
-		jl floop
-	
-	movl %esi, %cr3
-	
-	movl %cr0, %ebx
-	orl $(1 << 31), %ebx  /* paging on */
-	movl %ebx, %cr0
+	movl (%edi), %esi
+	andl $0x7fffffff, %esi
+	
+	movl $hardcoded_ktext_size, %edi
+	andl $0x7fffffff, %edi
+	addl (%edi), %esi
+	andl $0x7fffffff, %esi
+	
+	movl $hardcoded_kdata_size, %edi
+	andl $0x7fffffff, %edi
+	addl (%edi), %esi
+	andl $0x7fffffff, %esi
+	movl %esi, kernel_end
+	
 	ret
+
+/** Find free 2M (+4k for alignment) region where to store page tables */
+find_mem_for_pt:
+	/* Check if multiboot info is present */
+	cmpl $MULTIBOOT_LOADER_MAGIC, grub_eax
+	je check_multiboot_map
+		
+		ret
+	
+	check_multiboot_map:
+		
+		/* Copy address of the multiboot info to ebx */
+		movl grub_ebx, %ebx
+		
+		/* Check if memory map flag is present */
+		movl (%ebx), %edx
+		andl $(1 << 6), %edx
+		jnz use_multiboot_map
+			
+			ret
+		
+	use_multiboot_map:
+		
+		/* Copy address of the memory map to edx */
+		movl 48(%ebx), %edx
+		movl %edx, %ecx
+		
+		addl 44(%ebx), %ecx
+		
+		/* Find a free region at least 2M in size */
+		check_memmap_loop:
+			
+			/* Is this a free region? */
+			cmp $1, 20(%edx)
+			jnz next_region
+			
+			/* Check size */
+			cmp $0, 16(%edx)
+			jnz next_region
+			
+			cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
+			jbe next_region
+			
+			cmp $0, 8(%edx)
+			jz found_region
+		
+		next_region:
+			
+			cmp %ecx, %edx
+			jbe next_region_do
+			
+				ret
+		
+		next_region_do:
+			
+			addl (%edx), %edx
+			addl $4, %edx
+			jmp check_memmap_loop
+			
+		found_region:
+			
+			/* Use end of the found region */
+			mov 4(%edx), %ecx
+			add 12(%edx), %ecx
+			sub $(2 * 1024 * 1024), %ecx
+			mov %ecx, free_area
+			
+			ret
 
 /** Print string to EGA display (in light red) and halt.
@@ -610,5 +707,4 @@
 grub_eax:
 	.long 0
-
 grub_ebx:
 	.long 0
@@ -616,14 +712,15 @@
 pt_loc:
 	.long 0
-end_of_kernel:
+kernel_end:
 	.long 0
 free_area:
 	.long 0
 
-err_pse:
-	.asciz "Page Size Extension not supported. System halted."
-
 status_prot:
 	.asciz "[prot] "
+status_pse:
+	.asciz "[pse] "
+status_non_pse:
+	.asciz "[non_pse] "
 status_vesa_copy:
 	.asciz "[vesa_copy] "
@@ -634,4 +731,6 @@
 status_prot2:
 	.asciz "[prot2] "
+status_prot3:
+	.asciz "[prot3] "
 status_main:
 	.asciz "[main] "
Index: kernel/arch/ia32/src/syscall.c
===================================================================
--- kernel/arch/ia32/src/syscall.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/arch/ia32/src/syscall.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -40,4 +40,5 @@
 
 #ifndef PROCESSOR_i486
+
 /** Enable & setup support for SYSENTER/SYSEXIT */
 void syscall_setup_cpu(void)
@@ -50,5 +51,6 @@
 	write_msr(IA32_MSR_SYSENTER_EIP, (uint32_t) sysenter_handler);
 }
-#endif
+
+#endif /* PROCESSOR_i486 */
 
 /** @}
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/generic/include/ipc/ipc.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -98,5 +98,8 @@
 typedef struct {
 	sysarg_t args[IPC_CALL_LEN];
-	/** Task which made or forwarded the call with IPC_FF_ROUTE_FROM_ME. */
+	/**
+	 * Task which made or forwarded the call with IPC_FF_ROUTE_FROM_ME,
+	 * or the task which answered the call.
+	 */
 	task_id_t task_id;
 	/** Phone which made or last masqueraded this call. */
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/generic/src/ipc/ipc.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -230,4 +230,6 @@
 		}
 	}
+
+	call->data.task_id = TASK->taskid;
 	
 	if (do_lock)
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ kernel/generic/src/ipc/sysipc.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -253,7 +253,4 @@
 			/* The connection was accepted */
 			phone_connect(phoneid, &answer->sender->answerbox);
-			/* Set 'task ID' as arg3 and arg4 of response */
-			IPC_SET_ARG3(answer->data, LOWER32(TASK->taskid));
-			IPC_SET_ARG4(answer->data, UPPER32(TASK->taskid));
 			/* Set 'phone hash' as arg5 of response */
 			IPC_SET_ARG5(answer->data,
Index: uspace/app/bdsh/compl.c
===================================================================
--- uspace/app/bdsh/compl.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/app/bdsh/compl.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -37,4 +38,5 @@
 #include "compl.h"
 #include "exec.h"
+#include "tok.h"
 
 static int compl_init(wchar_t *text, size_t pos, size_t *cstart, void **state);
@@ -88,5 +90,4 @@
 {
 	compl_t *cs = NULL;
-	size_t p;
 	size_t pref_size;
 	char *stext = NULL;
@@ -96,4 +97,8 @@
 	static const char *dirlist_arg[] = { ".", NULL };
 	int retval;
+	tokenizer_t tok;
+	token_t tokens[WORD_MAX];
+	unsigned int current_token;
+	size_t tokens_length;
 
 	cs = calloc(1, sizeof(compl_t));
@@ -103,21 +108,44 @@
 	}
 
-	/*
-	 * Copy token pointed to by caret from start up to the caret.
-	 * XXX Ideally we would use the standard tokenizer.
-	 */
-	p = pos;
-	while (p > 0 && text[p - 1] != (wchar_t) ' ')
-		--p;
-	*cstart = p;
-
 	/* Convert text buffer to string */
-	stext = wstr_to_astr(text + *cstart);
+	stext = wstr_to_astr(text);
 	if (stext == NULL) {
 		retval = ENOMEM;
 		goto error;
 	}
-
-	/* Extract the prefix being completed */
+	
+	/* Tokenize the input string */
+	retval = tok_init(&tok, stext, tokens, WORD_MAX);
+	if (retval != EOK) {
+		goto error;
+	}
+	
+	retval = tok_tokenize(&tok, &tokens_length);
+	if (retval != EOK) {
+		goto error;
+	}
+	
+	/* Find the current token */
+	for (current_token = 0; current_token < tokens_length; current_token++) {
+		token_t *t = &tokens[current_token];
+		size_t end = t->char_start + t->char_length;
+		/* Check if the caret lies inside the token or immediately
+		 * after it
+		 */
+		if (t->char_start <= pos && pos <= end) {
+			break;
+		}
+	}
+	
+	if (tokens[current_token].type != TOKTYPE_SPACE) {
+		*cstart = tokens[current_token].char_start;
+	}
+	else {
+		*cstart = pos;
+	}
+	
+	/* Extract the prefix being completed
+	 * XXX: handle strings, etc.
+	 */
 	pref_size = str_lsize(stext, pos - *cstart);
 	prefix = malloc(pref_size + 1);
@@ -127,5 +155,6 @@
 	}
 
-	str_ncpy(prefix, pref_size + 1, stext, pref_size);
+	str_ncpy(prefix, pref_size + 1, stext +
+	    tokens[current_token].byte_start, pref_size);
 
 	/*
@@ -133,10 +162,11 @@
 	 * We look at the previous token. If there is none or it is a pipe
 	 * ('|'), it is a command, otherwise it is an argument.
-	 * XXX Again we should use the standard tokenizer/parser.
 	 */
 
 	/* Skip any whitespace before current token */
-	while (p > 0 && text[p - 1] == (wchar_t) ' ')
-		--p;
+	int prev_token = current_token - 1;
+	if (prev_token != -1 && tokens[prev_token].type == TOKTYPE_SPACE) {
+		prev_token--;
+	}
 
 	/*
@@ -144,5 +174,5 @@
 	 * follows a pipe token.
 	 */
-	if (p == 0 || text[p - 1] == '|')
+	if (prev_token == -1 || tokens[prev_token].type == TOKTYPE_SPACE)
 		cs->is_command = true;
 	else
@@ -189,4 +219,6 @@
 
 	cs->prefix_len = str_length(cs->prefix);
+	
+	tok_fini(&tok);
 
 	*state = cs;
@@ -195,4 +227,6 @@
 error:
 	/* Error cleanup */
+	
+	tok_fini(&tok);
 
 	if (cs != NULL && cs->path_list != NULL) {
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/app/bdsh/input.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Tim Post
  * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -67,9 +68,10 @@
 {
 	char *cmd[WORD_MAX];
+	token_t tokens_space[WORD_MAX];
+	token_t *tokens = tokens_space;
 	int rc = 0;
 	tokenizer_t tok;
-	int i, pipe_count, processed_pipes;
-	int pipe_pos[2];
-	char **actual_cmd;
+	unsigned int i, pipe_count, processed_pipes;
+	unsigned int pipe_pos[2];
 	char *redir_from = NULL;
 	char *redir_to = NULL;
@@ -78,12 +80,22 @@
 		return CL_EFAIL;
 
-	rc = tok_init(&tok, usr->line, cmd, WORD_MAX);
+	rc = tok_init(&tok, usr->line, tokens, WORD_MAX);
 	if (rc != EOK) {
 		goto finit;
 	}
 	
-	rc = tok_tokenize(&tok);
+	size_t tokens_length;
+	rc = tok_tokenize(&tok, &tokens_length);
 	if (rc != EOK) {
 		goto finit;
+	}
+	
+	if (tokens_length > 0 && tokens[0].type == TOKTYPE_SPACE) {
+		tokens++;
+		tokens_length--;
+	}
+	
+	if (tokens_length > 0 && tokens[tokens_length-1].type == TOKTYPE_SPACE) {
+		tokens_length--;
 	}
 	
@@ -93,7 +105,6 @@
 	 * First find the pipes and check that there are no more
 	 */
-	int cmd_length = 0;
-	for (i = 0, pipe_count = 0; cmd[i] != NULL; i++, cmd_length++) {
-		if (cmd[i][0] == '|') {
+	for (i = 0, pipe_count = 0; i < tokens_length; i++) {
+		if (tokens[i].type == TOKTYPE_PIPE) {
 			if (pipe_count >= 2) {
 				print_pipe_usage();
@@ -106,12 +117,14 @@
 	}
 	
-	actual_cmd = cmd;
+	unsigned int cmd_token_start = 0;
+	unsigned int cmd_token_end = tokens_length;
+	
 	processed_pipes = 0;
 	
 	/* Check if the first part (from <file> |) is present */
-	if (pipe_count > 0 && pipe_pos[0] == 2 && str_cmp(cmd[0], "from") == 0) {
+	if (pipe_count > 0 && (pipe_pos[0] == 3 || pipe_pos[0] == 4) && str_cmp(tokens[0].text, "from") == 0) {
 		/* Ignore the first three tokens (from, file, pipe) and set from */
-		redir_from = cmd[1];
-		actual_cmd = cmd + 3;
+		redir_from = tokens[2].text;
+		cmd_token_start = pipe_pos[0]+1;
 		processed_pipes++;
 	}
@@ -119,10 +132,11 @@
 	/* Check if the second part (| to <file>) is present */
 	if ((pipe_count - processed_pipes) > 0 &&
-	    pipe_pos[processed_pipes] == cmd_length - 3 &&
-	    str_cmp(cmd[cmd_length-2], "to") == 0) {
+	    (pipe_pos[processed_pipes] == tokens_length - 4 ||
+	    (pipe_pos[processed_pipes] == tokens_length - 5 &&
+	    tokens[tokens_length-4].type == TOKTYPE_SPACE )) &&
+	    str_cmp(tokens[tokens_length-3].text, "to") == 0) {
 		/* Ignore the last three tokens (pipe, to, file) and set to */
-		redir_to = cmd[cmd_length-1];
-		cmd[cmd_length-3] = NULL;
-		cmd_length -= 3;
+		redir_to = tokens[tokens_length-1].text;
+		cmd_token_end = pipe_pos[processed_pipes];
 		processed_pipes++;
 	}
@@ -134,5 +148,14 @@
 	}
 	
-	if (actual_cmd[0] == NULL) {
+	/* Convert tokens of the command to string array */
+	unsigned int cmd_pos = 0;
+	for (i = cmd_token_start; i < cmd_token_end; i++) {
+		if (tokens[i].type != TOKTYPE_SPACE) {
+			cmd[cmd_pos++] = tokens[i].text;
+		}
+	}
+	cmd[cmd_pos++] = NULL;
+	
+	if (cmd[0] == NULL) {
 		print_pipe_usage();
 		rc = ENOTSUP;
@@ -170,8 +193,8 @@
 	}
 
-	if (str_cmp(actual_cmd[0], "batch") == 0 && actual_cmd[1] != NULL) {
-		FILE *batch = fopen(actual_cmd[1], "r");
+	if (str_cmp(cmd[0], "batch") == 0 && cmd[1] != NULL) {
+		FILE *batch = fopen(cmd[1], "r");
 		if (batch == NULL) {
-			printf("Cannot open file %s\n", actual_cmd[1]);
+			printf("Cannot open file %s\n", cmd[1]);
 			rc = errno;
 		} else {
@@ -211,6 +234,6 @@
 		}
 	} else {
-		rc = run_command(actual_cmd, usr, &new_iostate);
-	}	
+		rc = run_command(cmd, usr, &new_iostate);
+	}
 	
 finit_with_files:
Index: uspace/app/bdsh/tok.c
===================================================================
--- uspace/app/bdsh/tok.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/app/bdsh/tok.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -42,4 +42,5 @@
 static bool tok_pending_chars(tokenizer_t *);
 static int tok_finish_string(tokenizer_t *);
+static void tok_start_token(tokenizer_t *, token_type_t);
 
 /** Initialize the token parser
@@ -50,15 +51,16 @@
  * @param max_tokens number of elements of the out_tokens array
  */
-int tok_init(tokenizer_t *tok, char *input, char **out_tokens,
+int tok_init(tokenizer_t *tok, char *input, token_t *out_tokens,
     size_t max_tokens)
 {	
 	tok->in = input;
 	tok->in_offset = 0;
+	tok->last_in_offset = 0;
+	tok->in_char_offset = 0;
+	tok->last_in_char_offset = 0;
 	
 	tok->outtok = out_tokens;
 	tok->outtok_offset = 0;
-	/* Leave one slot for a null terminator */
-	assert(max_tokens > 0);
-	tok->outtok_size = max_tokens - 1;
+	tok->outtok_size = max_tokens;
 	
 	/* Prepare a buffer where all the token strings will be stored */
@@ -87,14 +89,13 @@
 
 /** Tokenize the input string into the tokens */
-int tok_tokenize(tokenizer_t *tok)
+int tok_tokenize(tokenizer_t *tok, size_t *tokens_length)
 {
 	int rc;
-	wchar_t cur_char;
+	wchar_t next_char;
 	
 	/* Read the input line char by char and append tokens */
-	while ((cur_char = tok_get_char(tok)) != 0) {
-		if (cur_char == ' ') {
-			/* Spaces delimit tokens, but are not processed in any way
-			 * Push the token if there is any.
+	while ((next_char = tok_look_char(tok)) != 0) {
+		if (next_char == ' ') {
+			/* Push the token if there is any.
 			 * There may not be any pending char for a token in case
 			 * there are several spaces in the input.
@@ -106,8 +107,15 @@
 				}
 			}
-		}
-		else if (cur_char == '|') {
-			/* Pipes are tokens that are delimiters and should be output
-			 * as a separate token
+			tok_start_token(tok, TOKTYPE_SPACE);
+			/* Eat all the spaces */
+			while (tok_look_char(tok) == ' ') {
+				tok_push_char(tok, tok_get_char(tok));
+			}
+			tok_push_token(tok);
+			
+		}
+		else if (next_char == '|') {
+			/* Pipes are tokens that are delimiters and should be
+			 * output as a separate token
 			 */
 			if (tok_pending_chars(tok)) {
@@ -118,5 +126,7 @@
 			}
 			
-			rc = tok_push_char(tok, '|');
+			tok_start_token(tok, TOKTYPE_PIPE);
+			
+			rc = tok_push_char(tok, tok_get_char(tok));
 			if (rc != EOK) {
 				return rc;
@@ -128,8 +138,11 @@
 			}
 		}
-		else if (cur_char == '\'') {
+		else if (next_char == '\'') {
 			/* A string starts with a quote (') and ends again with a quote.
 			 * A literal quote is written as ''
 			 */
+			tok_start_token(tok, TOKTYPE_TEXT);
+			/* Eat the quote */
+			tok_get_char(tok);
 			rc = tok_finish_string(tok);
 			if (rc != EOK) {
@@ -138,8 +151,11 @@
 		}
 		else {
+			if (!tok_pending_chars(tok)) {
+				tok_start_token(tok, TOKTYPE_TEXT);
+			}
 			/* If we are handling any other character, just append it to
 			 * the current token.
 			 */
-			rc = tok_push_char(tok, cur_char);
+			rc = tok_push_char(tok, tok_get_char(tok));
 			if (rc != EOK) {
 				return rc;
@@ -156,7 +172,5 @@
 	}
 	
-	/* We always have a space for the terminator, as we
-	 * reserved it in tok_init */
-	tok->outtok[tok->outtok_offset] = 0;
+	*tokens_length = tok->outtok_offset;
 	
 	return EOK;
@@ -167,8 +181,10 @@
 {
 	int rc;
-	wchar_t cur_char;
-	
-	while ((cur_char = tok_get_char(tok)) != 0) {
-		if (cur_char == '\'') {
+	wchar_t next_char;
+	
+	while ((next_char = tok_look_char(tok)) != 0) {
+		if (next_char == '\'') {
+			/* Eat the quote */
+			tok_get_char(tok);
 			if (tok_look_char(tok) == '\'') {
 				/* Encode a single literal quote */
@@ -187,5 +203,5 @@
 		}
 		else {
-			rc = tok_push_char(tok, cur_char);
+			rc = tok_push_char(tok, tok_get_char(tok));
 			if (rc != EOK) {
 				return rc;
@@ -201,4 +217,5 @@
 wchar_t tok_get_char(tokenizer_t *tok)
 {
+	tok->in_char_offset++;
 	return str_decode(tok->in, &tok->in_offset, STR_NO_LIMIT);
 }
@@ -207,7 +224,9 @@
 wchar_t tok_look_char(tokenizer_t *tok)
 {
-	size_t old_offset = tok->in_offset;
+	unsigned int old_offset = tok->in_offset;
+	unsigned int old_char_offset = tok->in_char_offset;
 	wchar_t ret = tok_get_char(tok);
 	tok->in_offset = old_offset;
+	tok->in_char_offset = old_char_offset;
 	return ret;
 }
@@ -219,4 +238,9 @@
 }
 
+void tok_start_token(tokenizer_t *tok, token_type_t type)
+{
+	tok->current_type = type;
+}
+
 /** Push the current token to the output array */
 int tok_push_token(tokenizer_t *tok)
@@ -231,6 +255,16 @@
 	
 	tok->outbuf[tok->outbuf_offset++] = 0;
-	tok->outtok[tok->outtok_offset++] = tok->outbuf + tok->outbuf_last_start;
+	token_t *tokinfo = &tok->outtok[tok->outtok_offset++];
+	tokinfo->type = tok->current_type;
+	tokinfo->text = tok->outbuf + tok->outbuf_last_start;
+	tokinfo->byte_start = tok->last_in_offset;
+	tokinfo->byte_length = tok->in_offset - tok->last_in_offset;
+	tokinfo->char_start = tok->last_in_char_offset;
+	tokinfo->char_length = tok->in_char_offset - tok->last_in_char_offset;
 	tok->outbuf_last_start = tok->outbuf_offset;
+	
+	/* We have consumed the first char of the next token already */
+	tok->last_in_offset = tok->in_offset;
+	tok->last_in_char_offset = tok->in_char_offset;
 	
 	return EOK;
Index: uspace/app/bdsh/tok.h
===================================================================
--- uspace/app/bdsh/tok.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/app/bdsh/tok.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -30,7 +30,25 @@
 #define TOK_H
 
+typedef enum {
+	TOKTYPE_TEXT,
+	TOKTYPE_PIPE,
+	TOKTYPE_SPACE
+} token_type_t;
+
+typedef struct {
+	char *text;
+	unsigned int byte_start;
+	unsigned int char_start;
+	size_t byte_length;
+	size_t char_length;
+ 	token_type_t type;
+} token_t;
+
 typedef struct {
 	char *in;
-	size_t in_offset;
+	unsigned int in_offset;
+	unsigned int last_in_offset;
+	unsigned int in_char_offset;
+	unsigned int last_in_char_offset;
 	
 	char *outbuf;
@@ -39,12 +57,13 @@
 	size_t outbuf_last_start;
 	
-	char **outtok;
+	token_t *outtok;
+	token_type_t current_type;
 	size_t outtok_offset;
 	size_t outtok_size;
 } tokenizer_t;
 
-extern int tok_init(tokenizer_t *, char *, char **, size_t);
+extern int tok_init(tokenizer_t *, char *, token_t *, size_t);
 extern void tok_fini(tokenizer_t *);
-extern int tok_tokenize(tokenizer_t *);
+extern int tok_tokenize(tokenizer_t *, size_t *);
 
 #endif
Index: uspace/lib/c/arch/ia32/Makefile.common
===================================================================
--- uspace/lib/c/arch/ia32/Makefile.common	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/arch/ia32/Makefile.common	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -28,8 +28,9 @@
 
 CLANG_ARCH = i386
+
 ifeq ($(PROCESSOR),i486)
-GCC_CFLAGS += -march=i486 -fno-omit-frame-pointer
+	GCC_CFLAGS += -march=i486 -fno-omit-frame-pointer
 else
-GCC_CFLAGS += -march=pentium -fno-omit-frame-pointer
+	GCC_CFLAGS += -march=pentium -fno-omit-frame-pointer
 endif
 
Index: uspace/lib/c/arch/ia32/src/entry.S
===================================================================
--- uspace/lib/c/arch/ia32/src/entry.S	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/arch/ia32/src/entry.S	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -46,5 +46,5 @@
 	mov %ax, %fs
 	# Do not set %gs, it contains descriptor that can see TLS
-
+	
 #ifndef PROCESSOR_i486	
 	# Detect the mechanism used for making syscalls
@@ -53,8 +53,9 @@
 	bt $(INTEL_SEP), %edx
 	jnc 0f
-	leal __syscall_fast_func, %eax
-	movl $__syscall_fast, (%eax)
-0:
+		leal __syscall_fast_func, %eax
+		movl $__syscall_fast, (%eax)
+	0:
 #endif
+	
 	#
 	# Create the first stack frame.
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/generic/async.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -98,4 +98,5 @@
 #include <ipc/ipc.h>
 #include <async.h>
+#include "private/async.h"
 #undef LIBC_ASYNC_C_
 
@@ -113,5 +114,4 @@
 #include <stdlib.h>
 #include <macros.h>
-#include "private/async.h"
 
 #define CLIENT_HASH_TABLE_BUCKETS  32
@@ -996,4 +996,7 @@
 	session_ns->arg3 = 0;
 	
+	fibril_mutex_initialize(&session_ns->remote_state_mtx);
+	session_ns->remote_state_data = NULL;
+	
 	list_initialize(&session_ns->exch_list);
 	fibril_mutex_initialize(&session_ns->mutex);
@@ -1472,17 +1475,19 @@
 		return ENOENT;
 	
-	task_id_t task_id;
-	sysarg_t task_id_lo;
-	sysarg_t task_id_hi;
 	sysarg_t phone_hash;
-	int rc = async_req_3_5(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
-	    NULL, NULL, &task_id_lo, &task_id_hi, &phone_hash);
+	sysarg_t rc;
+
+	aid_t req;
+	ipc_call_t answer;
+	req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
+	    &answer);
+	async_wait_for(req, &rc);
 	if (rc != EOK)
-		return rc;
-
-	task_id = (task_id_t) MERGE_LOUP32(task_id_lo, task_id_hi);
-	
+		return (int) rc;
+
+	phone_hash = IPC_GET_ARG5(answer);
+
 	if (client_receiver != NULL)
-		async_new_connection(task_id, phone_hash, 0, NULL,
+		async_new_connection(answer.in_task_id, phone_hash, 0, NULL,
 		    client_receiver, carg);
 	
@@ -1559,4 +1564,7 @@
 	sess->arg3 = 0;
 	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
 	list_initialize(&sess->exch_list);
 	fibril_mutex_initialize(&sess->mutex);
@@ -1640,4 +1648,7 @@
 	sess->arg3 = arg3;
 	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
 	list_initialize(&sess->exch_list);
 	fibril_mutex_initialize(&sess->mutex);
@@ -1690,4 +1701,7 @@
 	sess->arg3 = arg3;
 	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
 	list_initialize(&sess->exch_list);
 	fibril_mutex_initialize(&sess->mutex);
@@ -1720,4 +1734,7 @@
 	sess->arg2 = 0;
 	sess->arg3 = 0;
+	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
 	
 	list_initialize(&sess->exch_list);
@@ -2384,4 +2401,7 @@
 	sess->arg3 = 0;
 	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
 	list_initialize(&sess->exch_list);
 	fibril_mutex_initialize(&sess->mutex);
@@ -2430,4 +2450,7 @@
 	sess->arg3 = 0;
 	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
 	list_initialize(&sess->exch_list);
 	fibril_mutex_initialize(&sess->mutex);
@@ -2471,4 +2494,7 @@
 	sess->arg2 = 0;
 	sess->arg3 = 0;
+	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
 	
 	list_initialize(&sess->exch_list);
@@ -2512,4 +2538,74 @@
 }
 
+/** Lock and get session remote state
+ *
+ * Lock and get the local replica of the remote state
+ * in stateful sessions. The call should be paired
+ * with async_remote_state_release*().
+ *
+ * @param[in] sess Stateful session.
+ *
+ * @return Local replica of the remote state.
+ *
+ */
+void *async_remote_state_acquire(async_sess_t *sess)
+{
+	fibril_mutex_lock(&sess->remote_state_mtx);
+	return sess->remote_state_data;
+}
+
+/** Update the session remote state
+ *
+ * Update the local replica of the remote state
+ * in stateful sessions. The remote state must
+ * be already locked.
+ *
+ * @param[in] sess  Stateful session.
+ * @param[in] state New local replica of the remote state.
+ *
+ */
+void async_remote_state_update(async_sess_t *sess, void *state)
+{
+	assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
+	sess->remote_state_data = state;
+}
+
+/** Release the session remote state
+ *
+ * Unlock the local replica of the remote state
+ * in stateful sessions.
+ *
+ * @param[in] sess Stateful session.
+ *
+ */
+void async_remote_state_release(async_sess_t *sess)
+{
+	assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
+	
+	fibril_mutex_unlock(&sess->remote_state_mtx);
+}
+
+/** Release the session remote state and end an exchange
+ *
+ * Unlock the local replica of the remote state
+ * in stateful sessions. This is convenience function
+ * which gets the session pointer from the exchange
+ * and also ends the exchange.
+ *
+ * @param[in] exch Stateful session's exchange.
+ *
+ */
+void async_remote_state_release_exchange(async_exch_t *exch)
+{
+	if (exch == NULL)
+		return;
+	
+	async_sess_t *sess = exch->sess;
+	assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
+	
+	async_exchange_end(exch);
+	fibril_mutex_unlock(&sess->remote_state_mtx);
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/async_obsolete.c
===================================================================
--- uspace/lib/c/generic/async_obsolete.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/generic/async_obsolete.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -38,4 +38,5 @@
 #include <async.h>
 #include <async_obsolete.h>
+#include "private/async.h"
 #undef LIBC_ASYNC_C_
 #undef LIBC_ASYNC_OBSOLETE_C_
@@ -44,5 +45,4 @@
 #include <malloc.h>
 #include <errno.h>
-#include "private/async.h"
 
 /** Send message and return id of the sent message.
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/generic/ipc.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -47,4 +47,5 @@
 #include <futex.h>
 #include <fibril.h>
+#include <macros.h>
 
 /**
@@ -611,5 +612,5 @@
 /** Request callback connection.
  *
- * The @a taskhash and @a phonehash identifiers returned
+ * The @a task_id and @a phonehash identifiers returned
  * by the kernel can be used for connection tracking.
  *
@@ -618,5 +619,5 @@
  * @param arg2      User defined argument.
  * @param arg3      User defined argument.
- * @param taskhash  Opaque identifier of the client task.
+ * @param task_id   Identifier of the client task.
  * @param phonehash Opaque identifier of the phone that will
  *                  be used for incoming calls.
@@ -626,8 +627,14 @@
  */
 int ipc_connect_to_me(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
-    sysarg_t *taskhash, sysarg_t *phonehash)
-{
-	return ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2,
-	    arg3, NULL, NULL, NULL, taskhash, phonehash);
+    task_id_t *task_id, sysarg_t *phonehash)
+{
+	ipc_call_t data;
+	int rc = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid,
+	    IPC_M_CONNECT_TO_ME, arg1, arg2, arg3, (sysarg_t) &data);
+	if (rc == EOK) {
+		*task_id = data.in_task_id;
+		*phonehash = IPC_GET_ARG5(data);
+	}	
+	return rc;
 }
 
Index: uspace/lib/c/generic/private/async.h
===================================================================
--- uspace/lib/c/generic/private/async.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/generic/private/async.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -36,9 +36,58 @@
 #define LIBC_PRIVATE_ASYNC_H_
 
-#include <ipc/common.h>
+#include <async.h>
 #include <adt/list.h>
 #include <fibril.h>
+#include <fibril_synch.h>
 #include <sys/time.h>
 #include <bool.h>
+
+/** Session data */
+struct _async_sess {
+	/** List of inactive exchanges */
+	list_t exch_list;
+	
+	/** Exchange management style */
+	exch_mgmt_t mgmt;
+	
+	/** Session identification */
+	int phone;
+	
+	/** First clone connection argument */
+	sysarg_t arg1;
+	
+	/** Second clone connection argument */
+	sysarg_t arg2;
+	
+	/** Third clone connection argument */
+	sysarg_t arg3;
+	
+	/** Exchange mutex */
+	fibril_mutex_t mutex;
+	
+	/** Number of opened exchanges */
+	atomic_t refcnt;
+	
+	/** Mutex for stateful connections */
+	fibril_mutex_t remote_state_mtx;
+	
+	/** Data for stateful connections */
+	void *remote_state_data;
+};
+
+/** Exchange data */
+struct _async_exch {
+	/** Link into list of inactive exchanges */
+	link_t sess_link;
+	
+	/** Link into global list of inactive exchanges */
+	link_t global_link;
+	
+	/** Session pointer */
+	async_sess_t *sess;
+	
+	/** Exchange identification */
+	int phone;
+};
 
 /** Structures of this type are used to track the timeout events. */
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/include/async.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -42,5 +42,4 @@
 #include <ipc/common.h>
 #include <fibril.h>
-#include <fibril_synch.h>
 #include <sys/time.h>
 #include <atomic.h>
@@ -96,45 +95,10 @@
 } exch_mgmt_t;
 
-/** Session data */
-typedef struct {
-	/** List of inactive exchanges */
-	list_t exch_list;
-	
-	/** Exchange management style */
-	exch_mgmt_t mgmt;
-	
-	/** Session identification */
-	int phone;
-	
-	/** First clone connection argument */
-	sysarg_t arg1;
-	
-	/** Second clone connection argument */
-	sysarg_t arg2;
-	
-	/** Third clone connection argument */
-	sysarg_t arg3;
-	
-	/** Exchange mutex */
-	fibril_mutex_t mutex;
-	
-	/** Number of opened exchanges */
-	atomic_t refcnt;
-} async_sess_t;
-
-/** Exchange data */
-typedef struct {
-	/** Link into list of inactive exchanges */
-	link_t sess_link;
-	
-	/** Link into global list of inactive exchanges */
-	link_t global_link;
-	
-	/** Session pointer */
-	async_sess_t *sess;
-	
-	/** Exchange identification */
-	int phone;
-} async_exch_t;
+/** Forward declarations */
+struct _async_exch;
+struct _async_sess;
+
+typedef struct _async_sess async_sess_t;
+typedef struct _async_exch async_exch_t;
 
 extern atomic_t threads_in_ipc_wait;
@@ -485,4 +449,9 @@
 extern int async_state_change_finalize(ipc_callid_t, async_exch_t *);
 
+extern void *async_remote_state_acquire(async_sess_t *);
+extern void async_remote_state_update(async_sess_t *, void *);
+extern void async_remote_state_release(async_sess_t *);
+extern void async_remote_state_release_exchange(async_exch_t *);
+
 #endif
 
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/c/include/ipc/ipc.h	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -254,5 +254,5 @@
     sysarg_t, sysarg_t, void *, ipc_async_callback_t, bool);
 
-extern int ipc_connect_to_me(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t *,
+extern int ipc_connect_to_me(int, sysarg_t, sysarg_t, sysarg_t, task_id_t *,
     sysarg_t *);
 extern int ipc_connect_me(int);
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision 921b84f17d66df121cdd2a54834689bec11033b1)
+++ uspace/lib/clui/tinput.c	(revision 5fb32c52ce08918112449b76f4c157af6f071530)
@@ -591,4 +591,43 @@
 }
 
+/* Print a list of completions */
+static void tinput_show_completions(tinput_t *ti, char **compl, size_t cnum)
+{
+	unsigned int i;
+	/* Determine the maximum length of the completion in chars */
+	size_t max_length = 0;
+	for (i = 0; i < cnum; i++)
+		max_length = max(max_length, str_length(compl[i]));
+	
+	unsigned int cols = max(1, (ti->con_cols + 1) / (max_length + 1));
+	unsigned int col_width = ti->con_cols / cols;
+	unsigned int rows = cnum / cols + ((cnum % cols) != 0);
+	
+	unsigned int row, col;
+	
+	for (row = 0; row < rows; row++) {
+		bool wlc = false;
+		for (col = 0; col < cols; col++) {
+			size_t compl_idx = col * rows + row;
+			if (compl_idx >= cnum)
+				break;
+			if (col)
+				printf(" ");
+			printf("%s", compl[compl_idx]);
+			size_t compl_len = str_length(compl[compl_idx]);
+			if (col == cols -1) {
+				wlc = (compl_len == max_length);
+			}
+			else {
+				for (i = compl_len; i < col_width; i++) {
+					printf(" ");
+				}
+			}
+		}
+		if (!wlc) printf("\n");
+	}
+}
+
+
 static void tinput_text_complete(tinput_t *ti)
 {
@@ -676,6 +715,5 @@
 
 			tinput_jump_after(ti);
-			for (i = 0; i < cnum; i++)
-				printf("%s\n", compl[i]);
+			tinput_show_completions(ti, compl, cnum);
 			tinput_display(ti);
 		}
