From: Matthias Kruk Date: Mon, 25 Nov 2019 07:23:15 +0000 (+0900) Subject: Add a fixed-length wait queue to mutexes, to speed up locking and unlocking operation... X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=81d8e3894e7092996ffefd3f6e09db20e2ebcb36;p=corax Add a fixed-length wait queue to mutexes, to speed up locking and unlocking operations; make use of sched_task_suspend() and sched_task_resume() in mutex implementation --- diff --git a/config.h b/config.h index d5d63e1..8304688 100644 --- a/config.h +++ b/config.h @@ -30,6 +30,7 @@ #endif /* !__ASSEMBLY_SOURCE */ #define CONFIG_USER_STACK_SIZE 4096 #define CONFIG_PROC_MAXTASKS 8 +#define CONFIG_MUTEX_WAITQLEN 8 #define CONFIG_APIC 0 diff --git a/kernel/klibc/mutex.c b/kernel/klibc/mutex.c index fc70930..9422b89 100644 --- a/kernel/klibc/mutex.c +++ b/kernel/klibc/mutex.c @@ -6,16 +6,12 @@ #include #include #include - -struct _waitq { - struct _waitq *next; - task_t *wtask; -}; +#include struct _mutex { spinlock_t mx_lock; task_t *mx_owner; - struct _waitq *mx_waitq; + task_t *mx_waitq[CONFIG_MUTEX_WAITQLEN]; }; int mutex_lock(mutex_t *mutex) @@ -23,54 +19,44 @@ int mutex_lock(mutex_t *mutex) task_t *ctask; int ret_val; - ret_val = -EAGAIN; + ret_val = EAGAIN; ctask = task_get_current(); - while(ret_val == -EAGAIN) { - task_t *prev; - - prev = NULL; + while(ret_val == EAGAIN) { + int i; /* lock the mutex */ spinlock_lock(&(mutex->mx_lock)); if(!mutex->mx_owner) { - /* mutex is not currently held by anyone */ + /* mutex is not currently held by anyone - claim it */ mutex->mx_owner = ctask; - ret_val = 0; - - if(mutex->mx_waitq) { - struct _waitq *qitem; - /* our item is still in the list if we had been waiting before */ - qitem = mutex->mx_waitq; - mutex->mx_waitq = qitem->next; - kfree(qitem); + /* + * Move the waitq up by one item, removing the first one (which should + * have been the task that is currently executing this function) + */ + for(i = 0; i < (CONFIG_MUTEX_WAITQLEN - 1) && mutex->mx_waitq[i + 1]; i++) { + mutex->mx_waitq[i] = mutex->mx_waitq[i + 1]; } - } else { - struct _waitq *qitem; + mutex->mx_waitq[CONFIG_MUTEX_WAITQLEN - 1] = NULL; + ret_val = 0; + } else { /* add the caller to the wait queue */ - qitem = kmalloc(sizeof(*qitem)); - - if(qitem) { - struct _waitq **cwq; - - qitem->wtask = ctask; - qitem->next = NULL; - - /* - * Add the item to the end of the queue, and get a pointer - * to the task that is in the list in front of us - */ - for(cwq = &(mutex->mx_waitq); *cwq; cwq = &((*cwq)->next)) { - prev = (*cwq)->wtask; + for(i = 0; i < CONFIG_MUTEX_WAITQLEN; i++) { + if(!mutex->mx_waitq[i]) { + mutex->mx_waitq[i] = ctask; + break; } - *cwq = qitem; + } - ret_val = -EAGAIN; + if(i < CONFIG_MUTEX_WAITQLEN) { + /* successfully enqueued */ + ret_val = EAGAIN; } else { + /* the queue was full */ ret_val = -ENOMEM; } } @@ -78,10 +64,17 @@ int mutex_lock(mutex_t *mutex) /* unlock the mutex */ spinlock_unlock(&(mutex->mx_lock)); - if(ret_val == -EAGAIN) { - /* FIXME: Something like task_wait() would be better */ - /* wait for the task in front of us */ - process_wait(prev->t_pid); + /* + * At this point, ret_val will have one of the values { -ENOMEM, 0, EAGAIN }. + * In case of -ENOMEM and 0, the loop will end and the value is returned to + * the caller. In the case of EAGAIN, the task will be suspended since it was + * successfully added to the mutex's wait queue. EAGAIN is deliberately chosen + * not to be a negative value since it is not an error that is suppposed to be + * returned to the caller. + */ + if(ret_val == EAGAIN) { + /* suspend this task */ + sched_task_suspend(NULL); } } @@ -119,17 +112,20 @@ int mutex_unlock(mutex_t *mutex) spinlock_lock(&(mutex->mx_lock)); if(mutex->mx_owner == ctask) { + /* caller currently owns the mutex - unlock it */ mutex->mx_owner = NULL; - if(mutex->mx_waitq) { - /* notify first task on the list */ - process_signal(mutex->mx_waitq->wtask->t_pid); + /* if there is a task in the waitq, resume it */ + if(mutex->mx_waitq[0]) { + sched_task_resume(mutex->mx_waitq[0]); } ret_val = 0; } else if(!mutex->mx_owner) { + /* mutex is not locked */ ret_val = -EALREADY; } else { + /* mutex is locked, but not by the caller */ ret_val = -EPERM; }