From ad1ec29070e1ffba7461687cd268e64be06aa78b Mon Sep 17 00:00:00 2001 From: Alexis211 Date: Tue, 30 Mar 2010 19:22:23 +0200 Subject: More work on IPC and userland tools. --- src/library/Makefile | 2 + src/library/gc/mem.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++ src/library/gc/object.c | 178 ++++++++++++++++++++++++++++++++ src/library/gc/syscall.c | 8 +- src/library/link.ld | 2 +- src/library/start.c | 1 + 6 files changed, 450 insertions(+), 3 deletions(-) create mode 100644 src/library/gc/mem.c create mode 100644 src/library/gc/object.c (limited to 'src/library') diff --git a/src/library/Makefile b/src/library/Makefile index 74eb525..be5a76d 100644 --- a/src/library/Makefile +++ b/src/library/Makefile @@ -8,6 +8,8 @@ LDFLAGS = -r Library = grapes.o Objects = gc/syscall.o \ + gc/mem.o \ + gc/object.o \ start.o all: $(Library) 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 +#include +#include + +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); +} diff --git a/src/library/link.ld b/src/library/link.ld index 17c944a..be5e028 100644 --- a/src/library/link.ld +++ b/src/library/link.ld @@ -2,7 +2,7 @@ ENTRY (start) INPUT (grapes.o) SECTIONS{ - . = 0x10000000; + . = 0x100000; .text : { *(.text) diff --git a/src/library/start.c b/src/library/start.c index b3c5541..c9a7acc 100644 --- a/src/library/start.c +++ b/src/library/start.c @@ -3,6 +3,7 @@ extern int main(); void start() { + objsrv_init(); int ret = main(); process_exit(ret); } -- cgit v1.2.3