Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision bdfd3c978d7f3378bdc591ff4fe153a17d5c2ea3)
+++ uspace/app/top/top.c	(revision dec16a201da62c0794357ded365e573a55387037)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
  * All rights reserved.
  *
@@ -38,92 +39,142 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <uptime.h>
 #include <task.h>
 #include <thread.h>
 #include <sys/time.h>
-#include <load.h>
-#include <ps.h>
 #include <arch/barrier.h>
+#include <errno.h>
 #include "screen.h"
 #include "input.h"
 #include "top.h"
-#include "ps.h"
-
-#define UPDATE_INTERVAL 1
-
-#define DAY 86400
-#define HOUR 3600
-#define MINUTE 60
+
+#define NAME  "top"
+
+#define UPDATE_INTERVAL  1
+
+#define DAY     86400
+#define HOUR    3600
+#define MINUTE  60
 
 int operation_type;
 
-static void read_data(data_t *target)
+static const char *read_data(data_t *target)
 {
-	/* Read current time */
+	/* Initialize data */
+	target->load = NULL;
+	target->cpus = NULL;
+	target->cpus_perc = NULL;
+	target->tasks = NULL;
+	target->tasks_perc = NULL;
+	target->threads = NULL;
+	target->physmem = NULL;
+	
+	/* Get current time */
 	struct timeval time;
-	if (gettimeofday(&time, NULL) != 0) {
-		printf("Cannot get time of day!\n");
-		exit(1);
-	}
+	if (gettimeofday(&time, NULL) != EOK)
+		return "Cannot get time of day";
+	
 	target->hours = (time.tv_sec % DAY) / HOUR;
 	target->minutes = (time.tv_sec % HOUR) / MINUTE;
 	target->seconds = time.tv_sec % MINUTE;
-
-	/* Read uptime */
-	uint64_t uptime;
-	get_uptime(&uptime);
-	target->uptime_d = uptime / DAY;
-	target->uptime_h = (uptime % DAY) / HOUR;
-	target->uptime_m = (uptime % HOUR) / MINUTE;
-	target->uptime_s = uptime % MINUTE;
-
-	/* Read load */
-	get_load(target->load);
-
-	/* Read task ids */
-	target->task_count = get_tasks(&target->taskinfos);
-
-	/* Read all threads */
-	target->thread_count = get_threads(&target->thread_infos);
-
-	/* Read cpu infos */
-	target->cpu_count = get_cpu_infos(&target->cpus);
-
-	/* Read mem info */
-	get_mem_info(&target->mem_info);
+	
+	/* Get uptime */
+	sysarg_t uptime = stats_get_uptime();
+	target->udays = uptime / DAY;
+	target->uhours = (uptime % DAY) / HOUR;
+	target->uminutes = (uptime % HOUR) / MINUTE;
+	target->useconds = uptime % MINUTE;
+	
+	/* Get load */
+	target->load = stats_get_load(&(target->load_count));
+	if (target->load == NULL)
+		return "Cannot get system load";
+	
+	/* Get CPUs */
+	target->cpus = stats_get_cpus(&(target->cpus_count));
+	if (target->cpus == NULL)
+		return "Cannot get CPUs";
+	
+	target->cpus_perc =
+	    (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
+	if (target->cpus_perc == NULL)
+		return "Not enough memory for CPU utilization";
+	
+	/* Get tasks */
+	target->tasks = stats_get_tasks(&(target->tasks_count));
+	if (target->tasks == NULL)
+		return "Cannot get tasks";
+	
+	target->tasks_perc =
+	    (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
+	if (target->tasks_perc == NULL)
+		return "Not enough memory for task utilization";
+	
+	/* Get threads */
+	target->threads = stats_get_threads(&(target->threads_count));
+	if (target->threads == NULL)
+		return "Cannot get threads";
+	
+	/* Get physical memory */
+	target->physmem = stats_get_physmem();
+	if (target->physmem == NULL)
+		return "Cannot get physical memory";
+	
+	return NULL;
 }
 
 /** Computes percentage differencies from old_data to new_data
  *
- * @param old_data	Pointer to old data strucutre.
- * @param new_data	Pointer to actual data where percetages are stored.
- *
- */
-static void compute_percentages(data_t *old_data, data_t *new_data)
+ * @param old_data Pointer to old data strucutre.
+ * @param new_data Pointer to actual data where percetages are stored.
+ *
+ */
+static const char *compute_percentages(data_t *old_data, data_t *new_data)
 {
-	/* Foreach cpu, compute total ticks and divide it between user and
-	 * system */
-	unsigned int i;
-	new_data->cpu_perc = malloc(new_data->cpu_count * sizeof(cpu_perc_t));
-	for (i = 0; i < new_data->cpu_count; ++i) {
-		uint64_t idle = new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
-		uint64_t busy = new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
+	/* Allocate memory */
+	
+	uint64_t *ucycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (ucycles_diff == NULL)
+		return "Not enough memory for user utilization";
+	
+	uint64_t *kcycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (kcycles_diff == NULL) {
+		free(ucycles_diff);
+		return "Not enough memory for kernel utilization";
+	}
+	
+	/* For each CPU: Compute total ticks and divide it between
+	   user and kernel */
+	
+	size_t i;
+	for (i = 0; i < new_data->cpus_count; i++) {
+		uint64_t idle =
+		    new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
+		uint64_t busy =
+		    new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
 		uint64_t sum = idle + busy;
-		FRACTION_TO_FLOAT(new_data->cpu_perc[i].idle, idle * 100, sum);
-		FRACTION_TO_FLOAT(new_data->cpu_perc[i].busy, busy * 100, sum);
-	}
-
+		
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
+	}
+	
 	/* For all tasks compute sum and differencies of all cycles */
-	uint64_t mem_total = 1; /*< Must NOT be null! */
-	uint64_t ucycles_total = 1; /*< Must NOT be null! */
-	uint64_t kcycles_total = 1; /*< Must NOT be null! */
-	uint64_t *ucycles_diff = malloc(new_data->task_count * sizeof(uint64_t));
-	uint64_t *kcycles_diff = malloc(new_data->task_count * sizeof(uint64_t));
-	unsigned int j = 0;
-	for (i = 0; i < new_data->task_count; ++i) {
-		/* Jump over all death tasks */
-		while (old_data->taskinfos[j].taskid < new_data->taskinfos[i].taskid)
-			++j;
-		if (old_data->taskinfos[j].taskid > new_data->taskinfos[i].taskid) {
+	
+	uint64_t virtmem_total = 1;  /* Must NOT be zero */
+	uint64_t ucycles_total = 1;  /* Must NOT be zero */
+	uint64_t kcycles_total = 1;  /* Must NOT be zero */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		/* Match task with the previous instance */
+		
+		bool found = false;
+		size_t j;
+		for (j = 0; j < old_data->tasks_count; j++) {
+			if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
+				found = true;
+				break;
+			}
+		}
+		
+		if (!found) {
 			/* This is newly borned task, ignore it */
 			ucycles_diff[i] = 0;
@@ -131,93 +182,122 @@
 			continue;
 		}
-		/* Now we now we have task with same id */
-		ucycles_diff[i] = new_data->taskinfos[i].ucycles - old_data->taskinfos[j].ucycles;
-		kcycles_diff[i] = new_data->taskinfos[i].kcycles - old_data->taskinfos[j].kcycles;
-
-		mem_total += new_data->taskinfos[i].virt_mem;
+		
+		ucycles_diff[i] =
+		    new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
+		kcycles_diff[i] =
+		    new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
+		
+		virtmem_total += new_data->tasks[i].virtmem;
 		ucycles_total += ucycles_diff[i];
 		kcycles_total += kcycles_diff[i];
 	}
-
-	/* And now compute percental change */
-	new_data->task_perc = malloc(new_data->task_count * sizeof(task_perc_t));
-	for (i = 0; i < new_data->task_count; ++i) {
-		FRACTION_TO_FLOAT(new_data->task_perc[i].mem, new_data->taskinfos[i].virt_mem * 100, mem_total);
-		FRACTION_TO_FLOAT(new_data->task_perc[i].ucycles, ucycles_diff[i] * 100, ucycles_total);
-		FRACTION_TO_FLOAT(new_data->task_perc[i].kcycles, kcycles_diff[i] * 100, kcycles_total);
-	}
-
-	/* Wait until coprocessor finishes its work */
-	write_barrier();
-
-	/* And free temporary structures */
+	
+	/* For each task: Compute percential change */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
+		    new_data->tasks[i].virtmem * 100, virtmem_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
+		    ucycles_diff[i] * 100, ucycles_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
+		    kcycles_diff[i] * 100, kcycles_total);
+	}
+	
+	/* Cleanup */
+	
 	free(ucycles_diff);
 	free(kcycles_diff);
+	
+	return NULL;
 }
 
 static void free_data(data_t *target)
 {
-	free(target->taskinfos);
-	free(target->thread_infos);
-	free(target->cpus);
-	free(target->cpu_perc);
-	free(target->task_perc);
+	if (target->load != NULL)
+		free(target->load);
+	
+	if (target->cpus != NULL)
+		free(target->cpus);
+	
+	if (target->cpus_perc != NULL)
+		free(target->cpus_perc);
+	
+	if (target->tasks != NULL)
+		free(target->tasks);
+	
+	if (target->tasks_perc != NULL)
+		free(target->tasks_perc);
+	
+	if (target->threads != NULL)
+		free(target->threads);
+	
+	if (target->physmem != NULL)
+		free(target->physmem);
 }
-
-static inline void swap(data_t **first, data_t **second)
-{
-	data_t *temp;
-	temp = *first;
-	*first = *second;
-	*second = temp;
-}
-
-static data_t data[2];
 
 int main(int argc, char *argv[])
 {
-	data_t *data1 = &data[0];
-	data_t *data2 = &data[1];
+	data_t data;
+	data_t data_prev;
+	const char *ret = NULL;
+	
 	screen_init();
-
-	/* Read initial stats */
 	printf("Reading initial data...\n");
-	read_data(data1);
+	
+	if ((ret = read_data(&data_prev)) != NULL)
+		goto out;
+	
 	/* Compute some rubbish to have initialised values */
-	compute_percentages(data1, data1);
-
-	/* And paint screen until death... */
+	if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
+		goto out;
+	
+	/* And paint screen until death */
 	operation_type = OP_TASKS;
 	while (true) {
 		char c = tgetchar(UPDATE_INTERVAL);
 		if (c < 0) {
-			read_data(data2);
-			compute_percentages(data1, data2);
-			free_data(data1);
-			print_data(data2);
-			swap(&data1, &data2);
+			if ((ret = read_data(&data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			if ((ret = compute_percentages(&data_prev, &data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			print_data(&data);
+			free_data(&data_prev);
+			data_prev = data;
+			
 			continue;
 		}
+		
 		switch (c) {
 			case 'q':
-				clear_screen();
-				return 0;
+				goto out;
 			case 'i':
-				PRINT_WARNING("Showing IPC statistics", c);
+				print_warning("Showing IPC statistics");
 				operation_type = OP_IPC;
 				break;
 			case 't':
-				PRINT_WARNING("Showing task stats", c);
+				print_warning("Showing task statistics");
 				operation_type = OP_TASKS;
 				break;
 			default:
-				PRINT_WARNING("Unknown command: %c", c);
+				print_warning("Unknown command: %c", c);
 				break;
 		}
-
-	}
-
-	free_data(data1);
-	free_data(data2);
+	}
+	
+out:
+	screen_done();
+	free_data(&data_prev);
+	
+	if (ret != NULL) {
+		fprintf(stderr, "%s: %s\n", NAME, ret);
+		return 1;
+	}
+	
 	return 0;
 }
