From 32b1f2391f56c753a59fbd1f4d41a52591ca9f2d Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Thu, 2 Jun 2022 13:01:43 +0200 Subject: [PATCH] add vorgabe06 --- c_os/kernel/Globals.cc | 1 + c_os/kernel/Globals.h | 2 + c_os/kernel/threads/Dispatch.cc | 48 ++++++++++++++++ c_os/kernel/threads/Dispatch.h | 35 ++++++++++++ c_os/kernel/threads/IdleThread.h | 35 ++++++++++++ c_os/kernel/threads/Scheduler.cc | 95 ++++++++++++++++++++++++++++++++ c_os/kernel/threads/Scheduler.h | 46 ++++++++++++++++ c_os/kernel/threads/Thread.h | 54 ++++++++++++++++++ c_os/lib/Queue.h | 44 +++++++++++++++ c_os/user/CoopThreadDemo.cc | 26 +++++++++ c_os/user/CoopThreadDemo.h | 31 +++++++++++ c_os/user/HelloWorldThread.cc | 27 +++++++++ c_os/user/HelloWorldThread.h | 30 ++++++++++ c_os/user/LoopThread.cc | 22 ++++++++ c_os/user/LoopThread.h | 29 ++++++++++ 15 files changed, 525 insertions(+) create mode 100755 c_os/kernel/threads/Dispatch.cc create mode 100755 c_os/kernel/threads/Dispatch.h create mode 100755 c_os/kernel/threads/IdleThread.h create mode 100755 c_os/kernel/threads/Scheduler.cc create mode 100755 c_os/kernel/threads/Scheduler.h create mode 100755 c_os/kernel/threads/Thread.h create mode 100755 c_os/lib/Queue.h create mode 100755 c_os/user/CoopThreadDemo.cc create mode 100755 c_os/user/CoopThreadDemo.h create mode 100755 c_os/user/HelloWorldThread.cc create mode 100755 c_os/user/HelloWorldThread.h create mode 100755 c_os/user/LoopThread.cc create mode 100755 c_os/user/LoopThread.h diff --git a/c_os/kernel/Globals.cc b/c_os/kernel/Globals.cc index 7fc089a..4b4acb3 100755 --- a/c_os/kernel/Globals.cc +++ b/c_os/kernel/Globals.cc @@ -20,3 +20,4 @@ unsigned int total_mem; // RAM total // BumpAllocator allocator; // LinkedListAllocator allocator; TreeAllocator allocator; +Scheduler scheduler; diff --git a/c_os/kernel/Globals.h b/c_os/kernel/Globals.h index 7b1ac96..300c0ea 100755 --- a/c_os/kernel/Globals.h +++ b/c_os/kernel/Globals.h @@ -19,6 +19,7 @@ #include "kernel/CPU.h" #include "kernel/interrupts/IntDispatcher.h" #include "kernel/interrupts/PIC.h" +#include "kernel/threads/Scheduler.h" extern CPU cpu; // CPU-spezifische Funktionen extern PCSPK pcspk; // PC-Lautsprecher @@ -30,6 +31,7 @@ extern unsigned int total_mem; // RAM total // extern BumpAllocator allocator; // extern LinkedListAllocator allocator; extern TreeAllocator allocator; +extern Scheduler scheduler; constexpr bool DEBUG = true; diff --git a/c_os/kernel/threads/Dispatch.cc b/c_os/kernel/threads/Dispatch.cc new file mode 100755 index 0000000..f027df4 --- /dev/null +++ b/c_os/kernel/threads/Dispatch.cc @@ -0,0 +1,48 @@ +/***************************************************************************** + * * + * D I S P A T C H E R * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Implementierung des Dispatchers. * + * Der Dispatcher verwaltet den 'active'-Pointer, der den * + * jeweils aktiven Thread angibt. Mit 'start()' wird der * + * 'active' Pointer initialisiert und der erste Thread ge- * + * startet, alle weiteren Kontextwechsel werden mit * + * 'dispatch()' ausgeloest. 'get_active()' liefert den * + * 'active' Pointer zurueck. * + * * + * Autor: Olaf Spinczyk, TU Dortmund * + *****************************************************************************/ + +#include "kernel/threads/Dispatch.h" + + +/***************************************************************************** + * Methode: Dispatcher::start * + *---------------------------------------------------------------------------* + * Beschreibung: Thread starten. * + * * + * Parameter: * + * first Zu startender Thread. * + *****************************************************************************/ +void Dispatcher::start (Thread& first) { + if (!active) { + active = &first; + active->start (); + } +} + + +/***************************************************************************** + * Methode: Dispatcher::dispatch * + *---------------------------------------------------------------------------* + * Beschreibung: Auf einen gegebenen Thread wechseln. * + * * + * Parameter: * + * next Thread der die CPU erhalten soll. * + *****************************************************************************/ +void Dispatcher::dispatch (Thread& next) { + Thread* current = active; + active = &next; + current->switchTo (next); +} diff --git a/c_os/kernel/threads/Dispatch.h b/c_os/kernel/threads/Dispatch.h new file mode 100755 index 0000000..a7275f0 --- /dev/null +++ b/c_os/kernel/threads/Dispatch.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * * + * D I S P A T C H E R * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Implementierung des Dispatchers. * + * Der Dispatcher verwaltet den 'active'-Pointer, der den * + * jeweils aktiven Thread angibt. Mit 'start()' wird der * + * 'active' Pointer initialisiert und der erste Thread ge- * + * startet, alle weiteren Kontextwechsel werden mit * + * 'dispatch()' ausgeloest. 'get_active()' liefert den * + * 'active' Pointer zurueck. * + * * + * Autor: Olaf Spinczyk, TU Dortmund * + *****************************************************************************/ +#ifndef __dispatch_include__ +#define __dispatch_include__ + +#include "kernel/threads/Thread.h" + +class Dispatcher { + +private: + Thread* active; // aktiver Thread + + Dispatcher(const Dispatcher ©); // Verhindere Kopieren + +public: + Dispatcher () : active (0) {} + void start (Thread& first); + void dispatch (Thread& next); + Thread* get_active () { return active; } +}; + +#endif diff --git a/c_os/kernel/threads/IdleThread.h b/c_os/kernel/threads/IdleThread.h new file mode 100755 index 0000000..9ebcd19 --- /dev/null +++ b/c_os/kernel/threads/IdleThread.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * * + * I D L E T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Wird nur aktiviert, wenn kein Thread arbeiten moechte. * + * * + * Autor: Michael, Schoettner, HHU, 13.8.2016 * + *****************************************************************************/ + +#ifndef __IdleThread_include__ +#define __IdleThread_include__ + + +#include "kernel/threads/Thread.h" +#include "kernel/Globals.h" + + +class IdleThread : public Thread { + +private: + IdleThread(const Thread ©); // Verhindere Kopieren + +public: + IdleThread () : Thread () { } + + void run () { + while (1) { + scheduler.yield (); + } + } + + }; + +#endif diff --git a/c_os/kernel/threads/Scheduler.cc b/c_os/kernel/threads/Scheduler.cc new file mode 100755 index 0000000..25a8207 --- /dev/null +++ b/c_os/kernel/threads/Scheduler.cc @@ -0,0 +1,95 @@ +/***************************************************************************** + * * + * S C H E D U L E R * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Implementierung eines einfachen Zeitscheiben-Schedulers. * + * Rechenbereite Threads werden in 'readQueue' verwaltet. * + * * + * Autor: Michael, Schoettner, HHU, 23.11.2018 * + *****************************************************************************/ + +#include "kernel/threads/Scheduler.h" +#include "kernel/threads/IdleThread.h" + + + +/***************************************************************************** + * Methode: Scheduler::schedule * + *---------------------------------------------------------------------------* + * Beschreibung: Scheduler starten. Wird nur einmalig aus main.cc gerufen.* + *****************************************************************************/ +void Scheduler::schedule () { + + /* hier muss Code eingefuegt werden */ + + /* Bevor diese Methode anufgerufen wird, muss zumindest der Idle-Thread + * in der Queue eingefuegt worden sein. + */ +} + + +/***************************************************************************** + * Methode: Scheduler::ready * + *---------------------------------------------------------------------------* + * Beschreibung: Thread in readyQueue eintragen. * + * * + * Parameter: * + * that Einzutragender Thread * + *****************************************************************************/ +void Scheduler::ready (Thread * that) { + + /* hier muss Code eingefuegt werden */ + +} + + +/***************************************************************************** + * Methode: Scheduler::exit * + *---------------------------------------------------------------------------* + * Beschreibung: Thread ist fertig und terminiert sich selbst. Hier muss * + * nur auf den naechsten Thread mithilfe des Dispatchers * + * umgeschaltet werden. Der aktuell laufende Thread ist * + * nicht in der readyQueue. * + *****************************************************************************/ +void Scheduler::exit () { + + /* hier muss Code eingefuegt werden */ + +} + + +/***************************************************************************** + * Methode: Scheduler::kill * + *---------------------------------------------------------------------------* + * Beschreibung: Thread mit 'Gewalt' terminieren. Er wird aus der * + * readyQueue ausgetragen und wird dann nicht mehr aufge- * + * rufen. Der Aufrufer dieser Methode muss ein anderer * + * Thread sein. * + * * + * Parameter: * + * that Zu terminierender Thread * + *****************************************************************************/ +void Scheduler::kill (Thread * that) { + + /* hier muss Code eingefuegt werden */ + +} + + +/***************************************************************************** + * Methode: Scheduler::yield * + *---------------------------------------------------------------------------* + * Beschreibung: CPU freiwillig abgeben und Auswahl des naechsten Threads.* + * Naechsten Thread aus der readyQueue holen, den aktuellen * + * in die readyQueue wieder eintragen. Das Umschalten soll * + * mithilfe des Dispatchers erfolgen. * + * * + * Achtung: Falls nur der Idle-Thread läuft, so ist die * + * readyQueue leer. * + *****************************************************************************/ +void Scheduler::yield () { + + /* hier muss Code eingefuegt werden */ + +} diff --git a/c_os/kernel/threads/Scheduler.h b/c_os/kernel/threads/Scheduler.h new file mode 100755 index 0000000..14bead5 --- /dev/null +++ b/c_os/kernel/threads/Scheduler.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * * + * S C H E D U L E R * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Implementierung eines einfachen Zeitscheiben-Schedulers. * + * Rechenbereite Threads werden in 'readQueue' verwaltet. * + * * + * Autor: Michael, Schoettner, HHU, 22.8.2016 * + *****************************************************************************/ + +#ifndef __Scheduler_include__ +#define __Scheduler_include__ + +#include "kernel/threads/Dispatch.h" +#include "kernel/threads/Thread.h" +#include "lib/Queue.h" + +class Scheduler : public Dispatcher { + +private: + Scheduler (const Scheduler ©); // Verhindere Kopieren + +private: + Queue readyQueue; // auf die CPU wartende Threads + +public: + Scheduler () {} + + // Scheduler starten + void schedule (); + + // Thread in readyQueue eintragen + void ready (Thread * that); + + // Thread terminiert sich selbst + void exit (); + + // Thread mit 'Gewalt' terminieren + void kill (Thread * that); + + // CPU freiwillig abgeben und Auswahl des naechsten Threads + void yield (); +}; + +#endif diff --git a/c_os/kernel/threads/Thread.h b/c_os/kernel/threads/Thread.h new file mode 100755 index 0000000..04faf55 --- /dev/null +++ b/c_os/kernel/threads/Thread.h @@ -0,0 +1,54 @@ +/***************************************************************************** + * * + * T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Implementierung eines kooperativen Thread-Konzepts. * + * Thread-Objekte werden vom Scheduler in einer verketteten * + * Liste 'readylist' verwaltet. * + * * + * Im Konstruktor wird der initialie Kontext des Threads * + * eingerichtet. Mit 'start' wird ein Thread aktiviert. * + * Die CPU sollte mit 'yield' freiwillig abgegeben werden. * + * Um bei einem Threadwechsel den Kontext sichern zu * + * koennen, enthaelt jedes Threadobjekt eine Struktur * + * ThreadState, in dem die Werte der nicht-fluechtigen * + * Register gesichert werden koennen. * + * * + * Autor: Michael, Schoettner, HHU, 16.12.2016 * + *****************************************************************************/ + +#ifndef __Thread_include__ +#define __Thread_include__ + +#include "kernel/threads/ThreadState.h" +#include "lib/Chain.h" + +class Thread : public Chain { + +private: + Thread(const Thread ©); // Verhindere Kopieren + +private: + struct ThreadState regs; + unsigned int *stack; + +public: + unsigned int tid; // Thread-ID (wird im Konstruktor vergeben) + + Thread () { } + + // Thread aktivieren + void start (); + + // Umschalten auf Thread 'next' + void switchTo (Thread& next); + + // Methode des Threads, muss in Sub-Klasse implementiert werden + virtual void run () = 0; + + ~Thread (); + + }; + +#endif diff --git a/c_os/lib/Queue.h b/c_os/lib/Queue.h new file mode 100755 index 0000000..584516b --- /dev/null +++ b/c_os/lib/Queue.h @@ -0,0 +1,44 @@ +/***************************************************************************** +* * +* Q U E U E * +* * +*---------------------------------------------------------------------------* +* Beschreibung: Implementierung einer einfach verketteten Liste von * +* Chain Objekten. Die Implementierung ist etwas trickreich * +* 'tail' verweist naemlich nicht, wie oft ueblich, auf das * +* letzte Element der Liste, sondern auf den 'next' Zeiger * +* des letzten Elements, bzw., solange die Liste noch leer * +* ist, auf den 'head' Zeiger der Liste. Dadurch muss beim * +* Anfuegen eines Elements an die Liste nicht ueberprueft * +* werden, ob bereits Elemente in ihr enthalten sind. Beim * +* Entfernen von Elementen kann auf die Fallunterscheidung * +* allerdings nicht verzichtet werden. * +* * +* Autor: Olaf Spinczyk, TU Dortmund * +*****************************************************************************/ + +#ifndef __Queue_include__ +#define __Queue_include__ + +#include "lib/Chain.h" + +class Queue { + +private: + Queue(const Queue& copy); // Verhindere Kopieren + +protected: + Chain* head; + Chain** tail; + +public: + Queue() { + head = 0; + tail = &head; + } + void enqueue(Chain* item); + Chain* dequeue(); + void remove(Chain*); +}; + +#endif diff --git a/c_os/user/CoopThreadDemo.cc b/c_os/user/CoopThreadDemo.cc new file mode 100755 index 0000000..7cbc0a7 --- /dev/null +++ b/c_os/user/CoopThreadDemo.cc @@ -0,0 +1,26 @@ +/***************************************************************************** + * * + * C O O P E R A T I V E T H R E A D D E M O * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Beispiel für kooperative Threads. * + * * + * Autor: Michael Schoettner, HHU, 21.8.2016 * + *****************************************************************************/ + +#include "kernel/Globals.h" +#include "user/CoopThreadDemo.h" +#include "user/LoopThread.h" + + +/***************************************************************************** + * Methode: CoopThreadDemo::run * + *---------------------------------------------------------------------------* + * Beschreibung: Der Anwendungsthread erzeugt drei Threads die Zaehler * + * ausgeben und terminiert sich selbst. * + *****************************************************************************/ +void CoopThreadDemo::run () { + + /* Hier muss Code eingefuegt werden */ + +} diff --git a/c_os/user/CoopThreadDemo.h b/c_os/user/CoopThreadDemo.h new file mode 100755 index 0000000..91c4f2a --- /dev/null +++ b/c_os/user/CoopThreadDemo.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * * + * C O O P E R A T I V E T H R E A D D E M O * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Beispiel für kooperative Threads. * + * * + * Autor: Michael Schoettner, HHU, 21.8.2016 * + *****************************************************************************/ +#ifndef __coopthreaddemo_include__ +#define __coopthreaddemo_include__ + + +#include "kernel/threads/Thread.h" + + +class CoopThreadDemo : public Thread { + +private: + CoopThreadDemo (const CoopThreadDemo ©); // Verhindere Kopieren + +public: + // Gib dem Anwendungsthread einen Stack. + CoopThreadDemo () : Thread () { } + + // Thread-Startmethode + void run (); + + }; + +#endif diff --git a/c_os/user/HelloWorldThread.cc b/c_os/user/HelloWorldThread.cc new file mode 100755 index 0000000..24747be --- /dev/null +++ b/c_os/user/HelloWorldThread.cc @@ -0,0 +1,27 @@ +/***************************************************************************** + * * + * H E L L O W O R L D T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Ein einfacher Thread. * + * * + * Autor: Michael Schoettner, HHU, 21.8.2016 * + *****************************************************************************/ + +#include "kernel/Globals.h" +#include "user/HelloWorldThread.h" + + + +/***************************************************************************** + * Methode: HelloWorldThread::run * + *---------------------------------------------------------------------------* + * Beschreibung: Einstiegsfunktion in unseren Thread. * + *****************************************************************************/ +void HelloWorldThread::run () { + + kout << "Hallo Welt von einem Thread!" << endl; + + // selbst terminieren + scheduler.exit (); +} diff --git a/c_os/user/HelloWorldThread.h b/c_os/user/HelloWorldThread.h new file mode 100755 index 0000000..a2b9ee6 --- /dev/null +++ b/c_os/user/HelloWorldThread.h @@ -0,0 +1,30 @@ +/***************************************************************************** + * * + * H E L L O W O R L D T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Ein einfacher Thread. * + * * + * Autor: Michael Schoettner, HHU, 16.12.2016 * + *****************************************************************************/ +#ifndef __hello_world_thread_include__ +#define __hello_world_thread_include__ + + +#include "kernel/threads/Thread.h" + + +class HelloWorldThread : public Thread { + +private: + HelloWorldThread (const HelloWorldThread ©); // Verhindere Kopieren + +public: + HelloWorldThread () : Thread () { } + + // Thread-Startmethode + void run (); + + }; + +#endif diff --git a/c_os/user/LoopThread.cc b/c_os/user/LoopThread.cc new file mode 100755 index 0000000..dcdc9ac --- /dev/null +++ b/c_os/user/LoopThread.cc @@ -0,0 +1,22 @@ +/***************************************************************************** + * * + * L O O P T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Demo eines Threads. Schleife die Zahlen ausgibt. * + *****************************************************************************/ + +#include "user/LoopThread.h" +#include "kernel/Globals.h" + + +/***************************************************************************** + * Methode: LoopThread::run * + *---------------------------------------------------------------------------* + * Beschreibung: Code des Threads. * + *****************************************************************************/ +void LoopThread::run () { + + /* Hier muss Code eingefuegt werden */ + +} diff --git a/c_os/user/LoopThread.h b/c_os/user/LoopThread.h new file mode 100755 index 0000000..47e9ec1 --- /dev/null +++ b/c_os/user/LoopThread.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * * + * L O O P T H R E A D * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Demo eines Threads. Schleife die Zahlen ausgibt. * + *****************************************************************************/ + +#ifndef __loopthread_include__ +#define __loopthread_include__ + +#include "kernel/threads/Thread.h" + +class LoopThread : public Thread { + +private: + int id; + + LoopThread (const LoopThread ©); // Verhindere Kopieren + +public: + // Gibt der Loop einen Stack und eine Id. + LoopThread (int i) : Thread () { id = i; } + + // Zaehlt einen Zaehler hoch und gibt ihn auf dem Bildschirm aus. + void run (); +}; + +#endif