summaryrefslogtreecommitdiff
path: root/src/library/gc
diff options
context:
space:
mode:
authorAlexis211 <alexis211@gmail.com>2010-03-30 19:22:23 +0200
committerAlexis211 <alexis211@gmail.com>2010-03-30 19:22:23 +0200
commitad1ec29070e1ffba7461687cd268e64be06aa78b (patch)
tree309ca65d46f1a6164c048d9ba2060275d6d63538 /src/library/gc
parent50152369119ffc92d7790ddcfd26f32613366ede (diff)
downloadTCE-ad1ec29070e1ffba7461687cd268e64be06aa78b.tar.gz
TCE-ad1ec29070e1ffba7461687cd268e64be06aa78b.zip
More work on IPC and userland tools.
Diffstat (limited to 'src/library/gc')
-rw-r--r--src/library/gc/mem.c262
-rw-r--r--src/library/gc/object.c178
-rw-r--r--src/library/gc/syscall.c8
3 files changed, 446 insertions, 2 deletions
diff --git a/src/library/gc/mem.c b/src/library/gc/mem.c
new file mode 100644
index 0000000..fe243ba
--- /dev/null
+++ b/src/library/gc/mem.c
@@ -0,0 +1,262 @@
+#include "gc/mem.h"
+
+struct heap_header {
+ uint32_t magic;
+ uint32_t is_hole;
+ size_t size;
+};
+
+struct heap_footer {
+ uint32_t magic;
+ struct heap_header *header;
+};
+
+struct heap {
+ struct heap_header **idx;
+ uint32_t idxused;
+ size_t start_addr, end_addr, max_end;
+};
+
+int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize);
+void* heap_alloc(struct heap *heap, size_t sz);
+void heap_free(struct heap *heap, void* ptr);
+
+#define HEAP_MAGIC 0xBAD0BEEF
+#define HEAP_MIN_SIZE 0x4000
+
+/* ******************* GENERAL MEMORY FUNCTIONS ******************** */
+
+static struct heap h;
+static int heap_ok = 0;
+
+void* malloc(size_t size) {
+ if (heap_ok == 0) {
+ if (heap_create(&h, 0x20000000, 0x00010000, 0x00100000, 0x4F000000)) return 0;
+ heap_ok = 1;
+ }
+ return heap_alloc(&h, size);
+}
+
+void free(void* p) {
+ if (heap_ok == 0 || (size_t)p < h.start_addr || (size_t)p > h.end_addr) return;
+ heap_free(&h, p);
+}
+
+static int setheapseg (struct heap *heap, size_t start, size_t end, size_t prev_end) { //returns nonzero on error
+ if (heap == &h) {
+ return proc_setheap(start, end);
+ } //otherwise, something else might be done.
+ return -1;
+}
+
+/* ******************* HEAP HEADER ****************** */
+
+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) {
+ if (heap->idx[iterator] == e) return;
+ iterator++;
+ }
+ if (iterator == heap->idxused) {
+ heap->idx[heap->idxused++] = e;
+ } else {
+ pos = iterator;
+ iterator = heap->idxused;
+ while (iterator > pos) {
+ heap->idx[iterator] = heap->idx[iterator - 1];
+ iterator--;
+ }
+ heap->idxused++;
+ heap->idx[pos] = e;
+ }
+}
+
+static void heapIdx_remove(struct heap *heap, struct heap_header *e) {
+ uint32_t iterator;
+ for (iterator = 0; iterator < heap->idxused; iterator++) {
+ if (heap->idx[iterator] == e) break;
+ }
+ if (iterator == heap->idxused) return;
+ heap->idxused--;
+ while (iterator < heap->idxused) {
+ heap->idx[iterator] = heap->idx[iterator + 1];
+ iterator++;
+ }
+}
+
+/* ******************** HEAP CONTENTS ********************* */
+
+int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize) {
+ if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000;
+
+ heap->start_addr = start + idxsize;
+ heap->end_addr = start + idxsize + datasize;
+ heap->max_end = start + idxsize + maxdatasize;
+
+ if (setheapseg(heap, start, heap->end_addr, 0)) return -1;
+
+ heap->idx = (struct heap_header**)start;
+ heap->idxused = 0;
+
+ struct heap_header *hole = (struct heap_header*) heap->start_addr;
+ hole->size = (heap->end_addr - heap->start_addr);
+ hole->magic = HEAP_MAGIC;
+ hole->is_hole = 1;
+
+ struct heap_footer *hole_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ hole_footer->header = hole;
+ hole_footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, hole);
+ return 0;
+}
+
+static uint32_t heap_expand(struct heap *heap, size_t quantity) {
+ if (quantity & 0x0FFF) {
+ quantity = (quantity & 0xFFFFF000) + 0x1000;
+ }
+
+ if (heap->end_addr + quantity > heap->max_end) return 0;
+
+ size_t newEnd = heap->end_addr + quantity;
+
+ if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return 0; //failed to bigger segment
+
+ 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) {
+ heapIdx_remove(heap, last_header);
+ last_header->size += quantity;
+
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ } else {
+ last_header = (struct heap_header*)heap->end_addr;
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+
+ last_header->is_hole = 1;
+ last_header->magic = HEAP_MAGIC;
+ last_header->size = quantity;
+
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ }
+
+ heap->end_addr = newEnd;
+
+ return 1;
+}
+
+static void heap_contract(struct heap *heap) {
+ 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;
+
+ size_t quantity = 0;
+ while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE &&
+ (last_header->size - quantity) > 0x1000)
+ quantity += 0x1000;
+ if (quantity == 0) return;
+
+ size_t newEnd = heap->end_addr - quantity;
+
+ if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return; //error ocurred
+
+ heapIdx_remove(heap, last_header);
+ last_header->size -= quantity;
+ last_footer = (struct heap_footer*)((size_t)last_footer - quantity);
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+ heapIdx_insert(heap, last_header);
+
+ heap->end_addr = newEnd;
+}
+
+void* heap_alloc(struct heap *heap, size_t sz) {
+ size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer);
+ uint32_t iterator = 0;
+
+ while (iterator < heap->idxused) {
+ if (heap->idx[iterator]->size >= newsize) break;
+ iterator++;
+ }
+
+ if (iterator == heap->idxused) { //No hole is big enough
+ if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED
+ return heap_alloc(heap, sz);
+ }
+
+ struct heap_header *loc = heap->idx[iterator];
+ 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 (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) {
+ loc->size = newsize;
+
+ //Write footer for block we return
+ struct heap_footer *newfooter = (struct heap_footer*)((size_t)loc + newsize - sizeof(struct heap_footer));
+ newfooter->header = loc;
+ newfooter->magic = HEAP_MAGIC;
+
+ //Write header for new hole we create
+ struct heap_header *nextloc = (struct heap_header*)((size_t)loc + newsize);
+ nextloc->is_hole = 1;
+ nextloc->magic = HEAP_MAGIC;
+ nextloc->size = ((size_t)footer - (size_t)nextloc + sizeof(struct heap_footer));
+ footer->header = nextloc; //Update footer
+ footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, nextloc);
+ }
+
+ return (void*)((size_t)loc + sizeof(struct heap_header));
+}
+
+void heap_free(struct heap *heap, void* ptr) {
+ if (ptr == 0) return;
+ if ((size_t)ptr < heap->start_addr || (size_t)ptr > heap->end_addr) return;
+
+ struct heap_header *header = (struct heap_header*)((size_t)ptr - sizeof(struct heap_header));
+ struct heap_footer *footer = (struct heap_footer*)((size_t)header + header->size - sizeof(struct heap_footer));
+ if (header->magic != HEAP_MAGIC || footer->magic != HEAP_MAGIC) return;
+
+ //Unify left
+ struct heap_footer *prev_footer = (struct heap_footer*)((size_t)header - sizeof(struct heap_footer));
+ if (prev_footer->magic == HEAP_MAGIC && prev_footer->header->is_hole) {
+ header = prev_footer->header;
+ heapIdx_remove(heap, header);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ //Unify right
+ struct heap_header *next_header = (struct heap_header*)((size_t)footer + sizeof(struct heap_footer));
+ if (next_header->magic == HEAP_MAGIC && next_header->is_hole) {
+ heapIdx_remove(heap, next_header);
+ footer = (struct heap_footer*)((size_t)footer + next_header->size);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ header->is_hole = 1;
+
+ heapIdx_insert(heap, header);
+
+ if ((size_t)footer == (heap->end_addr - sizeof(struct heap_footer)) &&
+ header->size >= 0x2000 && (heap->end_addr - heap->start_addr > HEAP_MIN_SIZE)) {
+ heap_contract(heap);
+ }
+}
diff --git a/src/library/gc/object.c b/src/library/gc/object.c
new file mode 100644
index 0000000..59b986b
--- /dev/null
+++ b/src/library/gc/object.c
@@ -0,0 +1,178 @@
+#include <gc/server.h>
+#include <gm/method.h>
+#include <gc/mem.h>
+
+Server procServer;
+static Server* servers = 0;
+
+static method_handler getHandler(Server *o, uint32_t m);
+static struct method_ret checkIfHandles(struct method_data *d);
+
+void objsrv_init() {
+ procServer.id = 0;
+ procServer.methods = 0;
+ procServer.next = 0;
+ procServer.data = 0;
+ servers = &procServer;
+ srv_addHandler(&procServer, M_HANDLECHECK_BIVV, checkIfHandles);
+}
+
+void srv_handleAll() {
+ Server *i = servers;
+ while (i) {
+ srv_handle(i, HA_ONCE);
+ i = i->next;
+ }
+}
+
+void srv_handle(Server *o, int act) {
+ int i;
+
+ if (act == HA_LOOP) {
+ while (1) srv_handle(o, HA_WAIT);
+ } else {
+ struct user_request rq;
+ int v = request_get(o->id, &rq, (act == HA_WAIT));
+ if (v == 0) {
+ method_handler m = getHandler(o, rq.func);
+ if (m == 0) {
+ if (rq.isBlocking) {
+ request_answer(o->id, 0, 0, ME_UNHANDLED);
+ }
+ } else {
+ struct method_data md;
+ md.func = rq.func;
+ md.blocking = rq.isBlocking;
+ md.obj = o;
+ //get parameters
+ for (i = 0; i < 3; i++) {
+ md.parameters[i].type = (rq.func >> (28 - (2 * i))) & 3;
+ switch (md.parameters[i].type) {
+ case PT_LONG:
+ case PT_OBJDESC:
+ md.parameters[i].val.i = rq.params[i];
+ break;
+ case PT_SHM: //all the fuss about keepShm only applies to messages.
+ md.parameters[i].keepShm = 1; //if local memory or if nothing, do not unmap it
+ if (rq.params[i] == 0) { //TODO : map shm (shm manager) !!!
+ md.parameters[i].val.p = 0;
+ //md.parameters[i].keepShm = 0; //we had to map it, so mark it to be unmapped
+ } else {
+ md.parameters[i].val.p = (void*)rq.params[i];
+ }
+ break;
+ }
+ }
+
+ struct method_ret ret = m(&md); //Call method
+ if (rq.isBlocking) {
+ uint32_t a = 0, b = 0;
+ if (ret.type == PT_OBJDESC || ret.type == PT_LONG) a = ret.i;
+ if (ret.type == PT_LONGLONG) a = (uint32_t)ret.l, b = (uint32_t)((uint64_t)ret.l >> 32);
+ request_answer(o->id, a, b, ret.status);
+ } else {
+ for (i = 0; i < 3; i++) {
+ if (md.parameters[i].type == PT_SHM && md.parameters[i].keepShm == 0) {
+ //TODO : unmap shm
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void srv_addHandler(Server* o, uint32_t method, method_handler h) {
+ struct method_srv *s = malloc(sizeof(struct method_srv));
+ s->id = method;
+ s->h = h;
+ s->next = o->methods;
+ o->methods = s;
+}
+
+Server *srv_create() {
+ Server *s = malloc(sizeof(Server));
+ s->id = object_create();
+ s->methods = 0;
+ s->data = 0;
+ s->next = servers;
+ srv_addHandler(s, M_HANDLECHECK_BIVV, checkIfHandles);
+ servers = s;
+ return s;
+}
+
+void srv_delete(Server* s) {
+ //remove s from servers
+ if (servers == s) {
+ servers = s->next;
+ } else {
+ Server *i = servers;
+ while (i->next != 0) {
+ if (i->next == s) {
+ i->next = s->next;
+ break;
+ }
+ i = i->next;
+ }
+ }
+ //close s
+ object_close(s->id);
+ //free methods for s
+ while (s->methods != 0) {
+ struct method_srv *m = s->methods->next;
+ free(s->methods);
+ s->methods = m;
+ }
+ //free s
+ free(s);
+}
+
+// internal use
+
+method_handler getHandler(Server *o, uint32_t m) {
+ struct method_srv *i = o->methods;
+ while (i) {
+ if (i->id == m) return i->h;
+ i = i->next;
+ }
+ return 0;
+}
+
+struct method_ret checkIfHandles(struct method_data *d) {
+ if (getHandler(d->obj, d->parameters[0].val.i) == 0) {
+ return mr_long(0);
+ }
+ return mr_long(1);
+}
+
+// ***************************** HELPER FUNCTIONS FOR RETRUN VALUES
+
+struct method_ret mr_long(int val) {
+ struct method_ret r; r.status = 0; r.type = PT_LONG; r.i = val;
+ return r;
+}
+
+struct method_ret mr_llong(int64_t val) {
+ struct method_ret r; r.status = 0; r.type = PT_LONGLONG; r.l = val;
+ return r;
+}
+
+struct method_ret mr_obj(Object* obj) {
+ struct method_ret r; r.status = 0; r.type = PT_OBJDESC; r.i = obj->id;
+ return r;
+}
+
+struct method_ret mr_srv(Server* obj) {
+ struct method_ret r; r.status = 0; r.type = PT_OBJDESC; r.i = obj->id;
+ return r;
+}
+
+struct method_ret mr_void() {
+ struct method_ret r; r.status = 0; r.type = PT_VOID;
+ return r;
+}
+
+struct method_ret mr_err(int error) {
+ struct method_ret r; r.status = error; r.type = PT_VOID; r.l = 0;
+ return r;
+}
diff --git a/src/library/gc/syscall.c b/src/library/gc/syscall.c
index 8fd1554..e7d77a0 100644
--- a/src/library/gc/syscall.c
+++ b/src/library/gc/syscall.c
@@ -66,8 +66,8 @@ int request_has(int descriptor) {
return call(14, descriptor, 0, 0, 0, 0);
}
-void request_answer(int descriptor, int answer1, int answer2) {
- call(15, descriptor, answer1, answer2, 0, 0);
+void request_answer(int descriptor, uint32_t answer1, uint32_t answer2, int errcode) {
+ call(15, descriptor, answer1, answer2, errcode, 0);
}
int request_mapShm(int descriptor, size_t offset, int number) {
@@ -81,3 +81,7 @@ int request(int descriptor, struct user_sendrequest *rq) {
int send_msg(int descriptor, struct user_sendrequest *rq) {
return call(18, descriptor, (size_t)rq, 0, 0, 0);
}
+
+int proc_setheap(size_t start, size_t end) {
+ return call(19, start, end, 0, 0, 0);
+}