[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