Index: kernel/generic/src/console/cmd.c
===================================================================
--- kernel/generic/src/console/cmd.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/console/cmd.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -886,5 +886,5 @@
 int cmd_sysinfo(cmd_arg_t * argv)
 {
-	sysinfo_dump(NULL, 0);
+	sysinfo_dump(NULL);
 	return 1;
 }
@@ -935,5 +935,5 @@
 int cmd_zones(cmd_arg_t * argv)
 {
-	zone_print_list();
+	zones_print_list();
 	return 1;
 }
Index: kernel/generic/src/cpu/cpu.c
===================================================================
--- kernel/generic/src/cpu/cpu.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/cpu/cpu.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -75,6 +75,4 @@
 			
 			cpus[i].id = i;
-			cpus[i].idle_ticks = 0;
-			cpus[i].busy_ticks = 0;
 			
 			spinlock_initialize(&cpus[i].lock, "cpu_t.lock");
@@ -97,6 +95,4 @@
 	cpu_identify();
 	cpu_arch_init();
-
-	sysinfo_set_item_val("cpu.count", NULL, config.cpu_count);
 }
 
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/main/kinit.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -67,5 +67,5 @@
 #include <debug.h>
 #include <str.h>
-#include <ps/load.h>
+#include <sysinfo/stats.h>
 
 #ifdef CONFIG_SMP
@@ -123,4 +123,5 @@
 		} else
 			panic("Unable to create kmp thread.");
+		
 		thread_join(thread);
 		thread_detach(thread);
@@ -151,4 +152,11 @@
 	arch_post_smp_init();
 	
+	/* Start thread computing system load */
+	thread = thread_create(kload, NULL, TASK, 0, "kload", false);
+	if (thread != NULL)
+		thread_ready(thread);
+	else
+		printf("Unable to create kload thread\n");
+	
 #ifdef CONFIG_KCONSOLE
 	if (stdin) {
@@ -164,11 +172,4 @@
 #endif /* CONFIG_KCONSOLE */
 	
-	/* Start thread computing system load */
-	thread = thread_create(kload_thread, NULL, TASK, 0, "kload", false);
-	if (thread != NULL)
-		thread_ready(thread);
-	else
-		printf("Unable to create kload thread\n");
-
 	interrupts_enable();
 	
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/main/main.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -85,4 +85,5 @@
 #include <ipc/event.h>
 #include <sysinfo/sysinfo.h>
+#include <sysinfo/stats.h>
 
 /** Global configuration structure. */
@@ -225,5 +226,5 @@
 	
 	printf("Detected %" PRIs " CPU(s), %" PRIu64" MiB free memory\n",
-	    config.cpu_count, SIZE2MB(zone_total_size()));
+	    config.cpu_count, SIZE2MB(zones_total_size()));
 
 	LOG_EXEC(cpu_init());
@@ -249,4 +250,5 @@
 	LOG_EXEC(event_init());
 	LOG_EXEC(klog_init());
+	LOG_EXEC(stats_init());
 	
 	/*
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/mm/frame.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -1202,5 +1202,5 @@
 
 /** Return total size of all zones. */
-uint64_t zone_total_size(void)
+uint64_t zones_total_size(void)
 {
 	ipl_t ipl = interrupts_disable();
@@ -1218,28 +1218,37 @@
 }
 
-void zone_busy_and_free(uint64_t *out_busy, uint64_t *out_free)
-{
+void zones_stats(uint64_t *total, uint64_t *unavail, uint64_t *busy,
+    uint64_t *free)
+{
+	ASSERT(total != NULL);
+	ASSERT(unavail != NULL);
+	ASSERT(busy != NULL);
+	ASSERT(free != NULL);
+	
 	ipl_t ipl = interrupts_disable();
 	spinlock_lock(&zones.lock);
-
-	uint64_t busy = 0, free = 0;
+	
+	*total = 0;
+	*unavail = 0;
+	*busy = 0;
+	*free = 0;
+	
 	size_t i;
 	for (i = 0; i < zones.count; i++) {
-		bool available = zone_flags_available(zones.info[i].flags);
-		/* Do not count reserved memory */
-		if (available) {
-			busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
-			free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
-		}
-	}
-
+		*total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
+		
+		if (zone_flags_available(zones.info[i].flags)) {
+			*busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
+			*free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
+		} else
+			*unavail += (uint64_t) FRAMES2SIZE(zones.info[i].count);
+	}
+	
 	spinlock_unlock(&zones.lock);
 	interrupts_restore(ipl);
-	*out_busy = busy;
-	*out_free = free;
 }
 
 /** Prints list of zones. */
-void zone_print_list(void)
+void zones_print_list(void)
 {
 #ifdef __32_BITS__
Index: kernel/generic/src/ps/cpu.c
===================================================================
--- kernel/generic/src/ps/cpu.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ 	(revision )
@@ -1,68 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup genericps
- * @{
- */
-
-/**
- * @file
- * @brief	CPU listing.
- */
-
-#include <ps/ps.h>
-#include <ps/cpuinfo.h>
-#include <arch/asm.h>
-#include <cpu.h>
-#include <syscall/copy.h>
-
-#define WRITE_CPU_INFO(dst, i, src) copy_to_uspace(dst+i, src, sizeof(uspace_cpu_info_t))
-
-int sys_ps_get_cpu_info(uspace_cpu_info_t *uspace_cpu)
-{
-	size_t i;
-	uspace_cpu_info_t cpuinfo;
-	ipl_t ipl;
-	ipl = interrupts_disable();
-
-	for (i = 0; i < config.cpu_count; ++i) {
-		spinlock_lock(&cpus[i].lock);
-		cpuinfo.id = cpus[i].id;
-		cpuinfo.frequency_mhz = cpus[i].frequency_mhz;
-		cpuinfo.busy_ticks = cpus[i].busy_ticks;
-		cpuinfo.idle_ticks = cpus[i].idle_ticks;
-		spinlock_unlock(&cpus[i].lock);
-		WRITE_CPU_INFO(uspace_cpu, i, &cpuinfo);
-	}
-
-	interrupts_restore(ipl);
-	return 0;
-}
-
-/** @}
- */
Index: kernel/generic/src/ps/load.c
===================================================================
--- kernel/generic/src/ps/load.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ 	(revision )
@@ -1,134 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup genericload
- * @{
- */
-
-/**
- * @file
- * @brief	System load computation.
- */
-
-#include <proc/thread.h>
-#include <ps/load.h>
-#include <arch.h>
-#include <proc/scheduler.h>
-#include <config.h>
-#include <arch/types.h>
-#include <time/clock.h>
-#include <syscall/copy.h>
-
-static size_t get_running_count(void);
-
-unsigned long avenrun[3];
-
-#define FSHIFT   11		/* nr of bits of precision */
-#define FIXED_1  (1<<FSHIFT)	/* 1.0 as fixed-point */
-#define LOAD_FREQ 5		/* 5 sec intervals */
-#define EXP_1  1884		/* 1/exp(5sec/1min) as fixed-point */
-#define EXP_5  2014		/* 1/exp(5sec/5min) */
-#define EXP_15 2037		/* 1/exp(5sec/15min) */
-
-void get_avenrun(unsigned long *loads, int shift)
-{
-	loads[0] = avenrun[0] << shift;
-	loads[1] = avenrun[1] << shift;
-	loads[2] = avenrun[2] << shift;
-}
-
-static inline unsigned long calc_load(unsigned long load, size_t exp, size_t active)
-{
-	load *= exp;
-	load += active * (FIXED_1 - exp);
-	return load >> FSHIFT;
-}
-
-static inline void calc_load_global(void)
-{
-	size_t active;
-
-	active = get_running_count();
-	active = active > 0 ? active * FIXED_1 : 0;
-	avenrun[0] = calc_load(avenrun[0], EXP_1, active);
-	avenrun[1] = calc_load(avenrun[1], EXP_5, active);
-	avenrun[2] = calc_load(avenrun[2], EXP_15, active);
-}
-
-static size_t get_running_count(void)
-{
-	size_t i;
-	size_t result = 0;
-	ipl_t ipl;
-
-	/* run queues should not change during reading */
-	ipl = interrupts_disable();
-
-	for (i = 0; i < config.cpu_active; ++i) {
-		cpu_t *cpu = &cpus[i];
-		int j;
-		for (j = 0; j < RQ_COUNT; ++j) {
-			result += cpu->rq[j].n;
-		}
-	} 
-
-	interrupts_restore(ipl);
-	return result;
-}
-
-/** Load thread main function.
- *  Thread computes system load every few seconds.
- *
- *  @param arg		Generic thread argument (unused).
- *
- */
-void kload_thread(void *arg)
-{
-	/* Noone will thread_join us */
-	thread_detach(THREAD);
-	avenrun[0] = 0;
-	avenrun[1] = 0;
-	avenrun[2] = 0;
-
-	while (true) {
-		calc_load_global();
-		thread_sleep(LOAD_FREQ);
-	}
-}
-
-int sys_ps_get_load(unsigned long *user_load)
-{
-	unsigned long loads[3];
-	get_avenrun(loads, 5);
-	copy_to_uspace(user_load, loads, sizeof(loads));
-	return 0;
-}
-
-
-/** @}
- */
Index: kernel/generic/src/ps/mem.c
===================================================================
--- kernel/generic/src/ps/mem.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ 	(revision )
@@ -1,59 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup genericps
- * @{
- */
-
-/**
- * @file
- * @brief	Mem info
- */
-
-#include <ps/meminfo.h>
-#include <ps/ps.h>
-#include <syscall/copy.h>
-#include <mm/frame.h>
-#include <arch.h>
-
-int sys_ps_get_mem_info(uspace_mem_info_t *uspace_mem)
-{
-	uspace_mem_info_t meminfo;
-	ipl_t ipl;
-	ipl = interrupts_disable();
-
-	meminfo.total = zone_total_size();
-	zone_busy_and_free(&meminfo.used, &meminfo.free);
-	interrupts_restore(ipl);
-
-	copy_to_uspace(uspace_mem, &meminfo, sizeof(uspace_mem_info_t));
-	return 0;
-}
-
-/** @}
- */
Index: kernel/generic/src/ps/ps.c
===================================================================
--- kernel/generic/src/ps/ps.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ 	(revision )
@@ -1,214 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup genericps
- * @{
- */
-
-/**
- * @file
- * @brief	Process listing.
- */
-
-#include <proc/task.h>
-#include <proc/thread.h>
-#include <ps/ps.h>
-#include <ps/taskinfo.h>
-#include <adt/avl.h>
-#include <synch/waitq.h>
-#include <syscall/copy.h>
-#include <atomic.h>
-#include <errno.h>
-
-static size_t count;
-static size_t max_count;
-
-#define WRITE_TASK_ID(dst, i, src) copy_to_uspace(dst + i, src, sizeof(task_id_t))
-#define WRITE_THREAD_INFO(dst, i, src) copy_to_uspace(dst+i, src, sizeof(thread_info_t))
-
-static bool task_walker(avltree_node_t *node, void *arg)
-{
-	task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
-	task_id_t *ids = (task_id_t *)arg;
-
-	spinlock_lock(&t->lock);
-
-	++count;
-	if (count > max_count) {
-		spinlock_unlock(&t->lock);
-		return false;
-	}
-
-	WRITE_TASK_ID(ids, count - 1, &t->taskid);
-
-	spinlock_unlock(&t->lock);
-	return true;
-}
-
-size_t sys_ps_get_tasks(task_id_t *uspace_ids, size_t size)
-{
-	ipl_t ipl;
-	
-	/* Messing with task structures, avoid deadlock */
-	ipl = interrupts_disable();
-	spinlock_lock(&tasks_lock);
-
-	count = 0;
-	max_count = size / sizeof(task_id_t);
-	avltree_walk(&tasks_tree, task_walker, uspace_ids);
-
-	spinlock_unlock(&tasks_lock);
-	interrupts_restore(ipl);
-	
-	return count;
-}
-
-static uint64_t get_task_memory(as_t *as)
-{
-	mutex_lock(&as->lock);
-
-	size_t result = 0;
-	
-	link_t *cur;
-	for (cur = as->as_area_btree.leaf_head.next;
-	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
-		btree_node_t *node;
-		
-		node = list_get_instance(cur, btree_node_t, leaf_link);
-		
-		unsigned int i;
-		for (i = 0; i < node->keys; i++) {
-			as_area_t *area = node->value[i];
-		
-			mutex_lock(&area->lock);
-			result += area->pages;
-			mutex_unlock(&area->lock);
-		}
-	}
-	
-	mutex_unlock(&as->lock);
-	
-	return result * PAGE_SIZE;
-}
-
-int sys_ps_get_task_info(task_id_t *uspace_id, task_info_t *uspace_info)
-{
-	ipl_t ipl;
-	ipl = interrupts_disable();
-
-	task_id_t id;
-	copy_from_uspace(&id, uspace_id, sizeof(task_id_t));
-
-	spinlock_lock(&tasks_lock);
-	task_t *t = task_find_by_id(id);
-	if (!t) {
-		spinlock_unlock(&tasks_lock);
-		return ENOENT;
-	}
-	spinlock_lock(&t->lock);
-	spinlock_unlock(&tasks_lock);
-
-	copy_to_uspace(&uspace_info->taskid, &t->taskid, sizeof(task_id_t));
-	copy_to_uspace(uspace_info->name, t->name, sizeof(t->name));
-
-	uint64_t ucycles;
-	uint64_t kcycles;
-	task_get_accounting(t, &ucycles, &kcycles);
-	copy_to_uspace(&uspace_info->ucycles, &ucycles, sizeof(uint64_t));
-	copy_to_uspace(&uspace_info->kcycles, &kcycles, sizeof(uint64_t));
-
-	task_ipc_info_t ipc_info;
-	ipc_info.call_sent = t->ipc_info.call_sent;
-	ipc_info.call_recieved = t->ipc_info.call_recieved;
-	ipc_info.answer_sent = t->ipc_info.answer_sent;
-	ipc_info.answer_recieved = t->ipc_info.answer_recieved;
-	ipc_info.irq_notif_recieved = t->ipc_info.irq_notif_recieved;
-	ipc_info.forwarded = t->ipc_info.forwarded;
-	copy_to_uspace(&uspace_info->ipc_info, &ipc_info, sizeof(task_ipc_info_t));
-
-	uint64_t memory = get_task_memory(t->as);
-	copy_to_uspace(&uspace_info->virt_mem, &memory, sizeof(memory));
-
-	int thread_count = atomic_get(&t->refcount);
-	copy_to_uspace(&uspace_info->thread_count, &thread_count, sizeof(thread_count));
-	
-	spinlock_unlock(&t->lock);
-	interrupts_restore(ipl);
-	return 0;
-}
-
-static bool thread_walker(avltree_node_t *node, void *arg)
-{
-	thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node);
-	thread_info_t *infos = (thread_info_t *)arg;
-	thread_info_t result;
-
-	spinlock_lock(&t->lock);
-
-	++count;
-	if (count > max_count) {
-		spinlock_unlock(&t->lock);
-		return false;
-	}
-	
-	result.tid = t->tid;
-	ASSERT(t->task);
-	result.taskid = t->task->taskid;
-	result.state = t->state;
-	result.priority = t->priority;
-	result.ucycles = t->ucycles;
-	result.kcycles = t->kcycles;
-
-	if (t->cpu)
-		result.cpu = t->cpu->id;
-	else
-		result.cpu = -1;
-
-	WRITE_THREAD_INFO(infos, count - 1, &result);
-
-	spinlock_unlock(&t->lock);
-	return true;
-}
-
-int sys_ps_get_threads(thread_info_t *uspace_infos, size_t size)
-{
-	ipl_t ipl;
-	ipl = interrupts_disable();
-	spinlock_lock(&threads_lock);
-
-	count = 0;
-	max_count = size / sizeof(thread_info_t);
-	avltree_walk(&threads_tree, thread_walker, uspace_infos);
-
-	spinlock_unlock(&threads_lock);
-	interrupts_restore(ipl);
-	return count;
-}
-
-/** @}
- */
Index: kernel/generic/src/ps/uptime.c
===================================================================
--- kernel/generic/src/ps/uptime.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/*
- * Copyright (c) 2010 Stanislav Kozina
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup genericuptime
- * @{
- */
-
-/**
- * @file
- * @brief	Get system uptime.
- */
-
-#include <time/clock.h>
-#include <syscall/copy.h>
-#include <ps/uptime.h>
-
-int sys_ps_get_uptime(uint64_t *user_uptime)
-{
-	uint64_t seconds = uptime->seconds1;
-	copy_to_uspace(user_uptime, &seconds, sizeof(uint64_t));
-	return 0;
-}
-
-
-/** @}
- */
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/syscall/syscall.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -54,7 +54,4 @@
 #include <console/console.h>
 #include <udebug/udebug.h>
-#include <ps/ps.h>
-#include <ps/load.h>
-#include <ps/uptime.h>
 
 /** Dispatch system call */
@@ -147,5 +144,5 @@
 	(syshandler_t) sys_ipc_register_irq,
 	(syshandler_t) sys_ipc_unregister_irq,
-
+	
 	/* Event notification syscalls. */
 	(syshandler_t) sys_event_subscribe,
@@ -170,13 +167,4 @@
 	(syshandler_t) sys_debug_enable_console,
 	(syshandler_t) sys_debug_disable_console,
-
-	/* Ps calls */
-	(syshandler_t) sys_ps_get_cpu_info,
-	(syshandler_t) sys_ps_get_mem_info,
-	(syshandler_t) sys_ps_get_tasks,
-	(syshandler_t) sys_ps_get_task_info,
-	(syshandler_t) sys_ps_get_threads,
-	(syshandler_t) sys_ps_get_uptime,
-	(syshandler_t) sys_ps_get_load,
 	
 	(syshandler_t) sys_ipc_connect_kbox
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
+++ kernel/generic/src/sysinfo/stats.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#include <typedefs.h>
+#include <sysinfo/abi.h>
+#include <sysinfo/stats.h>
+#include <sysinfo/sysinfo.h>
+#include <time/clock.h>
+#include <mm/frame.h>
+#include <proc/thread.h>
+#include <str.h>
+#include <errno.h>
+#include <cpu.h>
+#include <arch.h>
+
+/** Bits of fixed-point precision for load */
+#define LOAD_FIXED_SHIFT  11
+
+/** 1.0 as fixed-point for load */
+#define LOAD_FIXED_1  (1 << LOAD_FIXED_SHIFT)
+
+/** Compute load in 5 second intervals */
+#define LOAD_INTERVAL  5
+
+/**
+ * Fixed-point representation of:
+ *
+ * 1 / exp(5 sec / 1 min)
+ * 1 / exp(5 sec / 5 min)
+ * 1 / exp(5 sec / 15 min)
+ *
+ */
+static load_t load_exp[LOAD_STEPS] = {1884, 2014, 2037};
+static load_t avenrdy[LOAD_STEPS] = {0, 0, 0};
+SPINLOCK_STATIC_INITIALIZE_NAME(load_lock, "load_lock");
+
+static unative_t get_stats_uptime(struct sysinfo_item *item)
+{
+	/* This doesn't have to be very accurate */
+	return uptime->seconds1;
+}
+
+static void *get_stats_cpus(struct sysinfo_item *item, size_t *size)
+{
+	stats_cpu_t *stats_cpus =
+	    (stats_cpu_t *) malloc(sizeof(stats_cpu_t) * config.cpu_count,
+	    FRAME_ATOMIC);
+	if (stats_cpus == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	ipl_t ipl = interrupts_disable();
+	
+	size_t i;
+	for (i = 0; i < config.cpu_count; i++) {
+		spinlock_lock(&cpus[i].lock);
+		
+		stats_cpus[i].id = cpus[i].id;
+		stats_cpus[i].frequency_mhz = cpus[i].frequency_mhz;
+		stats_cpus[i].busy_ticks = cpus[i].busy_ticks;
+		stats_cpus[i].idle_ticks = cpus[i].idle_ticks;
+		
+		spinlock_unlock(&cpus[i].lock);
+	}
+	
+	interrupts_restore(ipl);
+	
+	*size = sizeof(stats_cpu_t) * config.cpu_count;
+	return ((void *) stats_cpus);
+}
+
+static bool task_count_walker(avltree_node_t *node, void *arg)
+{
+	size_t *count = (size_t *) arg;
+	(*count)++;
+	
+	return true;
+}
+
+static bool task_serialize_walker(avltree_node_t *node, void *arg)
+{
+	task_id_t **ids = (task_id_t **) arg;
+	task_t *task = avltree_get_instance(node, task_t, tasks_tree_node);
+	
+	spinlock_lock(&(task->lock));
+	
+	**ids = task->taskid;
+	(*ids)++;
+	
+	spinlock_unlock(&(task->lock));
+	
+	return true;
+}
+
+static void *get_stats_tasks(struct sysinfo_item *item, size_t *size)
+{
+	/* Messing with task structures, avoid deadlock */
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&tasks_lock);
+	
+	size_t count = 0;
+	avltree_walk(&tasks_tree, task_count_walker, (void *) &count);
+	
+	if (count == 0) {
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		
+		*size = 0;
+		return NULL;
+	}
+	
+	task_id_t *task_ids =
+	    (task_id_t *) malloc(sizeof(task_id_t) * count, FRAME_ATOMIC);
+	if (task_ids == NULL) {
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		
+		*size = 0;
+		return NULL;
+	}
+	
+	task_id_t *iterator = task_ids;
+	avltree_walk(&tasks_tree, task_serialize_walker, (void *) &iterator);
+	
+	spinlock_unlock(&tasks_lock);
+	interrupts_restore(ipl);
+	
+	*size = sizeof(task_id_t) * count;
+	return ((void *) task_ids);
+}
+
+static size_t get_task_virtmem(as_t *as)
+{
+	mutex_lock(&as->lock);
+	
+	size_t result = 0;
+	
+	link_t *cur;
+	for (cur = as->as_area_btree.leaf_head.next;
+	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
+		btree_node_t *node =
+		    list_get_instance(cur, btree_node_t, leaf_link);
+		
+		unsigned int i;
+		for (i = 0; i < node->keys; i++) {
+			as_area_t *area = node->value[i];
+			
+			mutex_lock(&area->lock);
+			result += area->pages;
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	mutex_unlock(&as->lock);
+	
+	return result * PAGE_SIZE;
+}
+
+static sysinfo_return_t get_stats_task(const char *name)
+{
+	
+	sysinfo_return_t ret;
+	ret.tag = SYSINFO_VAL_UNDEFINED;
+	
+	task_id_t task_id;
+	if (str_uint64(name, NULL, 0, true, &task_id) != EOK)
+		return ret;
+	
+	stats_task_t *stats_task =
+	    (stats_task_t *) malloc(sizeof(stats_task_t), FRAME_ATOMIC);
+	if (stats_task == NULL)
+		return ret;
+	
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&tasks_lock);
+	
+	task_t *task = task_find_by_id(task_id);
+	if (task == NULL) {
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		free(stats_task);
+		return ret;
+	}
+	
+	spinlock_lock(&task->lock);
+	spinlock_unlock(&tasks_lock);
+	
+	str_cpy(stats_task->name, TASK_NAME_BUFLEN, task->name);
+	stats_task->virtmem = get_task_virtmem(task->as);
+	stats_task->threads = atomic_get(&task->refcount);
+	task_get_accounting(task, &(stats_task->ucycles),
+	    &(stats_task->kcycles));
+	stats_task->ipc_info = task->ipc_info;
+	
+	spinlock_unlock(&task->lock);
+	interrupts_restore(ipl);
+	
+	ret.tag = SYSINFO_VAL_FUNCTION_DATA;
+	ret.data.data = (void *) stats_task;
+	ret.data.size = sizeof(stats_task_t);
+	
+	return ret;
+}
+
+static void *get_stats_physmem(struct sysinfo_item *item, size_t *size)
+{
+	stats_physmem_t *stats_physmem =
+	    (stats_physmem_t *) malloc(sizeof(stats_physmem_t), FRAME_ATOMIC);
+	if (stats_physmem == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	zones_stats(&(stats_physmem->total), &(stats_physmem->unavail),
+	    &(stats_physmem->used), &(stats_physmem->free));
+	
+	*size = sizeof(stats_physmem_t);
+	return ((void *) stats_physmem);
+}
+
+static void *get_stats_load(struct sysinfo_item *item, size_t *size)
+{
+	load_t *stats_load =
+	    (load_t *) malloc(sizeof(load_t) * LOAD_STEPS, FRAME_ATOMIC);
+	if (stats_load == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&load_lock);
+	
+	unsigned int i;
+	for (i = 0; i < LOAD_STEPS; i++)
+		stats_load[i] = avenrdy[i] << LOAD_FIXED_SHIFT;
+	
+	spinlock_unlock(&load_lock);
+	interrupts_restore(ipl);
+	
+	*size = sizeof(load_t) * LOAD_STEPS;
+	return ((void *) stats_load);
+}
+
+/** Calculate load
+ *
+ */
+static inline load_t load_calc(load_t load, load_t exp, size_t ready)
+{
+	load *= exp;
+	load += ready * (LOAD_FIXED_1 - exp);
+	
+	return (load >> LOAD_FIXED_SHIFT);
+}
+
+/** Count threads in ready queues
+ *
+ * Should be called with interrupts disabled.
+ *
+ */
+static inline size_t get_ready_count(void)
+{
+	size_t i;
+	size_t count = 0;
+	
+	for (i = 0; i < config.cpu_count; i++) {
+		spinlock_lock(&cpus[i].lock);
+		
+		size_t j;
+		for (j = 0; j < RQ_COUNT; j++) {
+			spinlock_lock(&cpus[i].rq[j].lock);
+			count += cpus[i].rq[j].n;
+			spinlock_unlock(&cpus[i].rq[j].lock);
+		}
+		
+		spinlock_unlock(&cpus[i].lock);
+	}
+	
+	return count;
+}
+
+/** Load computation thread.
+ *
+ * Compute system load every few seconds.
+ *
+ * @param arg Unused.
+ *
+ */
+void kload(void *arg)
+{
+	thread_detach(THREAD);
+	
+	while (true) {
+		ipl_t ipl = interrupts_disable();
+		spinlock_lock(&load_lock);
+		
+		size_t ready = get_ready_count() * LOAD_FIXED_1;
+		
+		unsigned int i;
+		for (i = 0; i < LOAD_STEPS; i++)
+			avenrdy[i] = load_calc(avenrdy[i], load_exp[i], ready);
+		
+		spinlock_unlock(&load_lock);
+		interrupts_restore(ipl);
+		
+		thread_sleep(LOAD_INTERVAL);
+	}
+}
+
+void stats_init(void)
+{
+	sysinfo_set_item_fn_val("system.uptime", NULL, get_stats_uptime);
+	sysinfo_set_item_fn_data("system.cpus", NULL, get_stats_cpus);
+	sysinfo_set_item_fn_data("system.physmem", NULL, get_stats_physmem);
+	sysinfo_set_item_fn_data("system.load", NULL, get_stats_load);
+	sysinfo_set_item_fn_data("system.tasks", NULL, get_stats_tasks);
+	sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task);
+}
+
+/** @}
+ */
Index: kernel/generic/src/sysinfo/sysinfo.c
===================================================================
--- kernel/generic/src/sysinfo/sysinfo.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/sysinfo/sysinfo.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -37,4 +37,5 @@
 #include <print.h>
 #include <syscall/copy.h>
+#include <synch/spinlock.h>
 #include <errno.h>
 
@@ -45,4 +46,6 @@
 static sysinfo_item_t *global_root = NULL;
 static slab_cache_t *sysinfo_item_slab;
+
+SPINLOCK_STATIC_INITIALIZE_NAME(sysinfo_lock, "sysinfo_lock");
 
 static int sysinfo_item_constructor(void *obj, int kmflag)
@@ -76,7 +79,16 @@
 }
 
+/** Recursively find item in sysinfo tree
+ *
+ * Should be called with interrupts disabled
+ * and sysinfo_lock held.
+ *
+ */
 static sysinfo_item_t *sysinfo_find_item(const char *name,
-    sysinfo_item_t *subtree)
-{
+    sysinfo_item_t *subtree, sysinfo_return_t **ret)
+{
+	ASSERT(subtree != NULL);
+	ASSERT(ret != NULL);
+	
 	sysinfo_item_t *cur = subtree;
 	
@@ -98,10 +110,13 @@
 			case SYSINFO_SUBTREE_TABLE:
 				/* Recursively find in subtree */
-				return sysinfo_find_item(name + i + 1, cur->subtree.table);
+				return sysinfo_find_item(name + i + 1,
+				    cur->subtree.table, ret);
 			case SYSINFO_SUBTREE_FUNCTION:
-				/* Get generated item */
-				return cur->subtree.find_item(name + i + 1);
+				/* Get generated data */
+				**ret = cur->subtree.get_data(name + i + 1);
+				return NULL;
 			default:
 				/* Not found */
+				*ret = NULL;
 				return NULL;
 			}
@@ -111,7 +126,14 @@
 	}
 	
+	*ret = NULL;
 	return NULL;
 }
 
+/** Recursively create items in sysinfo tree
+ *
+ * Should be called with interrupts disabled
+ * and sysinfo_lock held.
+ *
+ */
 static sysinfo_item_t *sysinfo_create_path(const char *name,
     sysinfo_item_t **psubtree)
@@ -224,4 +246,7 @@
     unative_t val)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	if (root == NULL)
 		root = &global_root;
@@ -232,4 +257,7 @@
 		item->val.val = val;
 	}
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
 }
 
@@ -237,4 +265,7 @@
     void *data, size_t size)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	if (root == NULL)
 		root = &global_root;
@@ -246,9 +277,15 @@
 		item->val.data.size = size;
 	}
-}
-
-void sysinfo_set_item_val_fn(const char *name, sysinfo_item_t **root,
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+}
+
+void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
     sysinfo_fn_val_t fn)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	if (root == NULL)
 		root = &global_root;
@@ -259,9 +296,15 @@
 		item->val.fn_val = fn;
 	}
-}
-
-void sysinfo_set_item_data_fn(const char *name, sysinfo_item_t **root,
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+}
+
+void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
     sysinfo_fn_data_t fn)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	if (root == NULL)
 		root = &global_root;
@@ -272,8 +315,14 @@
 		item->val.fn_data = fn;
 	}
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
 }
 
 void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	if (root == NULL)
 		root = &global_root;
@@ -282,6 +331,31 @@
 	if (item != NULL)
 		item->val_type = SYSINFO_VAL_UNDEFINED;
-}
-
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+}
+
+void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
+    sysinfo_fn_subtree_t fn)
+{
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
+	if (root == NULL)
+		root = &global_root;
+	
+	sysinfo_item_t *item = sysinfo_create_path(name, root);
+	if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
+		item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
+		item->subtree.get_data = fn;
+	}
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+}
+
+/** Sysinfo dump indentation helper routine
+ *
+ */
 static void sysinfo_indent(unsigned int depth)
 {
@@ -291,10 +365,16 @@
 }
 
-void sysinfo_dump(sysinfo_item_t **proot, unsigned int depth)
-{
-	if (proot == NULL)
-		proot = &global_root;
-	
-	sysinfo_item_t *cur = *proot;
+/** Dump the structure of sysinfo tree
+ *
+ * Should be called with interrupts disabled
+ * and sysinfo_lock held. Because this routine
+ * might take a reasonable long time to proceed,
+ * having the spinlock held is not optimal, but
+ * there is no better simple solution.
+ *
+ */
+static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
+{
+	sysinfo_item_t *cur = root;
 	
 	while (cur != NULL) {
@@ -302,4 +382,5 @@
 		
 		unative_t val;
+		void *data;
 		size_t size;
 		
@@ -322,5 +403,8 @@
 			break;
 		case SYSINFO_VAL_FUNCTION_DATA:
-			cur->val.fn_data(cur, &size);
+			data = cur->val.fn_data(cur, &size);
+			if (data != NULL)
+				free(data);
+			
 			printf("+ %s (%" PRIs" bytes) [generated]\n", cur->name,
 			    size);
@@ -334,13 +418,13 @@
 			break;
 		case SYSINFO_SUBTREE_TABLE:
-			sysinfo_dump(&(cur->subtree.table), depth + 1);
+			sysinfo_dump_internal(cur->subtree.table, depth + 1);
 			break;
 		case SYSINFO_SUBTREE_FUNCTION:
 			sysinfo_indent(depth + 1);
-			printf("  [generated subtree]\n");
+			printf("+ [generated subtree]\n");
 			break;
 		default:
 			sysinfo_indent(depth + 1);
-			printf("  [unknown subtree]\n");
+			printf("+ [unknown subtree]\n");
 		}
 		
@@ -349,40 +433,65 @@
 }
 
-sysinfo_return_t sysinfo_get_item(const char *name, sysinfo_item_t **root)
+void sysinfo_dump(sysinfo_item_t *root)
+{
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
+	if (root == NULL)
+		sysinfo_dump_internal(global_root, 0);
+	else
+		sysinfo_dump_internal(root, 0);
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+}
+
+/** Return sysinfo item determined by name
+ *
+ * Should be called with interrupts disabled
+ * and sysinfo_lock held.
+ *
+ */
+static sysinfo_return_t sysinfo_get_item(const char *name, sysinfo_item_t **root)
 {
 	if (root == NULL)
 		root = &global_root;
 	
-	sysinfo_item_t *item = sysinfo_find_item(name, *root);
 	sysinfo_return_t ret;
+	sysinfo_return_t *ret_ptr = &ret;
+	sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr);
 	
 	if (item != NULL) {
+		ret.tag = item->val_type;
 		switch (item->val_type) {
 		case SYSINFO_VAL_UNDEFINED:
+			break;
+		case SYSINFO_VAL_VAL:
+			ret.val = item->val.val;
+			break;
+		case SYSINFO_VAL_DATA:
+			ret.data = item->val.data;
+			break;
+		case SYSINFO_VAL_FUNCTION_VAL:
+			ret.val = item->val.fn_val(item);
+			break;
+		case SYSINFO_VAL_FUNCTION_DATA:
+			ret.data.data = item->val.fn_data(item, &ret.data.size);
+			break;
+		}
+	} else {
+		if (ret_ptr == NULL)
 			ret.tag = SYSINFO_VAL_UNDEFINED;
-			break;
-		case SYSINFO_VAL_VAL:
-			ret.tag = SYSINFO_VAL_VAL;
-			ret.val = item->val.val;
-			break;
-		case SYSINFO_VAL_DATA:
-			ret.tag = SYSINFO_VAL_DATA;
-			ret.data = item->val.data;
-			break;
-		case SYSINFO_VAL_FUNCTION_VAL:
-			ret.tag = SYSINFO_VAL_VAL;
-			ret.val = item->val.fn_val(item);
-			break;
-		case SYSINFO_VAL_FUNCTION_DATA:
-			ret.tag = SYSINFO_VAL_DATA;
-			ret.data.data = item->val.fn_data(item, &ret.data.size);
-			break;
-		}
-	} else
-		ret.tag = SYSINFO_VAL_UNDEFINED;
+	}
 	
 	return ret;
 }
 
+/** Return sysinfo item determined by name from user space
+ *
+ * Should be called with interrupts disabled
+ * and sysinfo_lock held.
+ *
+ */
 static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size)
 {
@@ -397,9 +506,8 @@
 	
 	if ((copy_from_uspace(path, ptr, size + 1) == 0)
-	    && (path[size] == 0)) {
+	    && (path[size] == 0))
 		ret = sysinfo_get_item(path, NULL);
-		free(path);
-	}
-	
+	
+	free(path);
 	return ret;
 }
@@ -407,5 +515,21 @@
 unative_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
 {
-	return (unative_t) sysinfo_get_item_uspace(path_ptr, path_size).tag;
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
+	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
+	
+	if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
+		free(ret.data.data);
+	
+	if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
+		ret.tag = SYSINFO_VAL_VAL;
+	else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
+		ret.tag = SYSINFO_VAL_DATA;
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+	
+	return (unative_t) ret.tag;
 }
 
@@ -413,11 +537,22 @@
     void *value_ptr)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
-	
-	if (ret.tag != SYSINFO_VAL_VAL)
-		return (unative_t) EINVAL;
-	
-	return (unative_t) copy_to_uspace(value_ptr, &ret.val,
-	    sizeof(ret.val));
+	int rc;
+	
+	if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
+		rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
+	else
+		rc = EINVAL;
+	
+	if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
+		free(ret.data.data);
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+	
+	return (unative_t) rc;
 }
 
@@ -425,11 +560,23 @@
     void *size_ptr)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
-	
-	if (ret.tag != SYSINFO_VAL_DATA)
-		return (unative_t) EINVAL;
-	
-	return (unative_t) copy_to_uspace(size_ptr, &ret.data.size,
-	    sizeof(ret.data.size));
+	int rc;
+	
+	if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
+		rc = copy_to_uspace(size_ptr, &ret.data.size,
+		    sizeof(ret.data.size));
+	else
+		rc = EINVAL;
+	
+	if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
+		free(ret.data.data);
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+	
+	return (unative_t) rc;
 }
 
@@ -437,14 +584,26 @@
     void *buffer_ptr, size_t buffer_size)
 {
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sysinfo_lock);
+	
 	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
-	
-	if (ret.tag != SYSINFO_VAL_DATA)
-		return (unative_t) EINVAL;
-	
-	if (ret.data.size != buffer_size)
-		return ENOMEM;
-	
-	return (unative_t) copy_to_uspace(buffer_ptr, ret.data.data,
-	    ret.data.size);
+	int rc;
+	
+	if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
+		if (ret.data.size == buffer_size)
+			rc = copy_to_uspace(buffer_ptr, ret.data.data,
+			    ret.data.size);
+		else
+			rc = ENOMEM;
+	} else
+		rc = EINVAL;
+	
+	if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
+		free(ret.data.data);
+	
+	spinlock_unlock(&sysinfo_lock);
+	interrupts_restore(ipl);
+	
+	return (unative_t) rc;
 }
 
Index: kernel/generic/src/time/clock.c
===================================================================
--- kernel/generic/src/time/clock.c	(revision 30a54709ba36bc519d1ad3075734736c27daf220)
+++ kernel/generic/src/time/clock.c	(revision 9dae191e774f517d5430fc726e4aef5787b1fcd0)
@@ -86,5 +86,5 @@
 	uptime->seconds1 = 0;
 	uptime->seconds2 = 0;
-	uptime->useconds = 0; 
+	uptime->useconds = 0;
 
 	clock_parea.pbase = (uintptr_t) faddr;
