[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 05/11] kernel2: pm_scheduler_kern_yield()
+ kernel2: Neue Funktion, um den aktuellen Thread aus dem Kernel
schlafen zu legen, mit optionalem neuen Thread und Status für den
alten Thread. Nutzt einen neuen privilegierten Syscall.
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/include/syscallno.h | 4 ++--
src/kernel2/include/syscall.h | 3 +++
src/kernel2/include/tasks.h | 3 +++
src/kernel2/src/syscall.c | 6 ++++++
src/kernel2/src/syscalls/pm.c | 24 ++++++++++++++++++++++++
src/kernel2/src/tasks/scheduler.c | 21 +++++++++++++++++++++
6 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/src/include/syscallno.h b/src/include/syscallno.h
index 917e58b..2a2f909 100644
--- a/src/include/syscallno.h
+++ b/src/include/syscallno.h
@@ -52,7 +52,7 @@
#define SYSCALL_PM_SET_UID 8
#define SYSCALL_PM_REQUEST_PORT 9
#define SYSCALL_PM_RELEASE_PORT 10
-#define SYSCALL_PM_SLEEP 6
+#define KERN_SYSCALL_PM_SLEEP 124
#define SYSCALL_VM86 81
#define SYSCALL_VM86_BIOS_INT 83
@@ -119,6 +119,6 @@
#define SYSCALL_LIO_SRV_NODE_REMOVE 118
//ACHTUNG: Muss eine Zahl groesser als die Groesste Syscall-Nummer sein
-#define SYSCALL_MAX 124
+#define SYSCALL_MAX 125
#endif
diff --git a/src/kernel2/include/syscall.h b/src/kernel2/include/syscall.h
index f4fcb57..51f0ff1 100644
--- a/src/kernel2/include/syscall.h
+++ b/src/kernel2/include/syscall.h
@@ -114,6 +114,9 @@ int syscall_pm_v_and_wait_for_rpc(void);
/// Die Kontrolle an einen anderen Task abgeben
void syscall_pm_sleep(void);
+/// Die Kontrolle an einen anderen Task abgeben
+void kern_syscall_pm_sleep(tid_t yield_to, int status);
+
/// Warten, bis ein RPC zu bearbeiten ist
void syscall_pm_wait_for_rpc(void);
diff --git a/src/kernel2/include/tasks.h b/src/kernel2/include/tasks.h
index 7bcebb3..55caae6 100644
--- a/src/kernel2/include/tasks.h
+++ b/src/kernel2/include/tasks.h
@@ -232,6 +232,9 @@ void pm_scheduler_push(pm_thread_t* thread);
/// Kontrolle vom aktuellen Kernelthread an einen anderen Thread abgeben
void pm_scheduler_yield(void);
+/// Kontrolle an einen bestimmten Thread abgeben, mit Folgezustand
+void pm_scheduler_kern_yield(tid_t tid, int status);
+
/// Versucht einen Taskwechsel zum übergebenen Thread
void pm_scheduler_try_switch(pm_thread_t* thread);
diff --git a/src/kernel2/src/syscall.c b/src/kernel2/src/syscall.c
index f663915..b6b06c5 100644
--- a/src/kernel2/src/syscall.c
+++ b/src/kernel2/src/syscall.c
@@ -123,6 +123,12 @@ void syscall_init()
syscall_register(SYSCALL_LIO_STAT, &syscall_lio_stat, 2);
syscall_register(SYSCALL_LIO_UNLINK, &syscall_lio_unlink, 3);
syscall_register(SYSCALL_LIO_SYNC_ALL, &syscall_lio_sync_all, 0);
+
+ syscalls[KERN_SYSCALL_PM_SLEEP] = (syscall_t) {
+ .handler = &kern_syscall_pm_sleep,
+ .arg_count = 2,
+ .privileged = true,
+ };
}
/**
diff --git a/src/kernel2/src/syscalls/pm.c b/src/kernel2/src/syscalls/pm.c
index 2bcabef..c316884 100644
--- a/src/kernel2/src/syscalls/pm.c
+++ b/src/kernel2/src/syscalls/pm.c
@@ -265,6 +265,30 @@ void syscall_pm_sleep(void)
}
/**
+ * Privilegierte Version von syscall_pm_sleep, die dem alten Task einen
+ * spezifischen neuen Zustand gibt und zu einem bestimmten anderen Task
+ * wechseln kann.
+ */
+void kern_syscall_pm_sleep(tid_t yield_to, int status)
+{
+ pm_thread_t* thread = NULL;
+
+ current_thread->status = status;
+
+ if (yield_to) {
+ thread = pm_thread_get(NULL, yield_to);
+ }
+
+ if (thread) {
+ pm_scheduler_get(thread);
+ thread->status = PM_STATUS_RUNNING;
+ current_thread = thread;
+ } else {
+ current_thread = pm_scheduler_pop();
+ }
+}
+
+/**
* Die Kontrolle an einen anderen Task abgeben und erst wieder aufwachen,
* wenn ein RPC zu bearbeiten ist
*/
diff --git a/src/kernel2/src/tasks/scheduler.c b/src/kernel2/src/tasks/scheduler.c
index de95d83..d63ef13 100644
--- a/src/kernel2/src/tasks/scheduler.c
+++ b/src/kernel2/src/tasks/scheduler.c
@@ -239,6 +239,27 @@ void pm_scheduler_yield(void)
}
/**
+ * Kontrolle vom aktuellen Kernelthread an einen anderen Thread abgeben
+ *
+ * @tid TID des Threads, an den die Kontrolle übergeben werden soll, oder 0
+ * @status Thread-Status des alten Threads
+ */
+void pm_scheduler_kern_yield(tid_t tid, int status)
+{
+ asm volatile(
+ "push %2;"
+ "push %1;"
+ "int $0x30;"
+ "add $8, %%esp;"
+ : : "a" (KERN_SYSCALL_PM_SLEEP), "r" (tid), "r" (status));
+
+ // Es kann passieren, dass zwei Tasks im Kernel hin- und heryielden und
+ // auf irgendetwas warten, was von einem IRQ abhängt. Deshalb müssen wir
+ // dem IRQ eine Chance geben, anzukommen.
+ asm volatile("sti; nop; cli");
+}
+
+/**
* Macht den übergebenen Thread zum aktuellen Thread dieser CPU, wenn er
* momentan lauffähig ist. Wenn nicht, bleibt der bisherige Thread aktiv.
*/
--
1.7.7