summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--doc/syscalls.txt1
-rw-r--r--gdb-cmd2
-rw-r--r--menu_fdd.cfg2
-rw-r--r--src/include/gc/syscall.h2
-rw-r--r--src/kernel/Makefile2
-rw-r--r--src/kernel/core/kmain.c3
-rw-r--r--src/kernel/core/monitor.h3
-rw-r--r--src/kernel/core/sys.c2
-rw-r--r--src/kernel/core/test.c31
-rw-r--r--src/kernel/core/test.h6
-rw-r--r--src/kernel/lib/stdlib.h3
-rw-r--r--src/kernel/linker/elf.c2
-rw-r--r--src/kernel/mem/heap.c26
-rw-r--r--src/kernel/mem/mem.c2
-rw-r--r--src/kernel/mem/paging.c15
-rw-r--r--src/kernel/task/idt.c8
-rw-r--r--src/kernel/task/syscall.c2
-rw-r--r--src/kernel/task/task.c29
-rw-r--r--src/kernel/task/task.h5
-rw-r--r--src/library/gc/syscall.c19
-rw-r--r--src/modules/test/main.c9
22 files changed, 136 insertions, 44 deletions
diff --git a/Makefile b/Makefile
index 6a014ec..192c867 100644
--- a/Makefile
+++ b/Makefile
@@ -44,4 +44,8 @@ bochs: all floppy
bochs -f bochs.cfg
qemu: all floppy
- qemu -fda $(Floppy) -m 8
+ qemu -fda $(Floppy) -m 16
+
+qemu-gdb: all floppy
+ qemu -fda $(Floppy) -m 16 -s -S & gdb src/kernel/kernel.elf -x gdb-cmd
+
diff --git a/doc/syscalls.txt b/doc/syscalls.txt
index 67b4b3c..8053b38 100644
--- a/doc/syscalls.txt
+++ b/doc/syscalls.txt
@@ -11,6 +11,7 @@ id=eax Name Parameters Description
4 printk ebx: addr of a string Print a message to screen
5 thread_new ebx: entry point Creates a new thread
ecx: data pointer
+ edx: stack pointer
6 irq_wait ebx: irq number Waits for an IRQ (requires privilege PL_DRIVER)
7 proc_priv none Returns current process privilege level
8 shm_create ebx: offset Create a shared memory segment at offset (ret = errcode)
diff --git a/gdb-cmd b/gdb-cmd
new file mode 100644
index 0000000..4c32a6e
--- /dev/null
+++ b/gdb-cmd
@@ -0,0 +1,2 @@
+target remote localhost:1234
+break core/sys.c:panic_do
diff --git a/menu_fdd.cfg b/menu_fdd.cfg
index 1d3504c..551c1e8 100644
--- a/menu_fdd.cfg
+++ b/menu_fdd.cfg
@@ -1,3 +1,5 @@
+timeout 1
+
title Grapes
kernel /kernel.elf
module /manager.elf
diff --git a/src/include/gc/syscall.h b/src/include/gc/syscall.h
index 9ac6748..e6005c1 100644
--- a/src/include/gc/syscall.h
+++ b/src/include/gc/syscall.h
@@ -25,6 +25,8 @@ struct user_sendrequest {
int errcode;
};
+#define NEW_STACK_SIZE 0x8000
+
void thread_exit();
void schedule();
void thread_sleep(int time);
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index e807fc0..757349f 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -1,5 +1,5 @@
Out = kernel.elf
-Obj = core/loader_.o core/kmain.o core/sys.o \
+Obj = core/loader_.o core/kmain.o core/sys.o core/test.o \
core/monitor.o task/timer.o \
task/idt.o task/idt_.o task/task.o task/task_.o task/syscall.o task/sched.o \
lib/stdlib.o lib/bitset.o lib/mutex.o \
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 65a39e6..6c9700e 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -2,6 +2,7 @@
#include "multiboot.h"
#include "monitor.h"
#include "sys.h"
+#include "test.h"
#include <task/idt.h>
#include <task/timer.h>
#include <task/task.h>
@@ -63,6 +64,8 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) {
}
}
+ test_run();
+
monitor_write("Modules now RULE THE WORLD !\n");
sti();
tasking_switch();
diff --git a/src/kernel/core/monitor.h b/src/kernel/core/monitor.h
index c04632e..bb8e16e 100644
--- a/src/kernel/core/monitor.h
+++ b/src/kernel/core/monitor.h
@@ -10,11 +10,12 @@ void monitor_writeHex(uint32_t v);
void monitor_writeDec(uint32_t v);
#define NL monitor_put('\n');
+#define TAB monitor_put('\t');
#define WHERE { monitor_write("(kernel:"); \
monitor_write(__FILE__); \
monitor_write(":"); \
monitor_writeDec(__LINE__); \
- monitor_write(") "); }
+ monitor_write(")\t"); }
#endif
diff --git a/src/kernel/core/sys.c b/src/kernel/core/sys.c
index 56de038..05a7bc5 100644
--- a/src/kernel/core/sys.c
+++ b/src/kernel/core/sys.c
@@ -28,7 +28,7 @@ uint16_t inw(uint16_t port) {
void stack_trace(size_t bp) {
uint32_t *stack = (uint32_t*)bp, i;
for (i = 0; i < 5 && stack > 0xE0000000 && stack < (bp + 0x8000); i++) {
- monitor_write(" "); monitor_writeHex(stack);
+ monitor_write("| "); monitor_writeHex(stack);
monitor_write("\tnext:"); monitor_writeHex(stack[0]); monitor_write("\t\tret:"); monitor_writeHex(stack[1]);
monitor_write("\n");
stack = (uint32_t*)stack[0];
diff --git a/src/kernel/core/test.c b/src/kernel/core/test.c
new file mode 100644
index 0000000..77c7029
--- /dev/null
+++ b/src/kernel/core/test.c
@@ -0,0 +1,31 @@
+#include "test.h"
+#include "monitor.h"
+#include <mem/mem.h>
+#include "sys.h"
+
+#define TEST_KMALLOC(var, sz) monitor_write("kmalloc:"); monitor_writeHex(sz); void *var = kmalloc(sz); \
+ if (var < 0xE0000000) { monitor_write(":FAIL\t"); PANIC("A test failed."); } \
+ else monitor_write(":OK:"); monitor_writeHex(var); monitor_write("\t");
+#define TEST_KFREE(var) if (var != 0) { monitor_write("kfree:"); monitor_writeHex(var); kfree(var); monitor_write(":OK\t"); }
+
+void test_run() {
+ monitor_write("Run kmalloc() and kfree() unit tests:\n");
+ int i;
+ for (i = 1; i <= 5; i++) {
+ monitor_write("\nMALLOC TEST SERIES #"); monitor_writeDec(i); monitor_write(":\n");
+ TEST_KMALLOC(a, 32);
+ TEST_KMALLOC(b, 64);
+ TEST_KMALLOC(c, 256);
+ TEST_KMALLOC(d, 512);
+ TEST_KMALLOC(e, 1024);
+ TEST_KMALLOC(f, 4096);
+ TEST_KMALLOC(g, 16384);
+ TEST_KFREE(b);
+ TEST_KFREE(c);
+ TEST_KFREE(d);
+ TEST_KFREE(e);
+ TEST_KFREE(f);
+ TEST_KFREE(g);
+ }
+ monitor_write("\nUnit tests finished.\n");
+}
diff --git a/src/kernel/core/test.h b/src/kernel/core/test.h
new file mode 100644
index 0000000..ee689c6
--- /dev/null
+++ b/src/kernel/core/test.h
@@ -0,0 +1,6 @@
+#ifndef DEF_TEST_H
+#define DEF_TEST_H
+
+void test_run(); //run basic unit tests on kmalloc() and kfree()
+
+#endif
diff --git a/src/kernel/lib/stdlib.h b/src/kernel/lib/stdlib.h
index 704c410..319cf26 100644
--- a/src/kernel/lib/stdlib.h
+++ b/src/kernel/lib/stdlib.h
@@ -8,5 +8,8 @@ uint8_t *memset(uint8_t *dest, uint8_t val, int count);
uint16_t *memsetw(uint16_t *dest, uint16_t val, int count);
int strlen(const char *str);
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
#endif
diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c
index 6ad5d34..7eaae94 100644
--- a/src/kernel/linker/elf.c
+++ b/src/kernel/linker/elf.c
@@ -44,7 +44,7 @@ struct process* elf_exec(uint8_t *data, int privilege) {
thread_entry e = elf_load(data, p);
- thread_new(p, e, 0);
+ thread_new(p, e, 0, 0);
return p;
}
diff --git a/src/kernel/mem/heap.c b/src/kernel/mem/heap.c
index b7f6c97..79ef81e 100644
--- a/src/kernel/mem/heap.c
+++ b/src/kernel/mem/heap.c
@@ -1,5 +1,8 @@
#include "heap.h"
#include "paging.h"
+#include <core/sys.h>
+
+#include <lib/stdlib.h>
#define HEAP_MAGIC 0xBAD0BEEF
#define HEAP_MIN_SIZE 0x4000
@@ -11,7 +14,7 @@ static void heapIdx_insert(struct heap *heap, struct heap_header *e) {
if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return;
uint32_t iterator = 0, pos;
- while (iterator < heap->idxused && heap->idx[iterator]->size < e->size) {
+ while (iterator < heap->idxused && heap->idx[iterator]->size <= e->size) {
if (heap->idx[iterator] == e) return;
iterator++;
}
@@ -122,15 +125,19 @@ static uint32_t heap_expand(struct heap *heap, size_t quantity) {
/* For internal use only. Called by heap_free when necessary. Reduces the heap's size. */
static void heap_contract(struct heap *heap) {
+ return; //TODO: this function bugs everything
+
+
struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
struct heap_header *last_header = last_footer->header;
if (last_header->is_hole == 0) return;
+ if (last_header->size <= 0x1000) return;
- size_t quantity = 0;
- while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE &&
- (last_header->size - quantity) > 0x1000)
- quantity += 0x1000;
+ size_t quantity = ((heap->end_addr - heap->start_addr) & 0xFFFFF000) - 0x1000;
+ while ((heap->end_addr - heap->start_addr) - quantity < HEAP_MIN_SIZE ||
+ last_header->size - 0x4000 < quantity)
+ quantity -= 0x1000;
if (quantity == 0) return;
size_t newEnd = heap->end_addr - quantity;
@@ -149,6 +156,7 @@ static void heap_contract(struct heap *heap) {
/* Alocate some bytes on the heap. */
void* heap_alloc(struct heap *heap, size_t sz) {
+ ASSERT(heap > 0xE0000000);
size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer);
uint32_t iterator = 0;
@@ -158,17 +166,19 @@ void* heap_alloc(struct heap *heap, size_t sz) {
}
if (iterator == heap->idxused) { //No hole is big enough
- if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED
+ if (heap_expand(heap,
+ MAX((heap->end_addr - heap->start_addr) & 0xFFFFF000, (newsize & 0xFFFFF000) + 0x1000)
+ ) == 0) return 0; //FAILED
return heap_alloc(heap, sz);
}
struct heap_header *loc = heap->idx[iterator];
+ heapIdx_remove(heap, loc);
struct heap_footer *footer = (struct heap_footer*)((size_t)loc + loc->size - sizeof(struct heap_footer));
loc->is_hole = 0;
- heapIdx_remove(heap, loc);
//If we have enough space to create a USEFUL new hole next to the allocated block, do it.
- //If we do not, we might return a block that is a few bytes bigger than neede.
+ //If we do not, we might return a block that is a few bytes bigger than needed.
if (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) {
loc->size = newsize;
diff --git a/src/kernel/mem/mem.c b/src/kernel/mem/mem.c
index 47a03dc..2061aff 100644
--- a/src/kernel/mem/mem.c
+++ b/src/kernel/mem/mem.c
@@ -7,7 +7,7 @@
#define FREEPAGESTOKEEP 5
#define KHEAP_IDXSIZE 0x1000
-#define KHEAP_INITSIZE 0x8000
+#define KHEAP_INITSIZE 0x80000
#define KHEAP_MAXSIZE 0x08000000
size_t mem_placementAddr;
diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c
index f8f69f1..4e5f33a 100644
--- a/src/kernel/mem/paging.c
+++ b/src/kernel/mem/paging.c
@@ -134,13 +134,14 @@ uint32_t paging_fault(struct registers *regs) {
}
if (seg == 0) {
- WHERE; monitor_write("Unhandled Page Fault ");
- if (regs->err_code & 0x1) monitor_write("present ");
- if (regs->err_code & 0x2) monitor_write("write ");
- if (regs->err_code & 0x4) monitor_write("user ");
- if (regs->err_code & 0x8) monitor_write("rsvd ");
- if (regs->err_code & 0x10) monitor_write("instructionfetch ");
- monitor_write("cr2:"); monitor_writeHex(addr); monitor_write("\n");
+ NL; WHERE; monitor_write("Unhandled Page Fault\t");
+ monitor_write("cr2:"); monitor_writeHex(addr);
+ NL; TAB;
+ if (regs->err_code & 0x1) monitor_write("present"); TAB;
+ if (regs->err_code & 0x2) monitor_write("write"); TAB;
+ if (regs->err_code & 0x4) monitor_write("user"); TAB;
+ if (regs->err_code & 0x8) monitor_write("rsvd"); TAB;
+ if (regs->err_code & 0x10) monitor_write("opfetch");
return 1;
}
return 0;
diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c
index 6aa16e0..be5d152 100644
--- a/src/kernel/task/idt.c
+++ b/src/kernel/task/idt.c
@@ -75,11 +75,9 @@ static struct irq_waiter {
void idt_isrHandler(struct registers regs) {
if ((regs.int_no == 14 && paging_fault(&regs) != 0) || regs.int_no != 14) {
if (tasking_handleException(&regs) == 0) {
- monitor_write("\n >> >> SOMETHING BAD HAPPENNED << <<\n");
- monitor_write("Unhandled exception ");
- monitor_writeHex(regs.int_no);
- monitor_write(" @"); monitor_writeHex(regs.eip);
- monitor_put('\n');
+ monitor_write("\nREALLY BAD THIS TIME\t\tUnhandled exception\t#");
+ monitor_writeDec(regs.int_no);
+ monitor_write("\t@"); monitor_writeHex(regs.eip);
PANIC("Unhandled Exception");
}
}
diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c
index 41cd0ea..b490987 100644
--- a/src/kernel/task/syscall.c
+++ b/src/kernel/task/syscall.c
@@ -35,7 +35,7 @@ CALL2(send_msg, send_msg_sc);
CALL2(process_setheapseg, proc_setheap_sc);
static void thread_new_sc(struct registers* r) {
- thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx);
+ thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx);
}
int_callback syscalls[NUMBER_OF_SYSCALLS] = {
diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c
index 7153d85..b8a72ce 100644
--- a/src/kernel/task/task.c
+++ b/src/kernel/task/task.c
@@ -39,7 +39,7 @@ void tasking_init() {
kernel_process->pagedir = kernel_pagedir;
kernel_process->next = 0;
current_thread = 0;
- idle_thread = thread_new(kernel_process, task_idle, 0);
+ idle_thread = thread_new(kernel_process, task_idle, 0, 0);
kernel_process->threads = idle_thread;
sti();
monitor_write("[Tasking] ");
@@ -99,15 +99,15 @@ void tasking_switch() {
Ends the thread for most exceptions, ends the whole process for page faults. */
uint32_t tasking_handleException(struct registers *regs) {
if (current_thread == 0) return 0; //No tasking yet
- NL; WHERE; monitor_write("Unhandled exception : ");
+ NL; WHERE; monitor_write("exception:`");
char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint",
"Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault",
"Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault",
"Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"};
monitor_write(exception_messages[regs->int_no]);
- monitor_write(" eip:"); monitor_writeHex(regs->eip);
+ monitor_write("'\teip:"); monitor_writeHex(regs->eip);
if (regs->eip >= 0xE0000000) {
- monitor_write("\n Exception stack trace :");
+ monitor_write("\n Exception stack trace :\n");
stack_trace(regs->ebp);
PANIC("Kernel error'd.");
}
@@ -194,10 +194,10 @@ void process_exit(uint32_t retval) {
/* For internal use only. This is called when a newly created thread first runs
(its address is the value given for EIP).
It switches to user mode if necessary and calls the entry point. */
-static void thread_run(struct thread *thread, thread_entry entry_point, void *data) {
+static void thread_run(void* u_esp, struct thread *thread, thread_entry entry_point, void *data) {
pagedir_switch(thread->process->pagedir);
if (thread->process->privilege >= PL_SERVICE) { //User mode !
- uint32_t *stack = (uint32_t*)(thread->userStack_seg->start + thread->userStack_seg->len);
+ uint32_t *stack = u_esp;
stack--; *stack = (uint32_t)data;
stack--; *stack = 0;
@@ -239,16 +239,13 @@ static void thread_run(struct thread *thread, thread_entry entry_point, void *da
/* Creates a new thread for given process.
Allocates a kernel stack and a user stack if necessary.
Sets up the kernel stack for values to be passed to thread_run. */
-struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data) {
+struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp) {
struct thread *t = kmalloc(sizeof(struct thread));
t->process = proc;
t->next = 0;
proc->thread_count++;
- if (proc->privilege >= PL_SERVICE) { //We are running in user mode
- proc->stacksBottom -= USER_STACK_SIZE;
- t->userStack_seg = seg_map(simpleseg_make(proc->stacksBottom, USER_STACK_SIZE, 1), proc->pagedir, 0);
- }
+ if (u_esp == 0) u_esp = (void*)proc->stack;
t->kernelStack_addr = kmalloc(KSTACKSIZE);
t->kernelStack_size = KSTACKSIZE;
@@ -259,6 +256,7 @@ struct thread *thread_new(struct process *proc, thread_entry entry_point, void *
stack--; *stack = (uint32_t)data;
stack--; *stack = (uint32_t)entry_point;
stack--; *stack = (uint32_t)t;
+ stack--; *stack = (uint32_t)u_esp;
stack--; *stack = 0;
t->esp = (uint32_t)stack;
t->ebp = t->esp + 8;
@@ -287,9 +285,15 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi
p->parent = parent;
p->pagedir = pagedir_new();
p->next = processes;
- p->stacksBottom = 0xDF000000;
p->heapseg = 0;
+ p->stack = 0;
+ if (p->privilege >= PL_SERVICE) { //We are running in user mode
+ size_t stacksBottom = 0xDF000000;
+ seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0);
+ p->stack = stacksBottom + USER_STACK_SIZE - 4;
+ }
+
p->next_objdesc = 0;
p->objects = 0;
struct object* o = obj_new(p);
@@ -318,7 +322,6 @@ static void thread_delete(struct thread *th) {
if (current_thread == th) current_thread = 0;
th->process->thread_count--;
kfree(th->kernelStack_addr);
- if (th->userStack_seg != 0) seg_unmap(th->userStack_seg);
kfree(th);
}
diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h
index 0a95e57..171a9fd 100644
--- a/src/kernel/task/task.h
+++ b/src/kernel/task/task.h
@@ -26,7 +26,7 @@ struct process {
uint32_t pid, uid, privilege, thread_count;
struct process *parent;
struct page_directory *pagedir;
- size_t stacksBottom;
+ size_t stack;
struct obj_descriptor *objects;
uint32_t next_objdesc;
@@ -44,7 +44,6 @@ struct thread {
uint32_t timeWait;
void* kernelStack_addr;
uint32_t kernelStack_size;
- struct segment_map *userStack_seg;
struct thread *next, *queue_next; //queue_next is used in sched.c
};
@@ -59,7 +58,7 @@ uint32_t tasking_handleException(struct registers *regs);
void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event.
void thread_wakeUp(struct thread *t);
int proc_priv(); //Returns current privilege level
-struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data);
+struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp);
struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege);
void thread_exit(); //syscall
diff --git a/src/library/gc/syscall.c b/src/library/gc/syscall.c
index e7d77a0..b16881e 100644
--- a/src/library/gc/syscall.c
+++ b/src/library/gc/syscall.c
@@ -1,4 +1,5 @@
#include <gc/syscall.h>
+#include <gc/mem.h>
static int call(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f) {
unsigned ret;
@@ -26,8 +27,24 @@ void printk(char* str) {
call(4, (unsigned)str, 0, 0, 0, 0);
}
+//THREAD CREATION
+struct thread_start_data {
+ void (*entry)(void*);
+ void *data;
+ void *stack;
+};
+void thread_start(void *data) {
+ struct thread_start_data *tsd = data;
+ tsd->entry(tsd->data);
+ free(tsd->stack);
+ thread_exit();
+}
void thread_new(void (*entry)(void*), void *data) {
- call(5, (unsigned)entry, (unsigned)data, 0, 0, 0);
+ struct thread_start_data *tsd = malloc(sizeof(struct thread_start_data));
+ tsd->entry = entry;
+ tsd->data = data;
+ tsd->stack = malloc(NEW_STACK_SIZE);
+ call(5, (unsigned)thread_start, (unsigned)tsd, (unsigned)(tsd->stack + NEW_STACK_SIZE), 0, 0);
}
void irq_wait(int number) {
diff --git a/src/modules/test/main.c b/src/modules/test/main.c
index 507567f..493867e 100644
--- a/src/modules/test/main.c
+++ b/src/modules/test/main.c
@@ -30,6 +30,12 @@ void thread2(void* d) {
}
}
+void thread_cascade(void* d) {
+ c_logSvc("{#} Thread cascade element started. Continuing.", LL_STATUS);
+ thread_new(thread_cascade, (void*)((int)d - 1));
+ c_logSvc("{#} Thread cascade element finished.", LL_STATUS);
+}
+
int main() {
c_logSvc("Hi world from unregistered test module !", LL_NOTICE);
c_registerSvc("test");
@@ -38,6 +44,9 @@ int main() {
c_logSvc("{1} Sending a test message to manager", LL_STATUS);
c_nothing(1, 0);
+ c_logSvc("{1} Creating thread cascade len:3", LL_STATUS);
+ thread_new(thread_cascade, (void*)3);
+
c_logSvc("{1} Thread now sleeping...", LL_WARNING);
while (1) thread_sleep(1000);
return 0;