summaryrefslogtreecommitdiff
path: root/src/library/gc
diff options
context:
space:
mode:
authorAlexis211 <alexis211@gmail.com>2010-03-31 17:26:21 +0200
committerAlexis211 <alexis211@gmail.com>2010-03-31 17:26:21 +0200
commitb945eafa126d6a17aa8826a405df7d5d4d999008 (patch)
tree34b5ba6f0c13b1b35770375f51183a047271a4d4 /src/library/gc
parentad1ec29070e1ffba7461687cd268e64be06aa78b (diff)
downloadTCE-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.c25
-rw-r--r--src/library/gc/shm.c100
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);
+}