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 --- doc/roadmap.txt | 5 +-- src/include/gc/shm.h | 16 ++++++++ src/include/gc/syscall.h | 2 +- src/include/mutex.h | 15 +++++++ src/kernel/ipc/request.c | 6 ++- src/kernel/ipc/request.h | 2 +- src/library/Makefile | 6 +-- src/library/gc/object.c | 25 ++++++++++-- src/library/gc/shm.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/library/mutex.c | 22 +++++++++++ 10 files changed, 187 insertions(+), 12 deletions(-) create mode 100644 src/include/gc/shm.h create mode 100644 src/include/mutex.h create mode 100644 src/library/gc/shm.c create mode 100644 src/library/mutex.c diff --git a/doc/roadmap.txt b/doc/roadmap.txt index 7304e4b..de4b3cb 100644 --- a/doc/roadmap.txt +++ b/doc/roadmap.txt @@ -1,8 +1,7 @@ ** 0.0.4 'Cat in my heart' ** - [OK] Userland heap (meaning kernel can give memory to processes) -- Userland helper functions for objects (server and client) -- Basic object method for knowing if object handles another method (list methods in src/include/gm) -- Userland library for writing numbers and other stuff +- Userland helper functions for objects (server and client, shared memory segment manager) +- [OK] Basic object method for knowing if object handles another method (list methods in src/include/gm) - A manager module that manages all other running modules (the privilege of manager is given by the kernel to the first module loaded) ** 0.0.5 'Truth is better cold' ** diff --git a/src/include/gc/shm.h b/src/include/gc/shm.h new file mode 100644 index 0000000..1a3f0a1 --- /dev/null +++ b/src/include/gc/shm.h @@ -0,0 +1,16 @@ +#ifndef DEF_SHM_H +#define DEF_SHM_H + +#include + +/* + * This file contains headers for the shared segment mapping manager. + */ + +void* shm_alloc(size_t size); //allocates a spot in shared memory space +void shm_free(void* p); //frees a spot + +void* shm_allocNew(size_t size); //calls shm_alloc, and maps a new segment there +void shm_freeDel(void* p); //unmaps segment and calls shm_free + +#endif diff --git a/src/include/gc/syscall.h b/src/include/gc/syscall.h index f731e10..c93a523 100644 --- a/src/include/gc/syscall.h +++ b/src/include/gc/syscall.h @@ -13,7 +13,7 @@ typedef char int8_t; typedef unsigned size_t; struct user_request { - uint32_t func, params[3]; + uint32_t func, params[3], shmsize[3]; int isBlocking; // 1 : blocking request, 0 : nonblocking request (message) }; diff --git a/src/include/mutex.h b/src/include/mutex.h new file mode 100644 index 0000000..50b5606 --- /dev/null +++ b/src/include/mutex.h @@ -0,0 +1,15 @@ +#ifndef DEF_MUTEX_H +#define DEF_MUTEX_H + +#include + +#define MUTEX_LOCKED 1 +#define MUTEX_UNLOCKED 0 + +//A mutex is just an uint32_t + +void mutex_lock(uint32_t* mutex); //wait for mutex to be free +int mutex_lockE(uint32_t* mutex); //lock mutex only if free, returns !0 if locked, 0 if was busy +void mutex_unlock(uint32_t* mutex); + +#endif diff --git a/src/kernel/ipc/request.c b/src/kernel/ipc/request.c index e59a66c..4e8b407 100644 --- a/src/kernel/ipc/request.c +++ b/src/kernel/ipc/request.c @@ -20,7 +20,11 @@ int request_get(int id, uint32_t ptr, int wait) { //when request pending (wait finished), write it to ptr struct user_request *p = (struct user_request*)ptr; p->func = obj->request->func; - for (i = 0; i < 3; i++) p->params[i] = obj->request->params[i]; + for (i = 0; i < 3; i++) { + p->params[i] = obj->request->params[i]; + if (obj->request->shm_sndr[i] != 0) p->shmsize[i] = obj->request->shm_sndr[i]->len; + else p->shmsize[i] = 0; + } p->isBlocking = (obj->request->requester != 0); //if request is nonblocking and no shm is to be mapped, delete request and unlock objects busymutex, else set it to acknowledged if (p->isBlocking) return 0; diff --git a/src/kernel/ipc/request.h b/src/kernel/ipc/request.h index 0afc48b..b08264f 100644 --- a/src/kernel/ipc/request.h +++ b/src/kernel/ipc/request.h @@ -28,7 +28,7 @@ struct request { }; struct user_request { - uint32_t func, params[3]; + uint32_t func, params[3], shmsize[3]; int isBlocking; // 1 : blocking request, 0 : nonblocking request (message) }; 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