From b945eafa126d6a17aa8826a405df7d5d4d999008 Mon Sep 17 00:00:00 2001 From: Alexis211 Date: Wed, 31 Mar 2010 17:26:21 +0200 Subject: Shared memory segment manager in userland --- src/library/Makefile | 6 +-- src/library/gc/object.c | 25 ++++++++++-- src/library/gc/shm.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ src/library/mutex.c | 22 +++++++++++ 4 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 src/library/gc/shm.c create mode 100644 src/library/mutex.c (limited to 'src/library') diff --git a/src/library/Makefile b/src/library/Makefile index be5a76d..b0dac11 100644 --- a/src/library/Makefile +++ b/src/library/Makefile @@ -7,9 +7,9 @@ LD = ld LDFLAGS = -r Library = grapes.o -Objects = gc/syscall.o \ - gc/mem.o \ - gc/object.o \ +Objects = gc/syscall.o gc/object.o \ + gc/mem.o gc/shm.o \ + mutex.o \ start.o all: $(Library) 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 #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); +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 +#include +#include + +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); +} diff --git a/src/library/mutex.c b/src/library/mutex.c new file mode 100644 index 0000000..ac0ee8f --- /dev/null +++ b/src/library/mutex.c @@ -0,0 +1,22 @@ +#include + +static uint32_t atomic_exchange(uint32_t* ptr, uint32_t newval) { + uint32_t r; + asm volatile("xchg (%%ecx), %%eax" : "=a"(r) : "c"(ptr), "a"(newval)); + return r; +} + +void mutex_lock(uint32_t* mutex) { + while (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) { + thread_sleep(1); + } +} + +int mutex_lockE(uint32_t* mutex) { + if (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) return 0; + return 1; +} + +void mutex_unlock(uint32_t* mutex) { + *mutex = MUTEX_UNLOCKED; +} -- cgit v1.2.3