Implement SchedulerService
This commit is contained in:
@ -1,18 +1,10 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* 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/system/Globals.h"
|
||||
#include "Thread.h"
|
||||
#include "kernel/service/SchedulerService.h"
|
||||
#include "kernel/system/System.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@ -20,19 +12,14 @@ class IdleThread : public Thread {
|
||||
public:
|
||||
IdleThread(const Thread ©) = delete; // Verhindere Kopieren
|
||||
|
||||
IdleThread() : Thread("IdleThread") {}
|
||||
IdleThread() {
|
||||
tid = Thread::IDLE; // The IdleThread gets a fixed id for convenience
|
||||
}
|
||||
|
||||
[[noreturn]] void run() override {
|
||||
// Idle-Thread läuft, ab jetzt ist der Scheduler fertig initialisiert
|
||||
log.info() << "IdleThread enabled preemption" << endl;
|
||||
scheduler.enable_preemption(tid);
|
||||
if (!scheduler.preemption_enabled()) {
|
||||
log.error() << "Preemption disabled" << endl;
|
||||
}
|
||||
|
||||
auto &schedulerService = Kernel::System::getService<Kernel::SchedulerService>();
|
||||
while (true) {
|
||||
// Util::System::out << "Idle!" << endl;
|
||||
scheduler.yield();
|
||||
schedulerService.yield();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,42 +1,18 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* S C H E D U L E R *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Implementierung eines einfachen Zeitscheiben-Schedulers. *
|
||||
* Rechenbereite Threads werden in 'readQueue' verwaltet. *
|
||||
* *
|
||||
* Der Scheduler wird mit 'schedule' gestartet. Neue Threads*
|
||||
* können mit 'ready' hinzugefügt werden. Ein Thread muss *
|
||||
* die CPU::freiwillig mit 'yield' abgeben, damit andere auch*
|
||||
* rechnen koennen. Ein Thread kann sich selbst mit 'exit' *
|
||||
* terminieren. Ein Thread kann einen anderen Thread mit *
|
||||
* 'kill' beenden. Ein erzwungener Threadwechsel erfolgt *
|
||||
* mit der Funktion 'preempt', welche von der Timer-ISR *
|
||||
* aufgerufen wird. *
|
||||
* *
|
||||
* Zusaetzlich gibt es nun fuer die Semaphore zwei neue *
|
||||
* Funktionen 'block' und 'deblock'. *
|
||||
* *
|
||||
* Autor: Michael, Schoettner, HHU, 23.11.2018 *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "Scheduler.h"
|
||||
#include "IdleThread.h"
|
||||
#include <utility>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr const bool INSANE_TRACE = false;
|
||||
Scheduler::Scheduler() {
|
||||
ready_queue.push_back(Memory::make_unique<IdleThread>());
|
||||
// TODO: Cleanup thread
|
||||
}
|
||||
|
||||
void Scheduler::start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next) {
|
||||
active = next;
|
||||
if (active >= ready_queue.end()) {
|
||||
active = ready_queue.begin();
|
||||
log.debug() << "Scheduler::start started different thread than passed" << endl;
|
||||
}
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Starting Thread with id: " << dec << (*active)->tid << endl;
|
||||
}
|
||||
(*active)->start(); // First dereference the Iterator, then the unique_ptr to get Thread
|
||||
}
|
||||
@ -47,31 +23,9 @@ void Scheduler::switch_to(Thread *prev_raw, Container::Vector<Memory::unique_ptr
|
||||
active = ready_queue.begin();
|
||||
// log.debug() << "Scheduler::switch_to started different thread than passed" << endl;
|
||||
}
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Switching to Thread with id: " << dec << (*active)->tid << endl;
|
||||
}
|
||||
prev_raw->switchTo(**active);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: Scheduler::schedule *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Scheduler starten. Wird nur einmalig aus main.cc gerufen.*
|
||||
*****************************************************************************/
|
||||
void Scheduler::schedule() {
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
// We need to start the idle thread first as this one sets the scheduler to initialized
|
||||
// and enables preemption.
|
||||
// Otherwise preemption will be blocked and nothing will happen if the first threads
|
||||
// run() function is blocking
|
||||
|
||||
ready_queue.push_back(Memory::make_unique<IdleThread>());
|
||||
log.info() << "Starting scheduling: starting thread with id: " << dec << (*(ready_queue.end() - 1))->tid << endl;
|
||||
start(ready_queue.end() - 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: Scheduler::ready *
|
||||
*---------------------------------------------------------------------------*
|
||||
@ -79,7 +33,6 @@ void Scheduler::schedule() {
|
||||
*****************************************************************************/
|
||||
void Scheduler::ready(Memory::unique_ptr<Thread> &&thread) {
|
||||
Device::CPU::disable_int();
|
||||
log.debug() << "Adding to ready_queue, ID: " << dec << thread->tid << endl;
|
||||
ready_queue.push_back(std::move(thread));
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
@ -100,18 +53,16 @@ void Scheduler::exit() {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
if (ready_queue.size() == 1) {
|
||||
log.error() << "Can't exit last thread, active ID: " << dec << (*active)->tid << endl;
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug() << "Exiting thread, ID: " << dec << (*active)->tid << endl;
|
||||
start(ready_queue.erase(active)); // erase returns the next iterator after the erased element
|
||||
// cannot use switch_to here as the previous thread no longer
|
||||
// exists (was deleted by erase)
|
||||
|
||||
// Interrupts werden in Thread_switch in Thread.asm wieder zugelassen
|
||||
// dispatch kehr nicht zurueck
|
||||
// dispatch kehrt nicht zurueck
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -125,10 +76,10 @@ void Scheduler::exit() {
|
||||
* Parameter: *
|
||||
* that Zu terminierender Thread *
|
||||
*****************************************************************************/
|
||||
void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
void Scheduler::kill(uint16_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
uint32_t prev_tid = (*active)->tid;
|
||||
uint16_t prev_tid = (*active)->tid;
|
||||
|
||||
// Block queue, can always kill
|
||||
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin();
|
||||
@ -138,13 +89,12 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
|
||||
if (ptr != nullptr) {
|
||||
// Move old thread out of queue to return it
|
||||
uint32_t pos = distance(block_queue.begin(), it);
|
||||
uint16_t pos = distance(block_queue.begin(), it);
|
||||
*ptr = std::move(block_queue[pos]); // Return the killed thread
|
||||
}
|
||||
|
||||
// Just erase from queue, do not need to switch
|
||||
block_queue.erase(it);
|
||||
log.info() << "Killed thread from block_queue with id: " << tid << endl;
|
||||
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
@ -153,7 +103,6 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
|
||||
// Ready queue, can't kill last one
|
||||
if (ready_queue.size() == 1) {
|
||||
log.error() << "Kill: Can't kill last thread in ready_queue with id: " << tid << endl;
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
@ -165,13 +114,12 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
|
||||
if (ptr != nullptr) {
|
||||
// Move old thread out of queue to return it
|
||||
uint32_t pos = distance(ready_queue.begin(), it);
|
||||
uint16_t pos = distance(ready_queue.begin(), it);
|
||||
*ptr = std::move(ready_queue[pos]); // Return the killed thread
|
||||
}
|
||||
|
||||
if (tid == prev_tid) {
|
||||
// If we killed the active thread we need to switch to another one
|
||||
log.info() << "Killed active thread from ready_queue with id: " << tid << endl;
|
||||
|
||||
// Switch to current active after old active was removed
|
||||
start(ready_queue.erase(it));
|
||||
@ -179,27 +127,23 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
|
||||
// Just erase from queue, do not need to switch
|
||||
ready_queue.erase(it);
|
||||
log.info() << "Killed thread from ready_queue with id: " << tid << endl;
|
||||
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.error() << "Kill: Couldn't find thread with id: " << tid << " in ready- or block-queue" << endl;
|
||||
log.error() << "Mabe it already exited itself?" << endl;
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
// TODO: Can't retrive the thread right now because it's not clear when it's finished,
|
||||
// maybe introduce a exited_queue and get it from there
|
||||
void Scheduler::nice_kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
void Scheduler::nice_kill(uint16_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
for (Memory::unique_ptr<Thread> &thread: block_queue) {
|
||||
if (thread->tid == tid) {
|
||||
thread->suicide();
|
||||
log.info() << "Nice killed thread in block_queue with id: " << tid << endl;
|
||||
deblock(tid);
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
@ -209,14 +153,11 @@ void Scheduler::nice_kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
for (Memory::unique_ptr<Thread> &thread: ready_queue) {
|
||||
if (thread->tid == tid) {
|
||||
thread->suicide();
|
||||
log.info() << "Nice killed thread in ready_queue with id: " << tid << endl;
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.error() << "Can't nice kill thread (not found) with id: " << tid << endl;
|
||||
log.error() << "Mabe it already exited itself?" << endl;
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
@ -239,33 +180,12 @@ void Scheduler::yield() {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
if (ready_queue.size() == 1) {
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Skipping yield as no thread is waiting, active ID: " << dec << (*active)->tid << endl;
|
||||
}
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Yielding, ID: " << dec << (*active)->tid << endl;
|
||||
}
|
||||
switch_to((*active).get(), active + 1); // prev_raw is valid since no thread was killed/deleted
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: Scheduler::preempt *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Diese Funktion wird aus der ISR des PITs aufgerufen und *
|
||||
* schaltet auf den naechsten Thread um, sofern einer vor- *
|
||||
* handen ist. *
|
||||
*****************************************************************************/
|
||||
void Scheduler::preempt() {
|
||||
|
||||
/* Hier muss Code eingefuegt werden */
|
||||
|
||||
Device::CPU::disable_int();
|
||||
yield();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: Scheduler::block *
|
||||
*---------------------------------------------------------------------------*
|
||||
@ -283,7 +203,6 @@ void Scheduler::block() {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
if (ready_queue.size() == 1) {
|
||||
log.error() << "Can't block last thread, active ID: " << dec << (*active)->tid << endl;
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
@ -292,10 +211,6 @@ void Scheduler::block() {
|
||||
std::size_t pos = distance(ready_queue.begin(), active);
|
||||
block_queue.push_back(std::move(ready_queue[pos]));
|
||||
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Blocked thread with id: " << prev_raw->tid << endl;
|
||||
}
|
||||
|
||||
switch_to(prev_raw, ready_queue.erase(active)); // prev_raw is valid as thread was moved before vector erase
|
||||
}
|
||||
|
||||
@ -310,7 +225,7 @@ void Scheduler::block() {
|
||||
* *
|
||||
* Parameter: that: Thread der deblockiert werden soll. *
|
||||
*****************************************************************************/
|
||||
void Scheduler::deblock(uint32_t tid) {
|
||||
void Scheduler::deblock(uint16_t tid) {
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
@ -325,15 +240,11 @@ void Scheduler::deblock(uint32_t tid) {
|
||||
ready_queue.insert(active + 1, std::move(block_queue[pos])); // We insert the thread after the active
|
||||
// thread to prefer deblocked threads
|
||||
block_queue.erase(it);
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Deblocked thread with id: " << tid << endl;
|
||||
}
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.error() << "Couldn't deblock thread with id: " << tid << endl;
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
|
@ -20,20 +20,26 @@
|
||||
namespace Kernel {
|
||||
|
||||
class Scheduler {
|
||||
friend class SchedulerService;
|
||||
|
||||
friend class IdleThread;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor. Initializes the IdleThread.
|
||||
*/
|
||||
Scheduler();
|
||||
|
||||
Scheduler(const Scheduler ©) = delete; // Verhindere Kopieren
|
||||
|
||||
// TODO: Rest of constructors
|
||||
|
||||
private:
|
||||
NamedLogger log;
|
||||
[[nodiscard]] uint16_t get_active() const {
|
||||
return (*active)->tid;
|
||||
}
|
||||
|
||||
Container::Vector<Memory::unique_ptr<Thread>> ready_queue;
|
||||
Container::Vector<Memory::unique_ptr<Thread>> block_queue;
|
||||
|
||||
// It makes sense to keep track of the active thread through this as it makes handling the
|
||||
// unique_ptr easier and reduces the copying in the vector when cycling through the threads
|
||||
// as we don't have to keep the active thread at the front (would only make sense with a queue)
|
||||
Container::Vector<Memory::unique_ptr<Thread>>::iterator active = nullptr;
|
||||
|
||||
// Scheduler wird evt. von einer Unterbrechung vom Zeitgeber gerufen,
|
||||
// bevor er initialisiert wurde
|
||||
uint32_t idle_tid = 0;
|
||||
void ready(Memory::unique_ptr<Thread> &&thread);
|
||||
|
||||
// Roughly the old dispatcher functionality
|
||||
void start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next); // Start next without prev
|
||||
@ -41,46 +47,14 @@ private:
|
||||
// Switch from prev to next
|
||||
void switch_to(Thread *prev_raw, Container::Vector<Memory::unique_ptr<Thread>>::iterator next);
|
||||
|
||||
// Kann nur vom Idle-Thread aufgerufen werden (erster Thread der vom Scheduler gestartet wird)
|
||||
void enable_preemption(uint32_t tid) { idle_tid = tid; }
|
||||
// CPU freiwillig abgeben und Auswahl des naechsten Threads
|
||||
void yield(); // Returns when only the idle thread runs
|
||||
|
||||
friend class IdleThread;
|
||||
// Blocks current thread (move to block_queue)
|
||||
void block(); // Returns on error because we don't have exceptions
|
||||
|
||||
void ready(Memory::unique_ptr<Thread> &&thread);
|
||||
|
||||
public:
|
||||
Scheduler(const Scheduler ©) = delete; // Verhindere Kopieren
|
||||
|
||||
Scheduler() : log("SCHED"), ready_queue(true), block_queue(true) {} // lazy queues, wait for allocator
|
||||
|
||||
// The scheduler has to init the queues explicitly after the allocator is available
|
||||
void init() {
|
||||
ready_queue.reserve();
|
||||
block_queue.reserve();
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t get_active() const {
|
||||
return (*active)->tid;
|
||||
}
|
||||
|
||||
// Scheduler initialisiert?
|
||||
// Zeitgeber-Unterbrechung kommt evt. bevor der Scheduler fertig
|
||||
// intiialisiert wurde!
|
||||
[[nodiscard]] bool preemption_enabled() const { return idle_tid != 0U; }
|
||||
|
||||
// Scheduler starten
|
||||
void schedule();
|
||||
|
||||
// Helper that directly constructs the thread, then readys it
|
||||
template<typename T, typename... Args>
|
||||
uint32_t ready(Args... args) {
|
||||
Memory::unique_ptr<Thread> thread = Memory::make_unique<T>(std::forward<Args>(args)...);
|
||||
uint32_t tid = thread->tid;
|
||||
|
||||
ready(std::move(thread));
|
||||
|
||||
return tid;
|
||||
}
|
||||
// Deblock by tid (move to ready_queue)
|
||||
void deblock(uint16_t tid);
|
||||
|
||||
// Thread terminiert sich selbst
|
||||
// NOTE: When a thread exits itself it will disappear...
|
||||
@ -89,29 +63,29 @@ public:
|
||||
void exit(); // Returns on error because we don't have exceptions
|
||||
|
||||
// Thread mit 'Gewalt' terminieren
|
||||
void kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
void kill(uint16_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
|
||||
void kill(uint32_t tid) { kill(tid, nullptr); }
|
||||
void kill(uint16_t tid) { kill(tid, nullptr); }
|
||||
|
||||
// Asks thread to exit
|
||||
// NOTE: I had many problems with killing threads that were stuck in some semaphore
|
||||
// or were involved in any locking mechanisms, so with this a thread can make sure
|
||||
// to "set things right" before exiting itself (but could also be ignored)
|
||||
void nice_kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
void nice_kill(uint16_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
|
||||
void nice_kill(uint32_t tid) { nice_kill(tid, nullptr); }
|
||||
void nice_kill(uint16_t tid) { nice_kill(tid, nullptr); }
|
||||
|
||||
// CPU freiwillig abgeben und Auswahl des naechsten Threads
|
||||
void yield(); // Returns when only the idle thread runs
|
||||
private:
|
||||
Container::Vector<Memory::unique_ptr<Thread>> ready_queue;
|
||||
Container::Vector<Memory::unique_ptr<Thread>> block_queue;
|
||||
Container::Vector<Memory::unique_ptr<Thread>> exited; // TODO: Manage exited threads
|
||||
|
||||
// Thread umschalten; wird aus der ISR des PITs gerufen
|
||||
void preempt(); // Returns when only the idle thread runs
|
||||
// It makes sense to keep track of the active thread through this as it makes handling the
|
||||
// unique_ptr easier and reduces the copying in the vector when cycling through the threads
|
||||
// as we don't have to keep the active thread at the front (would only make sense with a queue)
|
||||
Container::Vector<Memory::unique_ptr<Thread>>::iterator active = nullptr;
|
||||
|
||||
// Blocks current thread (move to block_queue)
|
||||
void block(); // Returns on error because we don't have exceptions
|
||||
|
||||
// Deblock by tid (move to ready_queue)
|
||||
void deblock(uint32_t tid);
|
||||
// TODO: Synchronization
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -22,20 +22,20 @@
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
// TODO: Move to thread_interface or sth.
|
||||
// Funktionen, die auf der Assembler-Ebene implementiert werden, muessen als
|
||||
// extern "C" deklariert werden, da sie nicht dem Name-Mangeling von C++
|
||||
// entsprechen.
|
||||
extern "C" {
|
||||
void Thread_start(uint32_t esp);
|
||||
|
||||
// NOTE: Only when backing up the previous thread the esp gets updated,
|
||||
// so only esp_pre is a pointer
|
||||
// NOTE: Only when backing up the previous thread the esp gets updated, so only esp_pre is a pointer
|
||||
void Thread_switch(uint32_t *esp_prev, uint32_t esp_next);
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
uint32_t ThreadCnt = 1; // Skip tid 0 as the scheduler indicates no preemption with 0
|
||||
uint16_t ThreadCnt = 2; // Skip IDs that are fixed to specific unique threads
|
||||
|
||||
/*****************************************************************************
|
||||
* Prozedur: Coroutine_init *
|
||||
@ -99,13 +99,11 @@ void Thread_init(uint32_t *esp, uint32_t *stack, void (*kickoff)(Thread *), void
|
||||
* Parameter: *
|
||||
* stack Stack für die neue Koroutine *
|
||||
*****************************************************************************/
|
||||
Thread::Thread(char *name) : stack(new uint32_t[1024]), esp(0), log(name), name(name), tid(ThreadCnt++) {
|
||||
Thread::Thread() : tid(ThreadCnt++), stack(new uint32_t[1024]), esp(0) {
|
||||
if (stack == nullptr) {
|
||||
log.error() << "Couldn't initialize Thread (couldn't alloc stack)" << endl;
|
||||
// TODO: Exception
|
||||
return;
|
||||
}
|
||||
|
||||
log.info() << "Initialized thread with ID: " << tid << " (" << name << ")" << endl;
|
||||
Thread_init(&esp, &stack[1024], kickoff, this); // Stack grows from top to bottom
|
||||
}
|
||||
|
||||
@ -118,7 +116,6 @@ void Thread::switchTo(Thread &next) {
|
||||
|
||||
/* hier muss Code eingefügt werden */
|
||||
|
||||
// log.trace() << name << ":: Has esp " << hex << esp << endl;
|
||||
Thread_switch(&esp, next.esp);
|
||||
}
|
||||
|
||||
|
@ -33,25 +33,33 @@
|
||||
namespace Kernel {
|
||||
|
||||
class Thread {
|
||||
private:
|
||||
uint32_t *stack;
|
||||
uint32_t esp;
|
||||
friend class SchedulerService;
|
||||
|
||||
friend class Scheduler;
|
||||
|
||||
protected:
|
||||
Thread(char *name);
|
||||
// TODO: Remove this
|
||||
bool running = true; // For soft exit, if thread uses infinite loop inside run(), use this as condition
|
||||
|
||||
NamedLogger log;
|
||||
|
||||
bool running = true; // For soft exit, if thread uses infinite loop inside run(), use this as condition
|
||||
char *name; // For logging
|
||||
uint32_t tid; // Thread-ID (wird im Konstruktor vergeben)
|
||||
friend class Scheduler; // Scheduler can access tid
|
||||
// TODO: Public this
|
||||
uint16_t tid; // Thread-ID (wird im Konstruktor vergeben)
|
||||
|
||||
public:
|
||||
Thread(const Thread ©) = delete; // Verhindere Kopieren
|
||||
// TODO: Is this a good idea?
|
||||
enum Threads : uint16_t {
|
||||
IDLE = 0,
|
||||
CLEANUP = 1 // TODO: Can cleanup be done in a thread?
|
||||
};
|
||||
|
||||
public:
|
||||
Thread();
|
||||
|
||||
Thread(const Thread ©) = delete; // Verhindere Kopieren
|
||||
|
||||
// TODO: Rest of constructors
|
||||
|
||||
// TODO: Investigate this
|
||||
virtual ~Thread() {
|
||||
log.info() << "Uninitialized thread, ID: " << dec << tid << " (" << name << ")" << endl;
|
||||
delete[] stack;
|
||||
}
|
||||
|
||||
@ -66,6 +74,10 @@ public:
|
||||
|
||||
// Methode des Threads, muss in Sub-Klasse implementiert werden
|
||||
virtual void run() = 0;
|
||||
|
||||
private:
|
||||
uint32_t *stack;
|
||||
uint32_t esp;
|
||||
};
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user