mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58:22 +00:00
semaphore: fix a race condition
This commit is contained in:
@@ -27,9 +27,37 @@ static thread_t *get(semaphore_t *sem) {
|
|||||||
else
|
else
|
||||||
sem->tail->sleepnext = NULL;
|
sem->tail->sleepnext = NULL;
|
||||||
|
|
||||||
|
thread->sleepprev = NULL;
|
||||||
|
thread->sleepnext = NULL;
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void removeself(semaphore_t *sem) {
|
||||||
|
thread_t *thread = _cpu()->thread;
|
||||||
|
|
||||||
|
// first see if we have been removed already
|
||||||
|
if ((sem->head == NULL && sem->tail == NULL) || // no threads in sleep list
|
||||||
|
!((thread->sleepnext != NULL || thread->sleepprev != NULL) || // 2 or more threads in sleep list and we are one of them
|
||||||
|
(sem->head == thread && sem->tail == thread))) // 1 thread in the sleep list and it is us
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sem->head == thread) {
|
||||||
|
sem->head = thread->sleepnext;
|
||||||
|
} else {
|
||||||
|
thread->sleepprev->sleepnext = thread->sleepnext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sem->tail == thread) {
|
||||||
|
sem->tail = thread->sleepprev;
|
||||||
|
} else {
|
||||||
|
thread->sleepnext->sleepprev = thread->sleepprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->sleepprev = NULL;
|
||||||
|
thread->sleepnext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int semaphore_wait(semaphore_t *sem, bool interruptible) {
|
int semaphore_wait(semaphore_t *sem, bool interruptible) {
|
||||||
if (_cpu()->thread == NULL) {
|
if (_cpu()->thread == NULL) {
|
||||||
while (semaphore_test(sem) == false) CPU_PAUSE();
|
while (semaphore_test(sem) == false) CPU_PAUSE();
|
||||||
@@ -48,6 +76,7 @@ int semaphore_wait(semaphore_t *sem, bool interruptible) {
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
spinlock_acquire(&sem->lock);
|
spinlock_acquire(&sem->lock);
|
||||||
++sem->i;
|
++sem->i;
|
||||||
|
removeself(sem);
|
||||||
spinlock_release(&sem->lock);
|
spinlock_release(&sem->lock);
|
||||||
}
|
}
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|||||||
Reference in New Issue
Block a user