diff options
Diffstat (limited to 'src/kernel/ipc/request.c')
-rw-r--r-- | src/kernel/ipc/request.c | 201 |
1 files changed, 177 insertions, 24 deletions
diff --git a/src/kernel/ipc/request.c b/src/kernel/ipc/request.c index 51a0bbc..25c778a 100644 --- a/src/kernel/ipc/request.c +++ b/src/kernel/ipc/request.c @@ -1,55 +1,208 @@ #include "request.h" +#include "shm.h" +#include "object.h" +#include <lib/mutex.h> +#include <mem/seg.h> +#include <mem/mem.h> -int request_get(int obj, uint32_t ptr, int wait) { - //check if we own the object, if not return -2 - //check if a request is pending. if request is being processed, return -3 - //if not (busymutex unlocked or request==0) && wait, then wait, else return -1 - //if request pending, write it to ptr - // if request is nonblocking and no shm is to be mapped, delete it and unlock objects busymutex - //return 0 +int request_get(int id, uint32_t ptr, int wait) { + int i; + //check if we own the object, if not return -2 (-10 if descriptor does not exist) + struct object *obj = objdesc_read(current_thread->process, id); + if (obj == 0) return -10; + if (obj->owner != current_thread->process) return -2; + //check if a request is pending. if request is being processed (acknowledged), return -3 + if (obj->request != 0 && obj->request->acknowledged != RS_PENDING) return -3; + //if not (busymutex unlocked and request==0) && wait, then wait, else return -1 + if (wait == 0) return -1; + while (obj->busyMutex != MUTEX_LOCKED && (obj->request == 0 || obj->request->acknowledged != RS_PENDING)) thread_sleep(1); + obj->request->acknowledged = RS_PROCESSED; + //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]; + 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; + for (i = 0; i < 3; i++) { + if (obj->request->shm_sndr[i] != 0) return 0; + } + kfree(obj->request); + obj->request = 0; + mutex_unlock(&obj->busyMutex); + return 0; } -int request_has(int obj) { - //check if we own the object, if not return -2 +int request_has(int id) { + //check if we own the object, if not return -2 (-10 if descriptor does not exist) + struct object *obj = objdesc_read(current_thread->process, id); + if (obj == 0) return -10; + if (obj->owner != current_thread->process) return -2; //check if a request is pending. - // if being processed, return 2 - // if waiting for ack, return 1 // if none (busymutex unlocked or request==0), return 0 + if (obj->request == 0 || obj->busyMutex == MUTEX_UNLOCKED) return 0; + // if waiting for ack (not acknowledged), return 1 + if (obj->request->acknowledged == RS_PENDING) return 1; + // if being processed (acknowledged), return 2 + return 2; } -void request_answer(int obj, uint32_t answer) { - //check if we own the object, if not return +void request_answer(int id, uint32_t answer, uint32_t answer2) { + int i; + //check if we own the object, if not return (also return if descriptor does not exist) + struct object *obj = objdesc_read(current_thread->process, id); + if (obj == 0) return; + if (obj->owner != current_thread->process) return; //if no blocking request is being processed (including non-acknowledged waiting requests), return - //set blocking request to finished, and set its answer + if (obj->request == 0 || obj->request->acknowledged == RS_PENDING || obj->request->requester == 0) return; + //unmap shared memory segments from shm_rcv, close descriptors to objects from obj_close + for (i = 0; i < 3; i++) { + if (obj->request->shm_rcv[i] != 0) seg_unmap(obj->request->shm_rcv[i]); + if (obj->request->obj_close[i] != 0) obj_closeP(obj->owner, obj->request->obj_close[i]); + } + //set blocking request to finished (acknowledged = 2), and set its answer + obj->request->acknowledged = RS_FINISHED; + switch (obj->request->func >> 30) { + case PT_OBJDESC: + if (obj->owner == obj->request->requester->process) { + obj->request->answer.n = answer; + } else { + int n = objdesc_get(obj->request->requester->process, objdesc_read(obj->owner, answer)); + if (n == -1) { + n = objdesc_add(obj->request->requester->process, objdesc_read(obj->owner, answer)); + } + obj->request->answer.n = n; + } + break; + case PT_LONG: + obj->request->answer.n = answer; + break; + case PT_LONGLONG: + obj->request->answer.ll = (uint64_t)((uint64_t)answer << 32) | answer2; + } + //wake up receiver thread (thread_wakeUp) + thread_wakeUp(obj->request->requester); //dereference request from object, unlock objects busymutex + obj->request = 0; + mutex_unlock(&obj->busyMutex); } -int request_mapShm(int obj, uint32_t pos, int number) { - //check if we own the object, if not return -2 +int request_mapShm(int id, uint32_t pos, int number) { + int i; + if (number > 2 || number < 0) return -9; + //check if we own the object, if not return -2 (-10 if descriptor does not exist) + struct object *obj = objdesc_read(current_thread->process, id); + if (obj == 0) return -10; + if (obj->owner != current_thread->process) return -2; //if no request is being processes (including non-acknowledged waiting requests), return -3 - //check if the requests has shm in parameter [number], if not return -4 + if (obj->request == 0 || obj->request->acknowledged == RS_PENDING || obj->request->requester == 0) return -3; + //check if the requests should have shm in parameter [number], if not return -4 + int n = (obj->request->func >> (28 - (2 * number))) & 3; + if (n != PT_SHM) return -4; + //check if sender process is different from receiver process, if not return -7 + if (obj->owner == obj->request->requester->process) return -7; + //check if sender sent a shm seg in parameter [number], if not return -5 + if (obj->request->shm_sndr[number] == 0) return -5; //map shm to position + obj->request->shm_rcv[number] = seg_map(obj->request->shm_sndr[number]->seg, obj->owner->pagedir, pos); //if request is nonblocking and no more shm is to be mapped, delete request and free object busymutex - //return 0 + if (obj->request->requester != 0) return 0; + for (i = 0; i < 3; i++) { + if (obj->request->shm_sndr[i] != 0 && obj->request->shm_rcv[i] == 0) return 0; + } + kfree(obj->request); + obj->request = 0; + mutex_unlock(&obj->busyMutex); + return 0; } -static struct request *mkrequest(int obj, struct thread *requester, +static struct request *mkrequest(int id, struct thread *requester, uint32_t func, uint32_t a, uint32_t b, uint32_t c) { + int i; // get object from descriptor id, if none return 0 + struct object *obj = objdesc_read(current_thread->process, id); + if (obj == 0) return 0; // waitlock object's busy mutex + mutex_lock(&obj->busyMutex); // if object cannot answer (owner == 0) return 0 - // create request, fill it up, reference it from object + if (obj->owner == 0) { + mutex_unlock(&obj->busyMutex); + return 0; + } + // create request, fill it up : + struct request *rq = kmalloc(sizeof(struct request)); + rq->obj = obj; + rq->requester = requester; + rq->func = func; + for (i = 0; i < 3; i++) { rq->params[i] = 0; rq->obj_close[i] = 0; rq->shm_sndr[i] = 0; rq->shm_rcv[i] = 0; } + rq->acknowledged = RS_PENDING; + // integers: use as is + // objects: open a new descriptor in receiver process (if same process, keep number), put that number as an int + // if receiver already had descriptor to this object, use it and set obj_close to 0, else set obj_close to new number + // shm: if same process, put ptr as int, else put 0 as int and get segment_map to shm_sndr + // objects and shm: 0 means sender didn't want to share anything, that should stay 0. + for (i = 0; i < 3; i++) { + int n = (rq->func >> (28 - (2 * i))) & 3; + uint32_t v = (i == 0 ? a : (i == 1 ? b : c)); + switch (n) { + case PT_OBJDESC: + if (obj->owner == current_thread->process) { + rq->params[i] = v; + } else { + int d = objdesc_get(obj->owner, objdesc_read(current_thread->process, v)); + if (d == -1) { + d = objdesc_add(obj->owner, objdesc_read(current_thread->process, v)); + rq->obj_close[i] = d; + } + rq->params[i] = d; + } + break; + case PT_LONG: + rq->params[i] = v; + break; + case PT_SHM: + if (obj->owner == current_thread->process) { + rq->params[i] = v; + } else { + rq->shm_sndr[i] = shmseg_getByOff(current_thread->process, v); + } + break; + } + } + // reference request from object + obj->request = rq; // return request + return rq; } -int request(int obj, uint32_t func, uint32_t a, uint32_t b, uint32_t c, uint32_t answerptr) { +int request(int obj, uint32_t rq_ptr) { + struct user_sendrequest *urq = (void*)rq_ptr; //call mkrequest with parameters (requester thread = current thread) - //if returned value is 0, return -1 + struct request *rq = mkrequest(obj, current_thread, urq->func, urq->a, urq->b, urq->c); + //if returned value is 0 (could not create request), return -1 + if (rq == 0) return -1; //sleep until request is handled - //write answer to *answerptr, delete request, return 0 + thread_goInactive(); + //if request has been interrupted because process closed communication (acknowledged == 3), return -2 + if (rq->acknowledged == 3) return -2; + //write answer to urq, delete request, return 0 + switch (urq->func >> 30) { + case PT_OBJDESC: + case PT_LONG: + urq->answeri = rq->answer.n; + break; + case PT_LONGLONG: + urq->answerll = rq->answer.ll; + } + kfree(rq); + return 0; } -int send_msg(int obj, uint32_t func, uint32_t a, uint32_t b, uint32_t c) { +int send_msg(int obj, uint32_t rq_ptr) { + struct user_sendrequest *urq = (void*)rq_ptr; //call mkrequest with parameters (requester thread = 0) + struct request *rq = mkrequest(obj, 0, urq->func, urq->a, urq->b, urq->c); //if returned value is 0, return -1 else return 0 + if (rq == 0) return -1; + return 0; } |