semaphore: signal safety

This commit is contained in:
Matheus
2024-05-08 20:13:12 -03:00
parent 0910232b56
commit bf841406d5
3 changed files with 23 additions and 7 deletions
+1 -1
View File
@@ -121,7 +121,7 @@ void sched_queue(thread_t *thread);
void sched_stopcurrentthread();
int sched_yield();
void sched_preparesleep(bool interruptible);
void sched_wakeup(thread_t *thread, int reason);
bool sched_wakeup(thread_t *thread, int reason);
int sched_sleep();
proc_t *sched_newproc();
vnode_t *sched_getcwd();
+18 -4
View File
@@ -17,7 +17,8 @@ static void insert(semaphore_t *sem, thread_t *thread) {
static thread_t *get(semaphore_t *sem) {
thread_t *thread = sem->tail;
__assert(thread);
if (thread == NULL)
return NULL;
sem->tail = thread->sleepprev;
@@ -44,6 +45,11 @@ int semaphore_wait(semaphore_t *sem, bool interruptible) {
sched_preparesleep(interruptible);
spinlock_release(&sem->lock);
ret = sched_yield();
if (ret) {
spinlock_acquire(&sem->lock);
++sem->i;
spinlock_release(&sem->lock);
}
goto leave;
}
@@ -57,9 +63,17 @@ void semaphore_signal(semaphore_t *sem) {
bool intstate = interrupt_set(false);
spinlock_acquire(&sem->lock);
if (++sem->i <= 0) {
thread_t *thread = get(sem);
// XXX the current method doesn't respect thread priorities
sched_wakeup(thread, 0);
thread_t *thread;
do {
// wake SOMEONE up. this will *try* to wake up a thread
// it could wake up none though, as a thread could have been interrupted by a signal
thread = get(sem);
// XXX the current method doesn't respect thread priorities
if (thread) {
sched_wakeup(thread, 0);
break;
}
} while (thread);
}
spinlock_release(&sem->lock);
interrupt_set(intstate);
+4 -2
View File
@@ -417,14 +417,14 @@ void sched_preparesleep(bool interruptible) {
_cpu()->thread->flags |= SCHED_THREAD_FLAGS_SLEEP | (interruptible ? SCHED_THREAD_FLAGS_INTERRUPTIBLE : 0);
}
void sched_wakeup(thread_t *thread, int reason) {
bool sched_wakeup(thread_t *thread, int reason) {
bool intstate = interrupt_set(false);
spinlock_acquire(&thread->sleeplock);
if ((thread->flags & SCHED_THREAD_FLAGS_SLEEP) == 0 || ((reason == SCHED_WAKEUP_REASON_INTERRUPTED) && (thread->flags & SCHED_THREAD_FLAGS_INTERRUPTIBLE) == 0)) {
spinlock_release(&thread->sleeplock);
interrupt_set(intstate);
return;
return false;
}
thread->flags &= ~(SCHED_THREAD_FLAGS_SLEEP | SCHED_THREAD_FLAGS_INTERRUPTIBLE);
@@ -433,6 +433,8 @@ void sched_wakeup(thread_t *thread, int reason) {
spinlock_release(&thread->sleeplock);
sched_queue(thread);
interrupt_set(intstate);
return true;
}
static vnode_t *getnodeslock(vnode_t **addr) {