commit b1ba512aa22afc8e52a4eb0593b5c8da4d5db276
parent 07d157d0fe7503f7dc64e02673fa10f330e5df23
Author: Roberto E. Vargas Caballero <roberto.vargas@midokura.com>
Date: Wed, 16 Nov 2022 15:47:01 +0100
os9: Fix concurrency problems in sched()
Sched() is a complex function because it has to lock two
processes and the full tasktab data structure. Having 3
locks hold at the same time is dangerous and can drive
to deadlocks easily.
Diffstat:
4 files changed, 38 insertions(+), 16 deletions(-)
diff --git a/include/os9/os9.h b/include/os9/os9.h
@@ -291,6 +291,7 @@ extern noreturn void trap(Context *ctx);
extern Ptable *initptable(Task *);
extern int ictx(Task *, void *);
extern char *getconf(char *);
+extern void idle(void);
/* dev functions */
extern void idev(void);
diff --git a/src/os9/hosted/arch.c b/src/os9/hosted/arch.c
@@ -17,10 +17,17 @@ halt(void)
abort();
}
+/*
+ * we don't implement context switch in hosted mode
+ * so, this function is going to be called only once
+ * with the entry point of the initial task
+ */
void
swtch(Context *ctx)
{
- longjmp(recover, 1);
+ void (*fn)(void) = (void (*)(void)) ctx->entry;
+
+ (*fn)();
}
uint8_t
@@ -59,6 +66,11 @@ outm32(uint32_t val, void *addr)
return 0;
}
+void
+idle(void)
+{
+}
+
int
ictx(Task *tp, void *fn)
{
diff --git a/src/os9/proc.c b/src/os9/proc.c
@@ -43,7 +43,8 @@ iproc(void)
if ((tp = kproc(initfn)) == NULL)
panic("init task failed");
- unlock(&tp->m);
+ tp->affinity = -1;
+ proc = tp;
}
void
@@ -456,7 +457,7 @@ kproc(void *fn)
tp->flags = 0;
- tp->state = TRUNNING;
+ tp->state = TREADY;
tp->start = SKERNEL;
if ((tp->kstack = allocb(1)) == NULL)
@@ -472,6 +473,9 @@ err:
return NULL;
}
+/*
+ * sched must be called without having any task locked
+ */
void
sched(void)
{
@@ -479,11 +483,15 @@ sched(void)
int prio;
long long wait, mask;
- lock(&procm);
- new = proc;
- if (proc->state == TRUNNING && proc->flags&TLOCK_PREEMP)
- goto found;
+ if (proc->state == TRUNNING && proc->flags&TLOCK_PREEMP) {
+ unlock(&proc->m);
+ swtch(&proc->ctx);
+ }
+ unlock(&proc->m);
+repeat:
+ lock(&procm);
+ new = NULL;
prio = -1;
wait = -1;
mask = 1ul << cpuid;
@@ -492,20 +500,21 @@ sched(void)
if (tp->state == TREADY
&& (tp->affinity & mask) != 0
&& tp->prio >= prio
- && (tp->prio != prio || new->wait > wait)) {
- new = tp;
+ && (tp->prio != prio || tp->wait > wait)) {
+ new = proc = tp;
prio = tp->prio;
wait = tp->wait;
}
+ unlock(&tp->m);
+ }
+
+ if (!new) {
+ unlock(&procm);
+ idle();
+ goto repeat;
}
-found:
- if (proc->state == TRUNNING)
- proc->state = TREADY;
- proc->wait = now;
- proc = new;
proc->state = TRUNNING;
unlock(&procm);
-
swtch(&proc->ctx);
}
diff --git a/src/os9/sys.c b/src/os9/sys.c
@@ -109,5 +109,5 @@ isys(void)
iconf();
icons();
iproc();
- debug();
+ sched();
}