adapt to scheduler rework
This commit is contained in:
@ -30,7 +30,7 @@ public:
|
|||||||
void run() override {
|
void run() override {
|
||||||
// Idle-Thread läuft, ab jetzt ist der Scheduler fertig initialisiert
|
// Idle-Thread läuft, ab jetzt ist der Scheduler fertig initialisiert
|
||||||
log << INFO << "IdleThread enabled preemption" << endl;
|
log << INFO << "IdleThread enabled preemption" << endl;
|
||||||
scheduler.enable_preemption();
|
scheduler.enable_preemption(this->tid);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// kout << "Idle!" << endl;
|
// kout << "Idle!" << endl;
|
||||||
|
|||||||
@ -31,7 +31,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger Thread::log = Logger("Thread");
|
Logger Thread::log = Logger("Thread");
|
||||||
unsigned int ThreadCnt = 0;
|
unsigned int ThreadCnt = 1; // Skip tid 0 as the scheduler indicates no preemption with 0
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Prozedur: Coroutine_init *
|
* Prozedur: Coroutine_init *
|
||||||
|
|||||||
@ -11,7 +11,7 @@ void Semaphore::p() {
|
|||||||
this->lock.release();
|
this->lock.release();
|
||||||
} else {
|
} else {
|
||||||
// Block and manage thread in semaphore queue until it's woken up by v() again
|
// Block and manage thread in semaphore queue until it's woken up by v() again
|
||||||
this->waitQueue.push_back(scheduler.get_active());
|
this->wait_queue.push_back(scheduler.get_active());
|
||||||
this->lock.release();
|
this->lock.release();
|
||||||
scheduler.block(); // Moves to next thread
|
scheduler.block(); // Moves to next thread
|
||||||
}
|
}
|
||||||
@ -20,16 +20,16 @@ void Semaphore::p() {
|
|||||||
void Semaphore::v() {
|
void Semaphore::v() {
|
||||||
this->lock.acquire();
|
this->lock.acquire();
|
||||||
|
|
||||||
if (!this->waitQueue.empty()) {
|
if (!this->wait_queue.empty()) {
|
||||||
// Semaphore stays busy and unblocks next thread to work in critical section
|
// Semaphore stays busy and unblocks next thread to work in critical section
|
||||||
if (this->waitQueue.empty()) {
|
if (this->wait_queue.empty()) {
|
||||||
this->lock.release();
|
this->lock.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Thread* next = this->waitQueue[0];
|
unsigned int tid = this->wait_queue.front();
|
||||||
this->waitQueue.erase(waitQueue.begin());
|
this->wait_queue.erase(wait_queue.begin());
|
||||||
this->lock.release();
|
this->lock.release();
|
||||||
scheduler.deblock(next);
|
scheduler.deblock(tid);
|
||||||
} else {
|
} else {
|
||||||
// No more threads want to work so free semaphore
|
// No more threads want to work so free semaphore
|
||||||
this->counter = this->counter + 1;
|
this->counter = this->counter + 1;
|
||||||
|
|||||||
@ -20,7 +20,7 @@ private:
|
|||||||
Semaphore(const Semaphore& copy) = delete; // Verhindere Kopieren
|
Semaphore(const Semaphore& copy) = delete; // Verhindere Kopieren
|
||||||
|
|
||||||
// Queue fuer wartende Threads.
|
// Queue fuer wartende Threads.
|
||||||
bse::Vector<Thread*> waitQueue;
|
bse::Vector<unsigned int> wait_queue;
|
||||||
SpinLock lock;
|
SpinLock lock;
|
||||||
|
|
||||||
int counter;
|
int counter;
|
||||||
|
|||||||
@ -62,8 +62,8 @@ int main() {
|
|||||||
waitForReturn();
|
waitForReturn();
|
||||||
|
|
||||||
// Scheduler starten (schedule() erzeugt den Idle-Thread)
|
// Scheduler starten (schedule() erzeugt den Idle-Thread)
|
||||||
scheduler.ready(new MainMenu()); // NOTE: A thread that manages other threads has to be added before scheduler.schedule(),
|
scheduler.ready<MainMenu>(); // NOTE: A thread that manages other threads has to be added before scheduler.schedule(),
|
||||||
// because scheduler.schedule() doesn't return, only threads get cpu time
|
// because scheduler.schedule() doesn't return, only threads get cpu time
|
||||||
scheduler.schedule();
|
scheduler.schedule();
|
||||||
|
|
||||||
// NOTE: Enforced ToDo's (needed)
|
// NOTE: Enforced ToDo's (needed)
|
||||||
@ -119,7 +119,7 @@ int main() {
|
|||||||
// TODO: Use singleton pattern for some device classes/classes used only in globals
|
// TODO: Use singleton pattern for some device classes/classes used only in globals
|
||||||
// TODO: Introduce name to threads?
|
// TODO: Introduce name to threads?
|
||||||
// DONE: Remove Iterator from List.h
|
// DONE: Remove Iterator from List.h
|
||||||
// TODO: Move Array/ArrayList/LinkedList/List to bse namespace
|
// DONE: Move Array/ArrayList/LinkedList/List to bse namespace
|
||||||
// TODO: Remove the Input.h file and replace functionality with kevman
|
// TODO: Remove the Input.h file and replace functionality with kevman
|
||||||
// TODO: Fix the output locking, lock for every kout till endl? (kout << ... << endl)
|
// TODO: Fix the output locking, lock for every kout till endl? (kout << ... << endl)
|
||||||
|
|
||||||
|
|||||||
@ -29,52 +29,47 @@ void MainMenu::run() {
|
|||||||
print_demo_menu();
|
print_demo_menu();
|
||||||
|
|
||||||
char input = '\0';
|
char input = '\0';
|
||||||
Thread* choosen_demo = NULL;
|
unsigned int running_demo = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
input = this->listener.waitForKeyEvent();
|
input = this->listener.waitForKeyEvent();
|
||||||
|
|
||||||
if (choosen_demo == NULL) {
|
if (running_demo == 0) {
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case '1':
|
case '1':
|
||||||
choosen_demo = new TextDemo();
|
running_demo = scheduler.ready<TextDemo>();
|
||||||
break;
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
choosen_demo = new PCSPKdemo(&PCSPK::aerodynamic);
|
running_demo = scheduler.ready<PCSPKdemo>(&PCSPK::aerodynamic);
|
||||||
break;
|
break;
|
||||||
case '3':
|
case '3':
|
||||||
choosen_demo = new KeyboardDemo();
|
running_demo = scheduler.ready<KeyboardDemo>();
|
||||||
break;
|
break;
|
||||||
case '4':
|
case '4':
|
||||||
choosen_demo = new HeapDemo();
|
running_demo = scheduler.ready<HeapDemo>();
|
||||||
break;
|
break;
|
||||||
case '5':
|
case '5':
|
||||||
choosen_demo = new VBEdemo();
|
running_demo = scheduler.ready<VBEdemo>();
|
||||||
break;
|
break;
|
||||||
case '6':
|
case '6':
|
||||||
choosen_demo = new BlueScreenDemo();
|
running_demo = scheduler.ready<BlueScreenDemo>();
|
||||||
break;
|
break;
|
||||||
case '7':
|
case '7':
|
||||||
choosen_demo = new PreemptiveThreadDemo(3);
|
running_demo = scheduler.ready<PreemptiveThreadDemo>(3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
choosen_demo = new VectorDemo();
|
running_demo = scheduler.ready<VectorDemo>();
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
choosen_demo = new ArrayDemo();
|
running_demo = scheduler.ready<ArrayDemo>();
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
choosen_demo = new SmartPointerDemo();
|
running_demo = scheduler.ready<SmartPointerDemo>();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (choosen_demo != NULL) {
|
|
||||||
// We actually chose something
|
|
||||||
scheduler.ready(choosen_demo);
|
|
||||||
}
|
|
||||||
} else if (input == 'K') {
|
} else if (input == 'K') {
|
||||||
scheduler.kill(choosen_demo); // NOTE: If thread exits itself this will throw error
|
scheduler.kill(running_demo); // NOTE: If thread exits itself this will throw error
|
||||||
choosen_demo = NULL;
|
running_demo = 0;
|
||||||
print_demo_menu();
|
print_demo_menu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ private:
|
|||||||
KeyEventListener listener;
|
KeyEventListener listener;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainMenu() : listener(*this) {
|
MainMenu() : listener(this->tid) {
|
||||||
log << INFO << "MainMenu initialized with ID: " << dec << this->tid << endl;
|
log << INFO << "MainMenu initialized with ID: " << dec << this->tid << endl;
|
||||||
kevman.subscribe(this->listener);
|
kevman.subscribe(this->listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ private:
|
|||||||
KeyEventListener listener;
|
KeyEventListener listener;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyboardDemo() : listener(*this) {
|
KeyboardDemo() : listener(this->tid) {
|
||||||
log << INFO << "Initialized KeyboardDemo with ID: " << dec << this->tid << endl;
|
log << INFO << "Initialized KeyboardDemo with ID: " << dec << this->tid << endl;
|
||||||
kevman.subscribe(this->listener);
|
kevman.subscribe(this->listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,8 @@ void PreemptiveLoopThread::run() {
|
|||||||
// Basic synchronization by semaphore
|
// Basic synchronization by semaphore
|
||||||
// NOTE: I placed the semaphore inside the CGA_Stream so multiple demos can synchronize, not
|
// NOTE: I placed the semaphore inside the CGA_Stream so multiple demos can synchronize, not
|
||||||
// only this one. This is optional so disruptions can still occur because of preemption
|
// only this one. This is optional so disruptions can still occur because of preemption
|
||||||
|
// (I only use this for the user output (demos), anywhere else could become problematic
|
||||||
|
// quickly...)
|
||||||
kout.lock();
|
kout.lock();
|
||||||
|
|
||||||
// Saving + restoring kout position doesn't help much as preemption still occurs
|
// Saving + restoring kout position doesn't help much as preemption still occurs
|
||||||
@ -19,17 +21,13 @@ void PreemptiveLoopThread::run() {
|
|||||||
|
|
||||||
void PreemptiveThreadDemo::run() {
|
void PreemptiveThreadDemo::run() {
|
||||||
kout << "Preemptive Thread Demo" << endl;
|
kout << "Preemptive Thread Demo" << endl;
|
||||||
Thread* threads[this->number_of_threads];
|
|
||||||
kout << "Allocating LoopThreads" << endl;
|
|
||||||
for (unsigned int i = 0; i < this->number_of_threads; ++i) {
|
|
||||||
threads[i] = new PreemptiveLoopThread(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
kout << "Adding threads to ready queue" << endl;
|
kout << "Readying LoopThreads" << endl;
|
||||||
for (unsigned int i = 0; i < this->number_of_threads; ++i) {
|
for (unsigned int i = 0; i < this->number_of_threads; ++i) {
|
||||||
scheduler.ready(threads[i]);
|
threads.push_back(scheduler.ready<PreemptiveLoopThread>(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
kout << "Exiting main thread" << endl;
|
kout << "Exiting main thread" << endl;
|
||||||
|
while (listener.waitForKeyEvent() != 'L') {}
|
||||||
scheduler.exit();
|
scheduler.exit();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,20 @@ private:
|
|||||||
PreemptiveThreadDemo(const PreemptiveThreadDemo& copy) = delete; // Verhindere Kopieren
|
PreemptiveThreadDemo(const PreemptiveThreadDemo& copy) = delete; // Verhindere Kopieren
|
||||||
|
|
||||||
unsigned int number_of_threads;
|
unsigned int number_of_threads;
|
||||||
|
bse::Vector<unsigned int> threads;
|
||||||
|
KeyEventListener listener;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PreemptiveThreadDemo(unsigned int n) : number_of_threads(n) {
|
PreemptiveThreadDemo(unsigned int n) : number_of_threads(n), listener(this->tid) {
|
||||||
kout << "Initialized PreemptiveThreadDemo" << endl;
|
kout << "Initialized PreemptiveThreadDemo" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~PreemptiveThreadDemo() override {
|
||||||
|
for (unsigned int tid : threads) {
|
||||||
|
scheduler.kill(tid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Thread-Startmethode
|
// Thread-Startmethode
|
||||||
void run() override;
|
void run() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,9 +10,9 @@ private:
|
|||||||
char lastChar = '\0';
|
char lastChar = '\0';
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thread& thread; // Thread which contains this listener, so the listener can block the thread
|
unsigned int tid; // Thread which contains this listener, so the listener can block the thread
|
||||||
|
|
||||||
KeyEventListener(Thread& thread) : thread(thread) {}
|
KeyEventListener(unsigned int tid) : tid(tid) {}
|
||||||
|
|
||||||
char waitForKeyEvent() const; // Blocks the thread until woken up by manager
|
char waitForKeyEvent() const; // Blocks the thread until woken up by manager
|
||||||
void trigger(char c); // Gets called from KeyEventManager
|
void trigger(char c); // Gets called from KeyEventManager
|
||||||
|
|||||||
@ -1,21 +1,26 @@
|
|||||||
#include "user/event/KeyEventManager.h"
|
#include "user/event/KeyEventManager.h"
|
||||||
#include "kernel/Globals.h"
|
#include "kernel/Globals.h"
|
||||||
|
|
||||||
void KeyEventManager::subscribe(KeyEventListener& listener) {
|
void KeyEventManager::subscribe(KeyEventListener& sub) {
|
||||||
log << DEBUG << "Subscribe, Thread ID: " << dec << listener.thread.tid << endl;
|
log << DEBUG << "Subscribe, Thread ID: " << dec << sub.tid << endl;
|
||||||
this->listeners.insert_last(&listener);
|
this->listeners.push_back(&sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyEventManager::unsubscribe(KeyEventListener& listener) {
|
void KeyEventManager::unsubscribe(KeyEventListener& unsub) {
|
||||||
log << DEBUG << "Unsubscribe, Thread ID: " << dec << listener.thread.tid << endl;
|
log << DEBUG << "Unsubscribe, Thread ID: " << dec << unsub.tid << endl;
|
||||||
this->listeners.remove(&listener);
|
for (bse::Vector<KeyEventListener*>::Iterator it = listeners.begin(); it != listeners.end(); ++it) {
|
||||||
|
if ((*it)->tid == unsub.tid) {
|
||||||
|
this->listeners.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyEventManager::broadcast(char c) {
|
void KeyEventManager::broadcast(char c) {
|
||||||
log << TRACE << "Beginning Broadcast" << endl;
|
log << TRACE << "Beginning Broadcast" << endl;
|
||||||
for (KeyEventListener* listener : this->listeners) {
|
for (KeyEventListener* listener : this->listeners) {
|
||||||
log << TRACE << "Broadcasting " << c << " to Thread ID: " << dec << listener->thread.tid << endl;
|
log << TRACE << "Broadcasting " << c << " to Thread ID: " << dec << listener->tid << endl;
|
||||||
listener->trigger(c);
|
listener->trigger(c);
|
||||||
scheduler.deblock(&listener->thread);
|
scheduler.deblock(listener->tid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
KeyEventManager() : log("KEvMan") {}
|
KeyEventManager() : log("KEvMan") {}
|
||||||
|
|
||||||
void subscribe(KeyEventListener& listener);
|
void subscribe(KeyEventListener& sub);
|
||||||
void unsubscribe(KeyEventListener& listener);
|
void unsubscribe(KeyEventListener& unsub);
|
||||||
void broadcast(char c); // Unblocks all input waiting threads, I don't have a method to direct input
|
void broadcast(char c); // Unblocks all input waiting threads, I don't have a method to direct input
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user