mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 23:18:21 +00:00
scheduler: fix concurrency issues
This commit is contained in:
@@ -208,6 +208,8 @@ static __attribute__((noreturn)) void switchthread(thread_t *thread) {
|
|||||||
|
|
||||||
_cpu()->intstatus = ARCH_CONTEXT_INTSTATUS(&thread->context);
|
_cpu()->intstatus = ARCH_CONTEXT_INTSTATUS(&thread->context);
|
||||||
thread->cpu = _cpu();
|
thread->cpu = _cpu();
|
||||||
|
// XXX make the locking of the flags field better, candidate for a r/w lock
|
||||||
|
spinlock_acquire(&runqueuelock);
|
||||||
if (current)
|
if (current)
|
||||||
current->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
|
current->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
|
||||||
|
|
||||||
@@ -217,12 +219,15 @@ static __attribute__((noreturn)) void switchthread(thread_t *thread) {
|
|||||||
spinlock_release(¤t->sleeplock);
|
spinlock_release(¤t->sleeplock);
|
||||||
|
|
||||||
thread->flags |= SCHED_THREAD_FLAGS_RUNNING;
|
thread->flags |= SCHED_THREAD_FLAGS_RUNNING;
|
||||||
|
__assert((thread->flags & SCHED_THREAD_FLAGS_QUEUED) == 0);
|
||||||
|
spinlock_release(&runqueuelock);
|
||||||
|
|
||||||
ARCH_CONTEXT_SWITCHTHREAD(thread);
|
ARCH_CONTEXT_SWITCHTHREAD(thread);
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runqueueinsert(thread_t *thread) {
|
static void runqueueinsert(thread_t *thread) {
|
||||||
|
__assert((thread->flags & SCHED_THREAD_FLAGS_RUNNING) == 0);
|
||||||
thread->flags |= SCHED_THREAD_FLAGS_QUEUED;
|
thread->flags |= SCHED_THREAD_FLAGS_QUEUED;
|
||||||
|
|
||||||
runqueuebitmap |= ((uint64_t)1 << thread->priority);
|
runqueuebitmap |= ((uint64_t)1 << thread->priority);
|
||||||
@@ -253,10 +258,10 @@ void sched_queue(thread_t *thread) {
|
|||||||
|
|
||||||
__attribute__((noreturn)) void sched_stopcurrentthread() {
|
__attribute__((noreturn)) void sched_stopcurrentthread() {
|
||||||
interrupt_set(false);
|
interrupt_set(false);
|
||||||
if (_cpu()->thread)
|
|
||||||
_cpu()->thread->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
|
|
||||||
|
|
||||||
spinlock_acquire(&runqueuelock);
|
spinlock_acquire(&runqueuelock);
|
||||||
|
if (_cpu()->thread)
|
||||||
|
_cpu()->thread->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
|
||||||
|
|
||||||
thread_t *next = runqueuenext(0x0fffffff);
|
thread_t *next = runqueuenext(0x0fffffff);
|
||||||
if (next == NULL)
|
if (next == NULL)
|
||||||
@@ -337,7 +342,10 @@ static void threadexit_internal(context_t *) {
|
|||||||
// as well as not being preempted at all
|
// as well as not being preempted at all
|
||||||
_cpu()->thread = NULL;
|
_cpu()->thread = NULL;
|
||||||
|
|
||||||
|
interrupt_set(false);
|
||||||
|
spinlock_acquire(&runqueuelock);
|
||||||
thread->flags |= SCHED_THREAD_FLAGS_DEAD;
|
thread->flags |= SCHED_THREAD_FLAGS_DEAD;
|
||||||
|
spinlock_release(&runqueuelock);
|
||||||
|
|
||||||
// because a thread deallocating its own data is a nightmare, thread deallocation and such will be left to whoever frees the proc it's tied to
|
// because a thread deallocating its own data is a nightmare, thread deallocation and such will be left to whoever frees the proc it's tied to
|
||||||
// (likely an exit(2) call)
|
// (likely an exit(2) call)
|
||||||
@@ -428,7 +436,6 @@ static void yield(context_t *context) {
|
|||||||
bool sleeping = thread->flags & SCHED_THREAD_FLAGS_SLEEP;
|
bool sleeping = thread->flags & SCHED_THREAD_FLAGS_SLEEP;
|
||||||
|
|
||||||
thread_t *next = runqueuenext(sleeping ? 0x0fffffff : thread->priority);
|
thread_t *next = runqueuenext(sleeping ? 0x0fffffff : thread->priority);
|
||||||
|
|
||||||
bool gotsignal = false;
|
bool gotsignal = false;
|
||||||
for (int i = 0; i < NSIG && thread->proc; ++i) {
|
for (int i = 0; i < NSIG && thread->proc; ++i) {
|
||||||
void *action = thread->proc->signals.actions[i].address;
|
void *action = thread->proc->signals.actions[i].address;
|
||||||
@@ -456,6 +463,7 @@ static void yield(context_t *context) {
|
|||||||
if (next || sleeping) {
|
if (next || sleeping) {
|
||||||
ARCH_CONTEXT_THREADSAVE(thread, context);
|
ARCH_CONTEXT_THREADSAVE(thread, context);
|
||||||
|
|
||||||
|
thread->flags &= ~SCHED_THREAD_FLAGS_RUNNING;
|
||||||
if (sleeping == false)
|
if (sleeping == false)
|
||||||
runqueueinsert(thread);
|
runqueueinsert(thread);
|
||||||
|
|
||||||
@@ -480,6 +488,7 @@ int sched_yield() {
|
|||||||
void sched_preparesleep(bool interruptible) {
|
void sched_preparesleep(bool interruptible) {
|
||||||
_cpu()->thread->sleepintstatus = interrupt_set(false);
|
_cpu()->thread->sleepintstatus = interrupt_set(false);
|
||||||
spinlock_acquire(&_cpu()->thread->sleeplock);
|
spinlock_acquire(&_cpu()->thread->sleeplock);
|
||||||
|
// no locking needed as only we will be accessing it
|
||||||
_cpu()->thread->flags |= SCHED_THREAD_FLAGS_SLEEP | (interruptible ? SCHED_THREAD_FLAGS_INTERRUPTIBLE : 0);
|
_cpu()->thread->flags |= SCHED_THREAD_FLAGS_SLEEP | (interruptible ? SCHED_THREAD_FLAGS_INTERRUPTIBLE : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,8 +505,8 @@ bool sched_wakeup(thread_t *thread, int reason) {
|
|||||||
thread->flags &= ~(SCHED_THREAD_FLAGS_SLEEP | SCHED_THREAD_FLAGS_INTERRUPTIBLE);
|
thread->flags &= ~(SCHED_THREAD_FLAGS_SLEEP | SCHED_THREAD_FLAGS_INTERRUPTIBLE);
|
||||||
thread->wakeupreason = reason;
|
thread->wakeupreason = reason;
|
||||||
|
|
||||||
spinlock_release(&thread->sleeplock);
|
|
||||||
sched_queue(thread);
|
sched_queue(thread);
|
||||||
|
spinlock_release(&thread->sleeplock);
|
||||||
interrupt_set(intstate);
|
interrupt_set(intstate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user