diff options
author | Alexis211 <alexis211@gmail.com> | 2010-03-31 17:26:21 +0200 |
---|---|---|
committer | Alexis211 <alexis211@gmail.com> | 2010-03-31 17:26:21 +0200 |
commit | b945eafa126d6a17aa8826a405df7d5d4d999008 (patch) | |
tree | 34b5ba6f0c13b1b35770375f51183a047271a4d4 /src/library/gc | |
parent | ad1ec29070e1ffba7461687cd268e64be06aa78b (diff) | |
download | TCE-b945eafa126d6a17aa8826a405df7d5d4d999008.tar.gz TCE-b945eafa126d6a17aa8826a405df7d5d4d999008.zip |
Shared memory segment manager in userland
Diffstat (limited to 'src/library/gc')
-rw-r--r-- | src/library/gc/object.c | 25 | ||||
-rw-r--r-- | src/library/gc/shm.c | 100 |
2 files changed, 122 insertions, 3 deletions
diff --git a/src/library/gc/object.c b/src/library/gc/object.c index 59b986b..87dafd8 100644 --- a/src/library/gc/object.c +++ b/src/library/gc/object.c @@ -1,12 +1,14 @@ #include <gc/server.h> #include <gm/method.h> #include <gc/mem.h> +#include <gc/shm.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); +static struct method_ret checkIfHandlesMany(struct method_data *d); void objsrv_init() { procServer.id = 0; @@ -15,6 +17,7 @@ void objsrv_init() { procServer.data = 0; servers = &procServer; srv_addHandler(&procServer, M_HANDLECHECK_BIVV, checkIfHandles); + srv_addHandler(&procServer, M_HANDLECHECK_BMIV, checkIfHandlesMany); } void srv_handleAll() { @@ -55,8 +58,12 @@ void srv_handle(Server *o, int act) { 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 + void* p = shm_alloc(rq.shmsize[i]); + md.parameters[i].val.p = p; + if (p != 0) { + request_mapShm(o->id, (size_t)p, i); + 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]; } @@ -73,7 +80,7 @@ void srv_handle(Server *o, int act) { } else { for (i = 0; i < 3; i++) { if (md.parameters[i].type == PT_SHM && md.parameters[i].keepShm == 0) { - //TODO : unmap shm + shm_freeDel(md.parameters[i].val.p); } } } @@ -97,6 +104,7 @@ Server *srv_create() { s->data = 0; s->next = servers; srv_addHandler(s, M_HANDLECHECK_BIVV, checkIfHandles); + srv_addHandler(s, M_HANDLECHECK_BMIV, checkIfHandlesMany); servers = s; return s; } @@ -145,6 +153,17 @@ struct method_ret checkIfHandles(struct method_data *d) { return mr_long(1); } +struct method_ret checkIfHandlesMany(struct method_data *d) { + if (d->parameters[0].type != PT_SHM) return mr_err(-1); + if (d->parameters[1].type != PT_LONG) return mr_err(-1); + uint32_t *data = d->parameters[0].val.p, i; + if (data == 0) return mr_long(0); + for (i = 0; i < d->parameters[1].val.i; i++) { + if (getHandler(d->obj, data[i]) == 0) return mr_long(0); + } + return mr_long(1); +} + // ***************************** HELPER FUNCTIONS FOR RETRUN VALUES struct method_ret mr_long(int val) { diff --git a/src/library/gc/shm.c b/src/library/gc/shm.c new file mode 100644 index 0000000..9e19533 --- /dev/null +++ b/src/library/gc/shm.c @@ -0,0 +1,100 @@ +#include <gc/shm.h> +#include <gc/mem.h> +#include <mutex.h> + +struct shm_block { + size_t start, size; + int is_hole; //1 : hole, 0 : used block + struct shm_block *prev, *next; +}; + +struct shm_block *blocks = 0; + +static uint32_t tMutex = MUTEX_UNLOCKED; + +static void shm_init() { + struct shm_block *b = malloc(sizeof(struct shm_block)); + b->start = 0x80000000; + b->size = 0xD0000000 - 0x80000000; + b->is_hole = 1; + b->prev = b->next = 0; + blocks = b; +} + +void* shm_alloc(size_t size) { + mutex_lock(&tMutex); + if (blocks == 0) shm_init(); + if (size & 0xFFF) size = (size & 0xFFFFF000) + 0x1000; + //go through all blocks, get the one with the closest size + struct shm_block *block = blocks; + while (block) { + if (block->size >= size) break; + block = block->next; + } + if (block == 0) { + mutex_unlock(&tMutex); + return 0; + } + //if the block's size is bigger, reduce it and create a new one after + if (block->size > size) { + struct shm_block *newb = malloc(sizeof(struct shm_block)); + newb->start = block->start + size; + newb->size = block->size - size; + newb->is_hole = 1; + newb->prev = block; newb->next = block->next; + block->size = size; + if (block->next != 0) block->next->prev = newb; + block->next = newb; + } + //mark block as used + block->is_hole = 0; + //return block's address + mutex_unlock(&tMutex); + return (void*)block->start; +} + +static void unify (struct shm_block *b) { + if (b->next == 0 || b->is_hole == 0 || b->next->is_hole == 0) return; + struct shm_block *n = b->next; + b->size += n->size; + n->next->prev = b; + b->next = n->next; + free(n); +} + +void shm_free(void* p) { + mutex_lock(&tMutex); + //find block + struct shm_block *bl = blocks; + while (bl) { + if (bl->start == (size_t)p) break; + bl = bl->next; + } + if (bl == 0) { + mutex_unlock(&tMutex); + return; + } + //mark it as a hole + bl->is_hole = 1; + //unify after if possible + if (bl->next != 0 && bl->next->is_hole == 1) unify(bl); + //unify before if possible + if (bl->prev != 0 && bl->prev->is_hole == 1) unify(bl->prev); + mutex_unlock(&tMutex); +} + +void* shm_allocNew(size_t size) { + if (size & 0xFFF) size = (size & 0xFFFFF000) + 0x1000; + + void* p = shm_alloc(size); + if (shm_create((size_t)p, size) != 0) { + shm_free(p); + return 0; + } + return p; +} + +void shm_freeDel(void *p) { + shm_delete((size_t)p); + shm_free(p); +} |