Namespace classes
This commit is contained in:
@ -1,40 +0,0 @@
|
||||
#include "ArrayDemo.h"
|
||||
|
||||
void ArrayDemo::run() {
|
||||
bse::array<int, 10> arr1 {};
|
||||
bse::array<int, 10> arr2 {};
|
||||
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
|
||||
kout << "Adding..." << endl;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
arr1[i] = i;
|
||||
}
|
||||
|
||||
kout << "Iterator printing arr1:" << endl;
|
||||
for (int i : arr1) {
|
||||
kout << i << " ";
|
||||
}
|
||||
kout << endl;
|
||||
|
||||
kout << "Swapping arr1 and arr2..." << endl;
|
||||
arr1.swap(arr2);
|
||||
|
||||
kout << "Iterator printing arr1:" << endl;
|
||||
for (int i : arr1) {
|
||||
kout << i << " ";
|
||||
}
|
||||
kout << endl;
|
||||
|
||||
kout << "Iterator printing arr2:" << endl;
|
||||
for (int i : arr2) {
|
||||
kout << i << " ";
|
||||
}
|
||||
kout << endl;
|
||||
|
||||
// arr1.swap(arr3); // Not possible as type/size has to match
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
#ifndef ArrayDemo_include__
|
||||
#define ArrayDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "lib/util/Array.h"
|
||||
|
||||
class ArrayDemo : public Thread {
|
||||
public:
|
||||
ArrayDemo(const ArrayDemo& copy) = delete;
|
||||
|
||||
ArrayDemo() : Thread("ArrayDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,78 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* H E A P D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Demonstration der dynamischen Speicherverwaltung. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 27.12.2016 *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "HeapDemo.h"
|
||||
|
||||
void HeapDemo::run() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "HEAP_DEMO ===================================================================" << endl;
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
allocator.dump_free_memory();
|
||||
|
||||
// Rounding to word border
|
||||
kout << "ROUNDING ====================================================================" << endl;
|
||||
void* alloc = allocator.alloc(1); // 1 Byte
|
||||
allocator.dump_free_memory();
|
||||
allocator.free(alloc);
|
||||
allocator.dump_free_memory();
|
||||
|
||||
// Some objects and forward/backward merging
|
||||
kout << "SOME OBJECTS ================================================================" << endl;
|
||||
MyObj* a = new MyObj(5);
|
||||
allocator.dump_free_memory();
|
||||
MyObj* b = new MyObj(10);
|
||||
allocator.dump_free_memory();
|
||||
MyObj* c = new MyObj(15);
|
||||
allocator.dump_free_memory();
|
||||
delete b; // No merge
|
||||
allocator.dump_free_memory();
|
||||
delete a; // Merge forward BUG: Bluescreen
|
||||
allocator.dump_free_memory();
|
||||
delete c;
|
||||
allocator.dump_free_memory();
|
||||
|
||||
// Allocate too whole heap
|
||||
// void* ptr = allocator.alloc(1024 * 1024 - 24);
|
||||
// allocator.dump_free_memory();
|
||||
// allocator.free(ptr);
|
||||
// allocator.dump_free_memory();
|
||||
|
||||
// Allocate too much
|
||||
kout << "TOO MUCH ====================================================================" << endl;
|
||||
allocator.alloc(1024 * 1024); // should fail as only 1024 * 1024 - Headersize bytes are available
|
||||
allocator.dump_free_memory();
|
||||
|
||||
// A lot of allocations
|
||||
// MyObj* objs[1024];
|
||||
// for (unsigned int i = 0; i < 1024; ++i) {
|
||||
// objs[i] = new MyObj(5);
|
||||
// }
|
||||
// allocator.dump_free_memory();
|
||||
// waitForReturn();
|
||||
// for (unsigned int i = 0; i < 1024; ++i) {
|
||||
// delete objs[i];
|
||||
// }
|
||||
// allocator.dump_free_memory();
|
||||
|
||||
// Array allocation
|
||||
kout << "ARRAY =======================================================================" << endl;
|
||||
MyObj* objs = new MyObj[1024];
|
||||
allocator.dump_free_memory();
|
||||
delete[] objs;
|
||||
allocator.dump_free_memory();
|
||||
|
||||
kout << "HEAP_DEMO END ===============================================================" << endl;
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* H E A P D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Demonstration der dynamischen Speicherverwaltung. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 25.9.2016 *
|
||||
*****************************************************************************/
|
||||
#ifndef HeapDemo_include__
|
||||
#define HeapDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
|
||||
class MyObj {
|
||||
public:
|
||||
constexpr MyObj() : value(5) {};
|
||||
constexpr MyObj(const unsigned int val) : value(val) {};
|
||||
const unsigned int value;
|
||||
};
|
||||
|
||||
class HeapDemo : public Thread {
|
||||
public:
|
||||
HeapDemo(const HeapDemo& copy) = delete;
|
||||
|
||||
HeapDemo() : Thread("HeapDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,34 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* K E Y B O A R D D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Testausgaben für den CGA-Treiber. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.10.2018 *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "KeyboardDemo.h"
|
||||
|
||||
void KeyboardDemo::run() {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
kout << "Keyboard Demo: " << endl;
|
||||
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "Info: Die Keyboard Demo sperrt den Output Stream:\n"
|
||||
<< " Wenn die Preemption Demo laeuft wird diese also erst\n"
|
||||
<< " fortfahren wenn die Keyboard Demo wieder beendet ist." << endl;
|
||||
kout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nInput: ";
|
||||
kout.flush();
|
||||
|
||||
while (running) {
|
||||
kout << listener.waitForKeyEvent();
|
||||
kout.flush();
|
||||
}
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* K E Y B O A R D D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Testausgaben für den CGA-Treiber. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.10.2018 *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef KeyboardDemo_include__
|
||||
#define KeyboardDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
#include "kernel/event/KeyEventListener.h"
|
||||
|
||||
class KeyboardDemo : public Thread {
|
||||
private:
|
||||
KeyEventListener listener;
|
||||
|
||||
public:
|
||||
KeyboardDemo(const KeyboardDemo& copy) = delete;
|
||||
|
||||
KeyboardDemo() : Thread("KeyboardDemo"), listener(tid) {
|
||||
kevman.subscribe(listener);
|
||||
}
|
||||
|
||||
// Base class destructor will be called automatically
|
||||
~KeyboardDemo() override {
|
||||
if (running) {
|
||||
// NOTE: If the thread was exited nicely it can unlock before destructor,
|
||||
// but on forced kill kout has to be unlocked in the destructor.
|
||||
// This is bad since it could release the lock although some other
|
||||
// thread set it (so use nice_kill)
|
||||
kout.unlock();
|
||||
}
|
||||
kevman.unsubscribe(listener);
|
||||
}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,90 +0,0 @@
|
||||
#include "MainMenu.h"
|
||||
#include "ArrayDemo.h"
|
||||
#include "HeapDemo.h"
|
||||
#include "KeyboardDemo.h"
|
||||
#include "PagingDemo.h"
|
||||
#include "PCSPKdemo.h"
|
||||
#include "PreemptiveThreadDemo.h"
|
||||
#include "SmartPointerDemo.h"
|
||||
#include "StringDemo.h"
|
||||
#include "TextDemo.h"
|
||||
#include "VBEdemo.h"
|
||||
#include "VectorDemo.h"
|
||||
|
||||
void print_demo_menu() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "Demo Menu, press number to start, k/K to kill:\n"
|
||||
<< "1 - Text Demo\n"
|
||||
<< "2 - PCSPK Demo\n"
|
||||
<< "3 - Keyboard Demo\n"
|
||||
<< "4 - Heap Demo\n"
|
||||
<< "5 - VBE Demo\n"
|
||||
<< "6 - Paging Demo\n"
|
||||
<< "7 - Preemption Demo\n"
|
||||
<< "Extra demos:\n"
|
||||
<< "8 - bse::vector demo\n"
|
||||
<< "9 - bse::array demo\n"
|
||||
<< "0 - bse::unique_ptr demo\n"
|
||||
<< "! - bse::string demo\n"
|
||||
<< endl;
|
||||
kout.unlock();
|
||||
}
|
||||
|
||||
void MainMenu::run() {
|
||||
print_demo_menu();
|
||||
|
||||
char input = '\0';
|
||||
unsigned int running_demo = 0;
|
||||
while (running) {
|
||||
input = listener.waitForKeyEvent();
|
||||
|
||||
if ((input >= '0' && input <= '9') || input == '!') {
|
||||
switch (input) {
|
||||
case '1':
|
||||
running_demo = scheduler.ready<TextDemo>();
|
||||
break;
|
||||
case '2':
|
||||
running_demo = scheduler.ready<PCSPKdemo>(&PCSPK::aerodynamic);
|
||||
break;
|
||||
case '3':
|
||||
running_demo = scheduler.ready<KeyboardDemo>();
|
||||
break;
|
||||
case '4':
|
||||
running_demo = scheduler.ready<HeapDemo>();
|
||||
break;
|
||||
case '5':
|
||||
running_demo = scheduler.ready<VBEdemo>();
|
||||
break;
|
||||
case '6':
|
||||
running_demo = scheduler.ready<PagingDemo>();
|
||||
break;
|
||||
case '7':
|
||||
running_demo = scheduler.ready<PreemptiveThreadDemo>(3);
|
||||
break;
|
||||
|
||||
case '8':
|
||||
running_demo = scheduler.ready<VectorDemo>();
|
||||
break;
|
||||
case '9':
|
||||
running_demo = scheduler.ready<ArrayDemo>();
|
||||
break;
|
||||
case '0':
|
||||
running_demo = scheduler.ready<SmartPointerDemo>();
|
||||
break;
|
||||
case '!':
|
||||
running_demo = scheduler.ready<StringDemo>();
|
||||
break;
|
||||
}
|
||||
} else if (input == 'k') {
|
||||
scheduler.nice_kill(running_demo); // NOTE: If thread exits itself this will throw error
|
||||
print_demo_menu();
|
||||
} else if (input == 'K') {
|
||||
scheduler.kill(running_demo);
|
||||
print_demo_menu();
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.exit();
|
||||
// This thread won't be deleted...
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
#ifndef MainMenu_Inlucde_H_
|
||||
#define MainMenu_Inlucde_H_
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
#include "kernel/event/KeyEventListener.h"
|
||||
|
||||
class MainMenu : public Thread {
|
||||
private:
|
||||
KeyEventListener listener;
|
||||
|
||||
public:
|
||||
MainMenu(const MainMenu& copy) = delete;
|
||||
|
||||
MainMenu() : Thread("MainMenu"), listener(tid) {
|
||||
kevman.subscribe(listener);
|
||||
}
|
||||
|
||||
~MainMenu() override {
|
||||
kevman.unsubscribe(listener);
|
||||
}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,16 +0,0 @@
|
||||
#include "PCSPKdemo.h"
|
||||
|
||||
void PCSPKdemo::run() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "Playing..." << endl;
|
||||
kout.unlock();
|
||||
|
||||
(*melody)(); // This syntax is confusing as hell
|
||||
|
||||
kout.lock();
|
||||
kout << "Finished" << endl;
|
||||
kout.unlock();
|
||||
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef PCSPKdemo_INCLUDE_H_
|
||||
#define PCSPKdemo_INCLUDE_H_
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
|
||||
class PCSPKdemo : public Thread {
|
||||
private:
|
||||
void (*melody)(); // Allow to pass a melody to play when initializing the demo
|
||||
|
||||
public:
|
||||
PCSPKdemo(const PCSPKdemo& copy) = delete;
|
||||
|
||||
PCSPKdemo(void (*melody)()) : Thread("PCSPKdemo"), melody(melody) {}
|
||||
|
||||
~PCSPKdemo() override {
|
||||
PCSPK::off();
|
||||
}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,50 +0,0 @@
|
||||
#include "PagingDemo.h"
|
||||
|
||||
void PagingDemo::writeprotect_page() {
|
||||
kout << "Accessing a writeprotected page triggers bluescreen,\nif you can read this it didn't work" << endl;
|
||||
|
||||
// BlueScreen 1
|
||||
// asm("int $3");
|
||||
|
||||
// BlueScreen 2
|
||||
log.info() << "Allocating page" << endl;
|
||||
uint32_t* page = pg_alloc_page();
|
||||
*page = 42;
|
||||
log.info() << "Writeprotecting page..." << endl;
|
||||
pg_write_protect_page(page);
|
||||
|
||||
log.info() << "Accessing writeprotected page" << endl;
|
||||
*page = 42; // We map logical to physical 1:1 so no need to do any lookup
|
||||
|
||||
// No free because bluescreen
|
||||
}
|
||||
|
||||
void PagingDemo::notpresent_page() {
|
||||
kout << "Produces pagefault, if you can read this it didn't work" << endl;
|
||||
|
||||
log.info() << "Allocating page" << endl;
|
||||
uint32_t* page = pg_alloc_page();
|
||||
*page = 42;
|
||||
|
||||
log.info() << "Marking page notpresent..." << endl;
|
||||
pg_notpresent_page(page);
|
||||
|
||||
log.info() << "Accessing page" << endl;
|
||||
kout << "Page not accessible: " << *page << endl;
|
||||
|
||||
// No free because bluescreen
|
||||
}
|
||||
|
||||
void PagingDemo::run() {
|
||||
kout << "Press w for writeprotect demo, n for notpresent demo" << endl;
|
||||
switch(listener.waitForKeyEvent()) {
|
||||
case 'w':
|
||||
writeprotect_page();
|
||||
break;
|
||||
case 'n':
|
||||
notpresent_page();
|
||||
break;
|
||||
}
|
||||
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
#ifndef BlueScreenDemo_include__
|
||||
#define BlueScreenDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
#include "kernel/event/KeyEventListener.h"
|
||||
|
||||
class PagingDemo: public Thread {
|
||||
private:
|
||||
void writeprotect_page();
|
||||
void free_page();
|
||||
void notpresent_page();
|
||||
|
||||
KeyEventListener listener;
|
||||
|
||||
public:
|
||||
PagingDemo(const PagingDemo& copy) = delete;
|
||||
|
||||
PagingDemo(): Thread("PagingDemo"), listener(tid) {
|
||||
kevman.subscribe(listener);
|
||||
}
|
||||
|
||||
~PagingDemo() override {
|
||||
kevman.unsubscribe(listener);
|
||||
}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,34 +0,0 @@
|
||||
#include "PreemptiveThreadDemo.h"
|
||||
|
||||
void PreemptiveLoopThread::run() {
|
||||
int cnt = 0;
|
||||
|
||||
while (running) {
|
||||
// Basic synchronization by semaphore
|
||||
kout.lock();
|
||||
|
||||
// Saving + restoring kout position doesn't help much as preemption still occurs
|
||||
CGA_Stream::setpos(55, id);
|
||||
kout << fillw(3) << id << fillw(0) << ": " << dec << cnt++ << endl;
|
||||
|
||||
kout.unlock();
|
||||
}
|
||||
|
||||
scheduler.exit();
|
||||
}
|
||||
|
||||
void PreemptiveThreadDemo::run() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
|
||||
kout << "Preemptive Thread Demo:" << endl;
|
||||
|
||||
kout << "Readying LoopThreads" << endl;
|
||||
for (unsigned int i = 0; i < number_of_threads; ++i) {
|
||||
scheduler.ready<PreemptiveLoopThread>(i);
|
||||
}
|
||||
|
||||
kout << "Exiting main thread" << endl;
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
#ifndef preemptive_thread_include__
|
||||
#define preemptive_thread_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
#include "lib/async/Semaphore.h"
|
||||
|
||||
class PreemptiveLoopThread : public Thread {
|
||||
private:
|
||||
int id;
|
||||
|
||||
public:
|
||||
PreemptiveLoopThread(const PreemptiveLoopThread& copy) = delete; // Verhindere Kopieren
|
||||
|
||||
// Gibt der Loop einen Stack und eine Id.
|
||||
PreemptiveLoopThread(int i) : Thread("LoopThread"), id(i) {}
|
||||
|
||||
// Zaehlt einen Zaehler hoch und gibt ihn auf dem Bildschirm aus.
|
||||
void run() override;
|
||||
};
|
||||
|
||||
class PreemptiveThreadDemo : public Thread {
|
||||
private:
|
||||
unsigned int number_of_threads;
|
||||
|
||||
public:
|
||||
PreemptiveThreadDemo(const PreemptiveThreadDemo& copy) = delete; // Verhindere Kopieren
|
||||
|
||||
PreemptiveThreadDemo(unsigned int n) : Thread("PreemptiveThreadDemo"), number_of_threads(n) {}
|
||||
|
||||
// Thread-Startmethode
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,122 +0,0 @@
|
||||
#include "SmartPointerDemo.h"
|
||||
#include "kernel/process/IdleThread.h"
|
||||
|
||||
void SmartPointerDemo::run() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
|
||||
kout << "Output is written to log to be able to trace memory allocations/deallocations" << endl;
|
||||
|
||||
{
|
||||
log.info() << "Allocating new unique_ptr<int>..." << endl;
|
||||
bse::unique_ptr<int> ptr = bse::make_unique<int>(1);
|
||||
log.info() << "Leaving scope..." << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "Allocating new unique_ptr<int>..." << endl;
|
||||
bse::unique_ptr<int> ptr1 = bse::make_unique<int>(1);
|
||||
bse::unique_ptr<int> ptr2;
|
||||
|
||||
log.info() << "*ptr1 == " << *ptr1 << ", (bool)ptr2 == " << static_cast<bool>(ptr2) << endl;
|
||||
log.info() << "Moving ptr1 => ptr2 (no allocations should happen)..." << endl;
|
||||
ptr2 = std::move(ptr1);
|
||||
log.info() << "(bool)ptr1 == " << static_cast<bool>(ptr1) << ", *ptr2 == " << *ptr2 << endl;
|
||||
|
||||
log.info() << "Leaving scope..." << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "Allocating (2) new unique_ptr<int>..." << endl;
|
||||
bse::unique_ptr<int> ptr1 = bse::make_unique<int>(1);
|
||||
bse::unique_ptr<int> ptr2 = bse::make_unique<int>(1);
|
||||
|
||||
log.info() << "Moving ptr1 => ptr2 (ptr1 should be freed)..." << endl;
|
||||
ptr2 = std::move(ptr1);
|
||||
|
||||
log.info() << "Leaving scope..." << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
// =====================================================================
|
||||
|
||||
{
|
||||
log.info() << "Allocating new unique_ptr<int[]>..." << endl;
|
||||
bse::unique_ptr<int[]> ptr = bse::make_unique<int[]>(10);
|
||||
ptr[0] = 1;
|
||||
log.info() << "ptr[0] == " << ptr[0] << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "Allocating new unique_ptr<int[10]>..." << endl;
|
||||
bse::unique_ptr<int[]> ptr1 = bse::make_unique<int[]>(10);
|
||||
bse::unique_ptr<int[]> ptr2;
|
||||
|
||||
log.info() << "Moving ptr1 => ptr2 (no allocations should happen)..." << endl;
|
||||
ptr2 = std::move(ptr1);
|
||||
|
||||
log.info() << "Leaving scope..." << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "Allocating (2) new unique_ptr<int[10]>..." << endl;
|
||||
bse::unique_ptr<int> ptr1 = bse::make_unique<int>(10);
|
||||
bse::unique_ptr<int> ptr2 = bse::make_unique<int>(10);
|
||||
|
||||
log.info() << "Moving ptr1 => ptr2 (ptr1 should be freed)..." << endl;
|
||||
ptr2 = std::move(ptr1);
|
||||
|
||||
log.info() << "Leaving scope..." << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
// NOTE: This wasn't working because of a missing operator[] delete in the allocator
|
||||
log.info() << "Allocating unique_ptr<int>*..." << endl;
|
||||
bse::unique_ptr<int>* ptrptr = new bse::unique_ptr<int>[10];
|
||||
delete[] ptrptr;
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
// =====================================================================
|
||||
|
||||
{
|
||||
log.info() << "Stackallocating Array<bse::unique_ptr<int>, 10>..." << endl;
|
||||
bse::array<bse::unique_ptr<int>, 10> arr;
|
||||
log.info() << "Populating slot 0..." << endl;
|
||||
arr[0] = bse::make_unique<int>(1);
|
||||
log.info() << "Moving slot 0 to slot 1..." << endl;
|
||||
arr[1] = std::move(arr[0]);
|
||||
log.info() << "Leaving scope" << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "Heapallocating Array<bse::unique_ptr<int>, 10>..." << endl;
|
||||
bse::array<bse::unique_ptr<int>, 10>* arr = new bse::array<bse::unique_ptr<int>, 10>;
|
||||
log.info() << "Populating slot 0..." << endl;
|
||||
(*arr)[0] = bse::make_unique<int>(1);
|
||||
log.info() << "Moving slot 0 to slot 1..." << endl;
|
||||
(*arr)[1] = std::move((*arr)[0]);
|
||||
log.info() << "Deleting" << endl;
|
||||
delete arr;
|
||||
log.info() << "Leaving scope" << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
{
|
||||
log.info() << "ArrayList<bse::unique_ptr<int>>..." << endl;
|
||||
bse::vector<bse::unique_ptr<int>> vec;
|
||||
log.info() << "2x insertion" << endl;
|
||||
vec.push_back(bse::make_unique<int>(1));
|
||||
vec.push_back(bse::make_unique<int>(2));
|
||||
|
||||
log.info() << "Leaving scope" << endl;
|
||||
}
|
||||
log.info() << "Should be deleted by now..." << endl;
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
#ifndef SmartPointerDemo_include__
|
||||
#define SmartPointerDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
class SmartPointerDemo : public Thread {
|
||||
public:
|
||||
SmartPointerDemo(const SmartPointerDemo& copy) = delete;
|
||||
|
||||
SmartPointerDemo() : Thread("SmartPointerDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,56 +0,0 @@
|
||||
#include "StringDemo.h"
|
||||
|
||||
void StringDemo::run() {
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
|
||||
log.info() << "Allocating new string" << endl;
|
||||
bse::string str1 = "This is a dynamically allocated string!";
|
||||
kout << str1 << endl;
|
||||
|
||||
log.info() << "Reassign string" << endl;
|
||||
str1 = "Hello";
|
||||
kout << str1 << " has length " << dec << str1.size() << endl;
|
||||
kout << "Again with strlen: Hello has length " << dec << bse::strlen("Hello") << endl;
|
||||
|
||||
kout << "Adding strings: " << str1 << " + World" << endl;
|
||||
log.info() << "Adding strings" << endl;
|
||||
str1 = str1 + " World";
|
||||
kout << str1 << endl;
|
||||
|
||||
kout << "Hello += World" << endl;
|
||||
log.info() << "Hello += World" << endl;
|
||||
bse::string str3 = "Hello";
|
||||
str3 += " World";
|
||||
kout << str3 << endl;
|
||||
|
||||
kout << "Hello World *= 3" << endl;
|
||||
str3 *= 3;
|
||||
kout << str3 << endl;
|
||||
|
||||
kout << "String iterator!" << endl;
|
||||
for (const char c : str1) {
|
||||
kout << c << " ";
|
||||
}
|
||||
kout << endl;
|
||||
|
||||
log.info() << "Allocating new string" << endl;
|
||||
bse::string str2 = "Hello World";
|
||||
kout << "str1 == str2: " << static_cast<int>(str1 == str2) << endl;
|
||||
kout << "strcmp(Hello, Hello): " << bse::strcmp("Hello", "Hello") << endl;
|
||||
|
||||
log.info() << "Reassign str2" << endl;
|
||||
str2 = "Hello";
|
||||
|
||||
bse::array<char, 5> arr{};
|
||||
arr[0] = 'H';
|
||||
arr[1] = 'e';
|
||||
arr[2] = 'l';
|
||||
arr[3] = 'l';
|
||||
arr[4] = 'o';
|
||||
kout << "bse::array<char, 5> to bse::string: " << static_cast<bse::string>(arr) << ", size: " << (bse::string(arr)).size() << endl;
|
||||
kout << "(bse::string)arr (" << static_cast<bse::string>(arr) << ") == str2 (" << str2 << "): " << static_cast<int>(bse::string(arr) == str2) << endl;
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
#ifndef StringDemo_include__
|
||||
#define StringDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
class StringDemo : public Thread {
|
||||
public:
|
||||
StringDemo(const StringDemo& copy) = delete;
|
||||
|
||||
StringDemo() : Thread("StringDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,43 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* T E X T D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Testausgaben für den CGA-Treiber. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.10.2018 *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "TextDemo.h"
|
||||
|
||||
void TextDemo::run() {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "TextDemo\n"
|
||||
<< endl;
|
||||
|
||||
kout << "Attribut (GREEN on WHITE): "
|
||||
<< bgc(CGA::WHITE) << green << "GREEN on WHITE" << endl
|
||||
<< "Attribut (WHITE on BLACK): "
|
||||
<< bgc(CGA::BLACK) << white << "WHITE on BLACK" << endl;
|
||||
kout << endl;
|
||||
|
||||
kout << "Test der Zahlenausgabefunktion:" << endl
|
||||
<< "| dec | hex | bin |" << endl
|
||||
<< "+-------+-------+-------+" << endl;
|
||||
|
||||
for (uint16_t num = 0; num < 17; ++num) {
|
||||
kout << fillw(0) << "| " << fillw(6) << dec << num
|
||||
<< fillw(0) << "| " << fillw(6) << hex << num
|
||||
<< fillw(0) << "| " << fillw(6) << bin << num
|
||||
<< fillw(0) << "|" << endl;
|
||||
}
|
||||
|
||||
kout << endl;
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* T E X T D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Testausgaben für den CGA-Treiber. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.10.2018 *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TextDemo_include__
|
||||
#define TextDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
|
||||
class TextDemo : public Thread {
|
||||
public:
|
||||
TextDemo(const TextDemo& copy) = delete;
|
||||
|
||||
TextDemo() : Thread("TextDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,106 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* V B E D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Demo zu VESA. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.12.2016 *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "VBEdemo.h"
|
||||
#include "bmp_hhu.cc"
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::linInterPol1D *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Farbwert in einer Dimension interpoliert berechnen. *
|
||||
*****************************************************************************/
|
||||
int VBEdemo::linInterPol1D(int x, int xr, int l, int r) {
|
||||
return ((((l >> 16) * (xr - x) + (r >> 16) * x) / xr) << 16) | (((((l >> 8) & 0xFF) * (xr - x) + ((r >> 8) & 0xFF) * x) / xr) << 8) | (((l & 0xFF) * (xr - x) + (r & 0xFF) * x) / xr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::linInterPol2D *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Farbwert in zwei Dimensionen interpoliert berechnen. *
|
||||
*****************************************************************************/
|
||||
int VBEdemo::linInterPol2D(int x, int y, int lt, int rt, int lb, int rb) {
|
||||
return linInterPol1D(y, vesa.yres,
|
||||
linInterPol1D(x, vesa.xres, lt, rt),
|
||||
linInterPol1D(x, vesa.xres, lb, rb));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::drawColors *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Pixel-Demo. *
|
||||
*****************************************************************************/
|
||||
void VBEdemo::drawColors() {
|
||||
int x_res = 640;
|
||||
int y_res = 480;
|
||||
|
||||
for (int y = 0; y < y_res; y++) {
|
||||
for (int x = 0; x < x_res; x++) {
|
||||
vesa.drawPixel(x, y, linInterPol2D(x, y, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::drawBitmap *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Bitmap aus GIMP ausgeben. *
|
||||
*****************************************************************************/
|
||||
void VBEdemo::drawBitmap() {
|
||||
unsigned int sprite_width = hhu.width;
|
||||
unsigned int sprite_height = hhu.height;
|
||||
unsigned int sprite_bpp = hhu.bytes_per_pixel;
|
||||
const uint8_t* sprite_pixel = reinterpret_cast<const uint8_t*>(hhu.pixel_data);
|
||||
|
||||
/* Hier muss Code eingefuegt werden */
|
||||
|
||||
vesa.drawSprite(sprite_width, sprite_height, sprite_bpp, sprite_pixel);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::drawFonts *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Fonts ausgeben. *
|
||||
*****************************************************************************/
|
||||
void VBEdemo::drawFonts() {
|
||||
|
||||
/* Hier muss Code eingefuegt werden */
|
||||
|
||||
vesa.drawString(std_font_8x8, 0, 300, 0, "STD FONT 8x8", 12);
|
||||
vesa.drawString(std_font_8x16, 0, 320, 0, "STD FONT 8x16", 13);
|
||||
vesa.drawString(acorn_font_8x8, 0, 340, 0, "ACORN FONT 8x8", 14);
|
||||
vesa.drawString(sun_font_8x16, 0, 360, 0, "SUN FONT 8x16", 13);
|
||||
vesa.drawString(sun_font_12x22, 0, 380, 0, "SUN FONT 12x22", 14);
|
||||
vesa.drawString(pearl_font_8x8, 0, 400, 0, "PEARL FONT 8x8", 14);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: VBEdemo::run *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Der Anwendungsthread erzeugt drei Threads die Zaehler *
|
||||
* ausgeben und terminiert sich selbst. *
|
||||
*****************************************************************************/
|
||||
void VBEdemo::run() {
|
||||
|
||||
// In den Grafikmodus schalten (32-Bit Farbtiefe)
|
||||
vesa.initGraphicMode(MODE_640_480_24BITS);
|
||||
vesa.setDrawingBuff(BUFFER_VISIBLE);
|
||||
|
||||
drawColors();
|
||||
|
||||
/* Hier muss Code eingefuegt werden */
|
||||
vesa.drawRectangle(100, 100, 300, 300, 0);
|
||||
drawBitmap();
|
||||
drawFonts();
|
||||
|
||||
while (running) {}
|
||||
|
||||
// selbst terminieren
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* V B E D E M O *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Demo zu VESA. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, HHU, 26.12.2016 *
|
||||
*****************************************************************************/
|
||||
#ifndef VBEdemo_include__
|
||||
#define VBEdemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
|
||||
class VBEdemo : public Thread {
|
||||
private:
|
||||
// Hilfsfunktionen fuer drawColors()
|
||||
static int linInterPol1D(int x, int xr, int l, int r);
|
||||
static int linInterPol2D(int x, int y, int lt, int rt, int lb, int rb);
|
||||
|
||||
public:
|
||||
VBEdemo(const VBEdemo& copy) = delete; // Verhindere Kopieren
|
||||
|
||||
// Gib dem Anwendungsthread einen Stack.
|
||||
VBEdemo() : Thread("VBEdemo") {}
|
||||
|
||||
~VBEdemo() override {
|
||||
allocator.free(reinterpret_cast<void*>(vesa.hfb)); // Memory is allocated after every start and never deleted, so add that
|
||||
VESA::initTextMode();
|
||||
}
|
||||
|
||||
// Thread-Startmethode
|
||||
void run() override;
|
||||
|
||||
// Farbraum ausgeben
|
||||
void drawColors();
|
||||
|
||||
// Bitmap aus GIMP ausgeben
|
||||
static void drawBitmap();
|
||||
|
||||
// Fonts ausgeben
|
||||
static void drawFonts();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,110 +0,0 @@
|
||||
#include "VectorDemo.h"
|
||||
|
||||
void print(OutStream& os, const bse::vector<int>& list) {
|
||||
os << "Printing List: ";
|
||||
for (const int i : list) {
|
||||
os << i << " ";
|
||||
}
|
||||
os << endl;
|
||||
}
|
||||
|
||||
void VectorDemo::run() {
|
||||
bse::vector<int> list;
|
||||
|
||||
kout.lock();
|
||||
kout.clear();
|
||||
kout << "Logs are written to serial to see the memory interactions" << endl;
|
||||
|
||||
log.info() << "Initial list size: " << dec << list.size() << endl;
|
||||
|
||||
log.info() << "Adding elements in order" << endl;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
list.push_back(i);
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
log.info() << "Removing all elements from the front" << endl;
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
list.erase(list.begin());
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
// ============================================================
|
||||
|
||||
log.info() << "Adding elements in order with realloc" << endl;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
log.info() << "Add " << dec << i << endl;
|
||||
list.push_back(i);
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
log.info() << "Removing all elements from the back" << endl;
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
list.erase(list.end() - 1);
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
// ============================================================
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
list.push_back(i);
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
log.info() << "Adding inside the list (at idx 0, 2, 5)" << endl;
|
||||
list.insert(list.begin() + 0, 10);
|
||||
list.insert(list.begin() + 2, 10);
|
||||
list.insert(list.begin() + 5, 10);
|
||||
print(log.info(), list);
|
||||
|
||||
log.info() << "Removing inside the list (at idx 0, 2, 5)" << endl;
|
||||
list.erase(list.begin() + 0);
|
||||
list.erase(list.begin() + 2);
|
||||
list.erase(list.begin() + 5);
|
||||
print(log.info(), list);
|
||||
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
list.erase(list.begin());
|
||||
}
|
||||
print(log.info(), list);
|
||||
|
||||
// ============================================================
|
||||
|
||||
log.info() << "Mirror scheduling behavior" << endl;
|
||||
|
||||
// These are the threads
|
||||
int active = 0; // Idle thread
|
||||
list.push_back(1);
|
||||
list.push_back(2);
|
||||
list.push_back(3);
|
||||
print(log.info(), list);
|
||||
|
||||
log.info() << "Starting..." << endl;
|
||||
for (unsigned int n = 0; n < 10000; ++n) {
|
||||
list.push_back(active);
|
||||
active = list[0];
|
||||
list.erase(list.begin());
|
||||
|
||||
if (list.size() != 3 || active == -1) {
|
||||
log.info() << "ERROR: Thread went missing" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n < 5) {
|
||||
print(log.info(), list);
|
||||
}
|
||||
}
|
||||
log.info() << "Finished." << endl;
|
||||
|
||||
print(log.info(), list);
|
||||
|
||||
// ============================================================
|
||||
|
||||
log.info() << "Range based for support" << endl;
|
||||
for (int i : list) {
|
||||
log.info() << "List contains element: " << dec << i << endl;
|
||||
}
|
||||
|
||||
kout.unlock();
|
||||
scheduler.exit();
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
#ifndef VectorDemo_include__
|
||||
#define VectorDemo_include__
|
||||
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/process/Thread.h"
|
||||
#include "lib/util/Vector.h"
|
||||
|
||||
class VectorDemo : public Thread {
|
||||
public:
|
||||
VectorDemo(const VectorDemo& copy) = delete;
|
||||
|
||||
VectorDemo() : Thread("VectorDemo") {}
|
||||
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,8 @@
|
||||
#include "kernel/event/KeyEventListener.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void KeyEventListener::trigger(char c) {
|
||||
lastChar = c;
|
||||
}
|
||||
@ -10,3 +12,5 @@ char KeyEventListener::waitForKeyEvent() const {
|
||||
scheduler.block();
|
||||
return lastChar; // This is only executed after thread is woken up by manager
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,15 +3,18 @@
|
||||
|
||||
#include "kernel/process/Thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KeyEventListener {
|
||||
private:
|
||||
char lastChar = '\0';
|
||||
|
||||
friend class KeyEventManager;
|
||||
|
||||
unsigned int tid; // Thread which contains this listener, so the listener can block the thread
|
||||
|
||||
public:
|
||||
KeyEventListener(const KeyEventListener& copy) = delete;
|
||||
KeyEventListener(const KeyEventListener ©) = delete;
|
||||
|
||||
KeyEventListener(unsigned int tid) : tid(tid) {}
|
||||
|
||||
@ -19,4 +22,6 @@ public:
|
||||
void trigger(char c); // Gets called from KeyEventManager
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
#include "KeyEventManager.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
void KeyEventManager::subscribe(KeyEventListener& sub) {
|
||||
namespace Kernel {
|
||||
|
||||
void KeyEventManager::subscribe(KeyEventListener &sub) {
|
||||
log.debug() << "Subscribe, Thread ID: " << dec << sub.tid << endl;
|
||||
listeners.push_back(&sub);
|
||||
}
|
||||
|
||||
void KeyEventManager::unsubscribe(KeyEventListener& unsub) {
|
||||
void KeyEventManager::unsubscribe(KeyEventListener &unsub) {
|
||||
log.debug() << "Unsubscribe, Thread ID: " << dec << unsub.tid << endl;
|
||||
for (bse::vector<KeyEventListener*>::iterator it = listeners.begin(); it != listeners.end(); ++it) {
|
||||
for (Container::vector<KeyEventListener *>::iterator it = listeners.begin(); it != listeners.end(); ++it) {
|
||||
if ((*it)->tid == unsub.tid) {
|
||||
listeners.erase(it);
|
||||
return;
|
||||
@ -18,9 +20,11 @@ void KeyEventManager::unsubscribe(KeyEventListener& unsub) {
|
||||
|
||||
void KeyEventManager::broadcast(char c) {
|
||||
log.trace() << "Beginning Broadcast" << endl;
|
||||
for (KeyEventListener* listener : listeners) {
|
||||
for (KeyEventListener *listener: listeners) {
|
||||
log.trace() << "Broadcasting " << c << " to Thread ID: " << dec << listener->tid << endl;
|
||||
listener->trigger(c);
|
||||
scheduler.deblock(listener->tid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,20 +2,22 @@
|
||||
#define KeyEventManager_Include_H_
|
||||
|
||||
#include "kernel/event/KeyEventListener.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/util/Vector.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
#include "lib/container/Vector.h"
|
||||
|
||||
// NOTE: Could do this more generally but we only have key events
|
||||
// Also pretty limited: One thread can have one listener as identification is done over tid
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KeyEventManager {
|
||||
private:
|
||||
NamedLogger log;
|
||||
|
||||
bse::vector<KeyEventListener*> listeners;
|
||||
Container::vector<KeyEventListener *> listeners;
|
||||
|
||||
public:
|
||||
KeyEventManager(const KeyEventManager& copy) = delete;
|
||||
KeyEventManager(const KeyEventManager ©) = delete;
|
||||
|
||||
KeyEventManager() : log("KEvMan"), listeners(true) {}
|
||||
|
||||
@ -23,9 +25,13 @@ public:
|
||||
listeners.reserve();
|
||||
}
|
||||
|
||||
void subscribe(KeyEventListener& sub);
|
||||
void unsubscribe(KeyEventListener& unsub);
|
||||
void subscribe(KeyEventListener &sub);
|
||||
|
||||
void unsubscribe(KeyEventListener &unsub);
|
||||
|
||||
void broadcast(char c); // Unblocks all input waiting threads, I don't have a method to direct input
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
||||
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
||||
* kout etc. verwendet wird. *
|
||||
* Kernel::kout etc. verwendet wird. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, 11.12.2018 *
|
||||
*****************************************************************************/
|
||||
@ -13,39 +13,39 @@
|
||||
|
||||
// in startup.asm
|
||||
extern "C" {
|
||||
// CR2 auslesen
|
||||
uint32_t get_page_fault_address();
|
||||
// CR2 auslesen
|
||||
uint32_t get_page_fault_address();
|
||||
|
||||
// 1st level interrupt handler in startup.asm sichert Zeiger auf Stackframe
|
||||
// unmittelbar nach dem Interrupt und nachdem alle Register mit PUSHAD
|
||||
// gesichert wurden
|
||||
// |-------------|
|
||||
// | EFLAGS |
|
||||
// |-------------|
|
||||
// | CS |
|
||||
// |-------------|
|
||||
// | EIP |
|
||||
// |-------------|
|
||||
// | [ErrorCode] |
|
||||
// |-------------|
|
||||
// | EAX |
|
||||
// |-------------|
|
||||
// | ECX |
|
||||
// |-------------|
|
||||
// | EDX |
|
||||
// |-------------|
|
||||
// | EBX |
|
||||
// |-------------|
|
||||
// | ESP |
|
||||
// |-------------|
|
||||
// | EBP |
|
||||
// |-------------|
|
||||
// | ESI |
|
||||
// |-------------|
|
||||
// | EDI |
|
||||
// |-------------| <-- int_esp
|
||||
// 1st level interrupt handler in startup.asm sichert Zeiger auf Stackframe
|
||||
// unmittelbar nach dem Interrupt und nachdem alle Register mit PUSHAD
|
||||
// gesichert wurden
|
||||
// |-------------|
|
||||
// | EFLAGS |
|
||||
// |-------------|
|
||||
// | CS |
|
||||
// |-------------|
|
||||
// | EIP |
|
||||
// |-------------|
|
||||
// | [ErrorCode] |
|
||||
// |-------------|
|
||||
// | EAX |
|
||||
// |-------------|
|
||||
// | ECX |
|
||||
// |-------------|
|
||||
// | EDX |
|
||||
// |-------------|
|
||||
// | EBX |
|
||||
// |-------------|
|
||||
// | ESP |
|
||||
// |-------------|
|
||||
// | EBP |
|
||||
// |-------------|
|
||||
// | ESI |
|
||||
// |-------------|
|
||||
// | EDI |
|
||||
// |-------------| <-- int_esp
|
||||
|
||||
void get_int_esp(uint32_t** esp);
|
||||
void get_int_esp(uint32_t **esp);
|
||||
}
|
||||
|
||||
void break_on_bluescreen() {
|
||||
@ -67,7 +67,7 @@ uint8_t bs_ypos = 0;
|
||||
void bs_clear() {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
auto* ptr = reinterpret_cast<uint16_t*>(0xb8000);
|
||||
auto *ptr = reinterpret_cast<uint16_t *>(0xb8000);
|
||||
|
||||
for (x = 0; x < 80; x++) {
|
||||
for (y = 0; y < 25; y++) {
|
||||
@ -95,7 +95,7 @@ void bs_lf() {
|
||||
* Beschreibung: Ein Zeichen ausgeben. *
|
||||
*****************************************************************************/
|
||||
void bs_print_char(char c) {
|
||||
auto* ptr = reinterpret_cast<uint8_t*>(0xb8000);
|
||||
auto *ptr = reinterpret_cast<uint8_t *>(0xb8000);
|
||||
|
||||
*(ptr + bs_ypos * 80 * 2 + bs_xpos * 2) = c;
|
||||
bs_xpos++;
|
||||
@ -106,7 +106,7 @@ void bs_print_char(char c) {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Eine Zeichenkette ausgeben. *
|
||||
*****************************************************************************/
|
||||
void bs_print_string(char* str) {
|
||||
void bs_print_string(char *str) {
|
||||
|
||||
while (*str != '\0') {
|
||||
bs_print_char(*str);
|
||||
@ -144,7 +144,7 @@ void bs_print_uintHex(uint32_t c) {
|
||||
* Beschreibung: String mit Integer ausgeben. Wird verwendet um ein *
|
||||
* Register auszugeben. *
|
||||
*****************************************************************************/
|
||||
void bs_printReg(char* str, uint32_t value) {
|
||||
void bs_printReg(char *str, uint32_t value) {
|
||||
bs_print_string(str);
|
||||
bs_print_uintHex(value);
|
||||
bs_print_string(" \0");
|
||||
@ -156,8 +156,8 @@ void bs_printReg(char* str, uint32_t value) {
|
||||
* Beschreibung: Hauptroutine des Bluescreens. *
|
||||
*****************************************************************************/
|
||||
void bs_dump(uint8_t exceptionNr) {
|
||||
uint32_t* int_esp;
|
||||
uint32_t* sptr;
|
||||
uint32_t *int_esp;
|
||||
uint32_t *sptr;
|
||||
uint32_t faultAdress;
|
||||
uint8_t has_error_code = 0;
|
||||
|
||||
@ -183,25 +183,62 @@ void bs_dump(uint8_t exceptionNr) {
|
||||
|
||||
// Spruch ausgeben
|
||||
switch (exceptionNr) {
|
||||
case 0x00: bs_print_string("Divide Error\0"); break;
|
||||
case 0x01: bs_print_string("Debug Exception\0"); break;
|
||||
case 0x02: bs_print_string("NMI\0"); break;
|
||||
case 0x03: bs_print_string("Breakpoint Exception\0"); break;
|
||||
case 0x04: bs_print_string("Into Exception\0"); break;
|
||||
case 0x05: bs_print_string("Index out of range Exception\0"); break;
|
||||
case 0x06: bs_print_string("Invalid Opcode\0"); break;
|
||||
case 0x08: bs_print_string("Double Fault\0"); break;
|
||||
case 0x0D: bs_print_string("General Protection Error\0"); break;
|
||||
case 0x0E: bs_print_string("Page Fault\0"); break;
|
||||
case 0x18: bs_print_string("Stack invalid\0"); break;
|
||||
case 0x19: bs_print_string("Return missing\0"); break;
|
||||
case 0x1A: bs_print_string("Type Test Failed\0"); break;
|
||||
case 0x1B: bs_print_string("Null pointer exception\0"); break;
|
||||
case 0x1C: bs_print_string("MAGIC.StackTest failed\0"); break;
|
||||
case 0x1D: bs_print_string("Memory-Panic\0"); break;
|
||||
case 0x1E: bs_print_string("Pageload failed\0"); break;
|
||||
case 0x1F: bs_print_string("Stack overflow\0"); break;
|
||||
default: bs_print_string("unknown\0");
|
||||
case 0x00:
|
||||
bs_print_string("Divide Error\0");
|
||||
break;
|
||||
case 0x01:
|
||||
bs_print_string("Debug Exception\0");
|
||||
break;
|
||||
case 0x02:
|
||||
bs_print_string("NMI\0");
|
||||
break;
|
||||
case 0x03:
|
||||
bs_print_string("Breakpoint Exception\0");
|
||||
break;
|
||||
case 0x04:
|
||||
bs_print_string("Into Exception\0");
|
||||
break;
|
||||
case 0x05:
|
||||
bs_print_string("Index out of range Exception\0");
|
||||
break;
|
||||
case 0x06:
|
||||
bs_print_string("Invalid Opcode\0");
|
||||
break;
|
||||
case 0x08:
|
||||
bs_print_string("Double Fault\0");
|
||||
break;
|
||||
case 0x0D:
|
||||
bs_print_string("General Protection Error\0");
|
||||
break;
|
||||
case 0x0E:
|
||||
bs_print_string("Page Fault\0");
|
||||
break;
|
||||
case 0x18:
|
||||
bs_print_string("Stack invalid\0");
|
||||
break;
|
||||
case 0x19:
|
||||
bs_print_string("Return missing\0");
|
||||
break;
|
||||
case 0x1A:
|
||||
bs_print_string("Type Test Failed\0");
|
||||
break;
|
||||
case 0x1B:
|
||||
bs_print_string("Null pointer exception\0");
|
||||
break;
|
||||
case 0x1C:
|
||||
bs_print_string("MAGIC.StackTest failed\0");
|
||||
break;
|
||||
case 0x1D:
|
||||
bs_print_string("Memory-Panic\0");
|
||||
break;
|
||||
case 0x1E:
|
||||
bs_print_string("Pageload failed\0");
|
||||
break;
|
||||
case 0x1F:
|
||||
bs_print_string("Stack overflow\0");
|
||||
break;
|
||||
default:
|
||||
bs_print_string("unknown\0");
|
||||
}
|
||||
bs_print_string(")\0");
|
||||
bs_lf();
|
||||
@ -210,7 +247,7 @@ void bs_dump(uint8_t exceptionNr) {
|
||||
get_int_esp(&int_esp);
|
||||
|
||||
// wir müssen den Inhalt auslesen und das als Zeiger verwenden, um den Stack auszulesen
|
||||
sptr = reinterpret_cast<uint32_t*>(*int_esp);
|
||||
sptr = reinterpret_cast<uint32_t *>(*int_esp);
|
||||
|
||||
bs_lf();
|
||||
|
||||
@ -244,7 +281,7 @@ void bs_dump(uint8_t exceptionNr) {
|
||||
bs_lf();
|
||||
|
||||
bs_print_string("Last useable address = \0");
|
||||
bs_print_uintHex(total_mem - 1);
|
||||
bs_print_uintHex(Kernel::total_mem - 1);
|
||||
|
||||
bs_lf();
|
||||
}
|
||||
@ -277,7 +314,7 @@ void bs_dump(uint8_t exceptionNr) {
|
||||
bs_print_string("Calling Stack:\0");
|
||||
bs_lf();
|
||||
int x = 0;
|
||||
auto* ebp = reinterpret_cast<uint32_t*>(*(sptr + 2));
|
||||
auto *ebp = reinterpret_cast<uint32_t *>(*(sptr + 2));
|
||||
uint32_t raddr;
|
||||
|
||||
// solange eip > 1 MB && ebp < 128 MB, max. Aufruftiefe 10
|
||||
@ -288,7 +325,7 @@ void bs_dump(uint8_t exceptionNr) {
|
||||
bs_lf();
|
||||
|
||||
// dynamische Kette -> zum Aufrufer
|
||||
ebp = reinterpret_cast<uint32_t*>(*ebp);
|
||||
ebp = reinterpret_cast<uint32_t *>(*ebp);
|
||||
|
||||
x++;
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
||||
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
||||
* kout etc. verwendet wird. *
|
||||
* Kernel::kout etc. verwendet wird. *
|
||||
* *
|
||||
* Autor: Michael Schoettner, 2.2.2017 *
|
||||
*****************************************************************************/
|
||||
@ -13,7 +13,10 @@
|
||||
#ifndef Bluescreen_include__
|
||||
#define Bluescreen_include__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// dump blue screen (will not return)
|
||||
void bs_dump(uint8_t exceptionNr);
|
||||
|
||||
|
||||
#endif
|
||||
@ -12,9 +12,11 @@
|
||||
#ifndef ISR_include__
|
||||
#define ISR_include__
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class ISR {
|
||||
public:
|
||||
ISR(const ISR& copy) = delete; // Verhindere Kopieren
|
||||
ISR(const ISR ©) = delete; // Verhindere Kopieren
|
||||
|
||||
// virtual ~ISR() = default;
|
||||
|
||||
@ -24,4 +26,6 @@ public:
|
||||
virtual void trigger() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include "IntDispatcher.h"
|
||||
#include "device/cpu/CPU.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/interrupt/Bluescreen.h"
|
||||
#include "kernel/exception//Bluescreen.h"
|
||||
|
||||
extern "C" void int_disp(uint8_t vector);
|
||||
|
||||
@ -35,16 +35,18 @@ void int_disp(uint8_t vector) {
|
||||
|
||||
if (vector < 32) {
|
||||
bs_dump(vector);
|
||||
CPU::halt();
|
||||
Device::CPU::halt();
|
||||
}
|
||||
|
||||
if (intdis.report(vector) < 0) {
|
||||
kout << "Panic: unexpected interrupt " << vector;
|
||||
kout << " - processor halted." << endl;
|
||||
CPU::halt();
|
||||
if (Kernel::intdis.report(vector) < 0) {
|
||||
Kernel::kout << "Panic: unexpected interrupt " << vector;
|
||||
Kernel::kout << " - processor halted." << endl;
|
||||
Device::CPU::halt();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: IntDispatcher::assign *
|
||||
*---------------------------------------------------------------------------*
|
||||
@ -56,7 +58,7 @@ void int_disp(uint8_t vector) {
|
||||
* *
|
||||
* Rueckgabewert: 0 = Erfolg, -1 = Fehler *
|
||||
*****************************************************************************/
|
||||
int IntDispatcher::assign(uint8_t vector, ISR& isr) {
|
||||
int IntDispatcher::assign(uint8_t vector, ISR &isr) {
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
@ -89,7 +91,7 @@ int IntDispatcher::report(uint8_t vector) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ISR* isr = map[vector];
|
||||
ISR *isr = map[vector];
|
||||
|
||||
if (isr == nullptr) {
|
||||
log.error() << "No ISR registered for vector " << vector << endl;
|
||||
@ -107,3 +109,5 @@ int IntDispatcher::report(uint8_t vector) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,18 +14,22 @@
|
||||
#define IntDispatcher_include__
|
||||
|
||||
#include "ISR.h"
|
||||
#include "lib/util/Array.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/container//Array.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class IntDispatcher {
|
||||
private:
|
||||
NamedLogger log;
|
||||
|
||||
enum { size = 256 };
|
||||
bse::array<ISR*, size> map;
|
||||
enum {
|
||||
size = 256
|
||||
};
|
||||
Container::array<ISR *, size> map;
|
||||
|
||||
public:
|
||||
IntDispatcher(const IntDispatcher& copy) = delete; // Verhindere Kopieren
|
||||
IntDispatcher(const IntDispatcher ©) = delete; // Verhindere Kopieren
|
||||
|
||||
// Vektor-Nummern
|
||||
enum {
|
||||
@ -36,16 +40,18 @@ public:
|
||||
|
||||
// Initialisierung der ISR map mit einer Default-ISR.
|
||||
IntDispatcher() : log("IntDis") {
|
||||
for (ISR*& slot : map) {
|
||||
for (ISR *&slot: map) {
|
||||
slot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Registrierung einer ISR. (Rueckgabewert: 0 = Erfolg, -1 = Fehler)
|
||||
int assign(uint8_t vector, ISR& isr);
|
||||
int assign(uint8_t vector, ISR &isr);
|
||||
|
||||
// ISR fuer 'vector' ausfuehren
|
||||
int report(uint8_t vector);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,119 +0,0 @@
|
||||
#include "Logger.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
bool Logger::kout_enabled = true;
|
||||
bool Logger::serial_enabled = true;
|
||||
|
||||
Logger::LogLevel Logger::level = Logger::ERROR;
|
||||
|
||||
constexpr const char* ansi_red = "\033[1;31m";
|
||||
constexpr const char* ansi_green = "\033[1;32m";
|
||||
constexpr const char* ansi_yellow = "\033[1;33m";
|
||||
constexpr const char* ansi_blue = "\033[1;34m";
|
||||
constexpr const char* ansi_magenta = "\033[1;35m";
|
||||
constexpr const char* ansi_cyan = "\033[1;36m";
|
||||
constexpr const char* ansi_white = "\033[1;37m";
|
||||
constexpr const char* ansi_default = "\033[0;39m ";
|
||||
|
||||
void Logger::log(const bse::string_view message, CGA::color col) const {
|
||||
if (Logger::kout_enabled) {
|
||||
CGA::color old_col = kout.color_fg;
|
||||
kout << fgc(col)
|
||||
<< "["
|
||||
<< Logger::level_to_string(current_message_level) << "] "
|
||||
<< message << fgc(old_col);
|
||||
kout.flush(); // Don't add newline, Logger already does that
|
||||
}
|
||||
if (Logger::serial_enabled) {
|
||||
switch (col) {
|
||||
case CGA::WHITE:
|
||||
SerialOut::write(ansi_white);
|
||||
break;
|
||||
case CGA::LIGHT_MAGENTA:
|
||||
SerialOut::write(ansi_magenta);
|
||||
break;
|
||||
case CGA::LIGHT_RED:
|
||||
SerialOut::write(ansi_red);
|
||||
break;
|
||||
case CGA::LIGHT_BLUE:
|
||||
SerialOut::write(ansi_blue);
|
||||
break;
|
||||
default:
|
||||
SerialOut::write(ansi_default);
|
||||
}
|
||||
SerialOut::write("[");
|
||||
SerialOut::write(Logger::level_to_string(current_message_level));
|
||||
SerialOut::write("] ");
|
||||
SerialOut::write(message);
|
||||
SerialOut::write('\r');
|
||||
// serial.write("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::flush() {
|
||||
buffer[pos] = '\0';
|
||||
|
||||
switch (current_message_level) {
|
||||
case Logger::TRACE:
|
||||
trace(buffer.data());
|
||||
break;
|
||||
case Logger::DEBUG:
|
||||
debug(buffer.data());
|
||||
break;
|
||||
case Logger::ERROR:
|
||||
error(buffer.data());
|
||||
break;
|
||||
case Logger::INFO:
|
||||
info(buffer.data());
|
||||
break;
|
||||
}
|
||||
|
||||
current_message_level = Logger::INFO;
|
||||
pos = 0;
|
||||
Logger::unlock();
|
||||
}
|
||||
|
||||
void Logger::trace(const bse::string_view message) const {
|
||||
if (Logger::level <= Logger::TRACE) {
|
||||
log(message, CGA::WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::debug(const bse::string_view message) const {
|
||||
if (Logger::level <= Logger::DEBUG) {
|
||||
log(message, CGA::LIGHT_MAGENTA);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::error(const bse::string_view message) const {
|
||||
if (Logger::level <= Logger::ERROR) {
|
||||
log(message, CGA::LIGHT_RED);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::info(const bse::string_view message) const {
|
||||
if (Logger::level <= Logger::INFO) {
|
||||
log(message, CGA::LIGHT_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Manipulatoren
|
||||
Logger& TRACE(Logger& log) {
|
||||
log.current_message_level = Logger::TRACE;
|
||||
return log;
|
||||
}
|
||||
|
||||
Logger& DEBUG(Logger& log) {
|
||||
log.current_message_level = Logger::DEBUG;
|
||||
return log;
|
||||
}
|
||||
|
||||
Logger& ERROR(Logger& log) {
|
||||
log.current_message_level = Logger::ERROR;
|
||||
return log;
|
||||
}
|
||||
|
||||
Logger& INFO(Logger& log) {
|
||||
log.current_message_level = Logger::INFO;
|
||||
return log;
|
||||
}
|
||||
@ -1,121 +0,0 @@
|
||||
#ifndef Logger_Include_H_
|
||||
#define Logger_Include_H_
|
||||
|
||||
#include "device/graphics/CGA.h"
|
||||
#include "lib/stream/OutStream.h"
|
||||
#include "lib/async/SpinLock.h"
|
||||
#include "lib/util/String.h"
|
||||
#include "lib/util/StringView.h"
|
||||
|
||||
class Logger : public OutStream {
|
||||
friend class NamedLogger; // Allow NamedLogger to lock/unlock
|
||||
|
||||
public:
|
||||
static Logger& instance() {
|
||||
static Logger log;
|
||||
return log;
|
||||
}
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
|
||||
static bool kout_enabled;
|
||||
static bool serial_enabled;
|
||||
|
||||
void log(bse::string_view message, CGA::color col) const;
|
||||
|
||||
SpinLock sem; // Semaphore would be a cyclic include
|
||||
static void lock() { Logger::instance().sem.acquire(); }
|
||||
static void unlock() { Logger::instance().sem.release(); }
|
||||
// static void lock() {}
|
||||
// static void unlock() {}
|
||||
|
||||
public:
|
||||
// ~Logger() override = default;
|
||||
|
||||
Logger(const Logger& copy) = delete;
|
||||
void operator=(const Logger& copy) = delete;
|
||||
|
||||
enum LogLevel {
|
||||
TRACE,
|
||||
DEBUG,
|
||||
ERROR,
|
||||
INFO
|
||||
};
|
||||
static LogLevel level;
|
||||
LogLevel current_message_level = Logger::INFO; // Use this to log with manipulators
|
||||
|
||||
void flush() override;
|
||||
|
||||
void trace(bse::string_view message) const;
|
||||
void debug(bse::string_view message) const;
|
||||
void error(bse::string_view message) const;
|
||||
void info(bse::string_view message) const;
|
||||
|
||||
// TODO: Make lvl change accessible over menu
|
||||
static void set_level(LogLevel lvl) {
|
||||
Logger::level = lvl;
|
||||
}
|
||||
|
||||
static bse::string_view level_to_string(LogLevel lvl) {
|
||||
switch (lvl) {
|
||||
case Logger::TRACE:
|
||||
return "TRC";
|
||||
case Logger::DEBUG:
|
||||
return "DBG";
|
||||
case Logger::ERROR:
|
||||
return "ERR";
|
||||
case Logger::INFO:
|
||||
return "INF";
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_kout() {
|
||||
Logger::kout_enabled = true;
|
||||
}
|
||||
static void disable_kout() {
|
||||
Logger::kout_enabled = false;
|
||||
}
|
||||
static void enable_serial() {
|
||||
Logger::serial_enabled = true;
|
||||
}
|
||||
static void disable_serial() {
|
||||
Logger::serial_enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Manipulatoren
|
||||
Logger& TRACE(Logger& log);
|
||||
Logger& DEBUG(Logger& log);
|
||||
Logger& ERROR(Logger& log);
|
||||
Logger& INFO(Logger& log);
|
||||
|
||||
class NamedLogger {
|
||||
private:
|
||||
const char* name;
|
||||
|
||||
public:
|
||||
explicit NamedLogger(const char* name) : name(name) {}
|
||||
|
||||
Logger& trace() {
|
||||
Logger::lock();
|
||||
return Logger::instance() << TRACE << name << " :: ";
|
||||
}
|
||||
|
||||
Logger& debug() {
|
||||
Logger::lock();
|
||||
return Logger::instance() << DEBUG << name << " :: ";
|
||||
}
|
||||
|
||||
Logger& error() {
|
||||
Logger::lock();
|
||||
return Logger::instance() << ERROR << name << " :: ";
|
||||
}
|
||||
|
||||
Logger& info() {
|
||||
Logger::lock();
|
||||
return Logger::instance() << INFO << name << " :: ";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -34,6 +34,8 @@
|
||||
#include "Allocator.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr const unsigned int MEM_SIZE_DEF = 8 * 1024 * 1024; // Groesse des Speichers = 8 MB
|
||||
constexpr const unsigned int HEAP_START = 0x300000; // Startadresse des Heaps
|
||||
constexpr const unsigned int HEAP_SIZE = 1024 * 1024; // Default-Groesse des Heaps, falls \
|
||||
@ -42,39 +44,42 @@ constexpr const unsigned int HEAP_SIZE = 1024 * 1024; // Default-Groesse des He
|
||||
/*****************************************************************************
|
||||
* Konstruktor: Allocator::Allocator *
|
||||
*****************************************************************************/
|
||||
Allocator::Allocator() : heap_start(HEAP_START), heap_end(HEAP_START + HEAP_SIZE), heap_size(HEAP_SIZE), initialized(1) {
|
||||
Allocator::Allocator() : heap_start(HEAP_START), heap_end(HEAP_START + HEAP_SIZE), heap_size(HEAP_SIZE),
|
||||
initialized(1) {
|
||||
// Groesse des Hauptspeichers (kann über das BIOS abgefragt werden,
|
||||
// aber sehr umstaendlich, daher hier fest eingetragen
|
||||
total_mem = MEM_SIZE_DEF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Nachfolgend sind die Operatoren von C++, die wir hier ueberschreiben *
|
||||
* und entsprechend 'mm_alloc' und 'mm_free' aufrufen. *
|
||||
*****************************************************************************/
|
||||
void* operator new(std::size_t size) {
|
||||
return allocator.alloc(size);
|
||||
void *operator new(std::size_t size) {
|
||||
return Kernel::allocator.alloc(size);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t count) {
|
||||
return allocator.alloc(count);
|
||||
void *operator new[](std::size_t count) {
|
||||
return Kernel::allocator.alloc(count);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr) {
|
||||
allocator.free(ptr);
|
||||
void operator delete(void *ptr) {
|
||||
Kernel::allocator.free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr) {
|
||||
allocator.free(ptr);
|
||||
void operator delete[](void *ptr) {
|
||||
Kernel::allocator.free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, unsigned int sz) {
|
||||
allocator.free(ptr);
|
||||
void operator delete(void *ptr, unsigned int sz) {
|
||||
Kernel::allocator.free(ptr);
|
||||
}
|
||||
|
||||
// I don't know if accidentally deleted it but one delete was missing
|
||||
// https://en.cppreference.com/w/cpp/memory/new/operator_delete
|
||||
|
||||
void operator delete[](void* ptr, unsigned int sz) {
|
||||
allocator.free(ptr);
|
||||
void operator delete[](void *ptr, unsigned int sz) {
|
||||
Kernel::allocator.free(ptr);
|
||||
}
|
||||
|
||||
@ -33,12 +33,14 @@
|
||||
#ifndef Allocator_include__
|
||||
#define Allocator_include__
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr const unsigned int BASIC_ALIGN = 4; // 32 Bit so 4 Bytes?
|
||||
constexpr const unsigned int HEAP_MIN_FREE_BLOCK_SIZE = 64; // min. Groesse eines freien Blocks
|
||||
|
||||
class Allocator {
|
||||
public:
|
||||
Allocator(Allocator& copy) = delete; // Verhindere Kopieren
|
||||
Allocator(Allocator ©) = delete; // Verhindere Kopieren
|
||||
|
||||
Allocator();
|
||||
|
||||
@ -50,9 +52,14 @@ public:
|
||||
unsigned int initialized;
|
||||
|
||||
virtual void init() = 0;
|
||||
|
||||
virtual void dump_free_memory() = 0;
|
||||
virtual void* alloc(unsigned int req_size) = 0;
|
||||
virtual void free(void* ptr) = 0;
|
||||
|
||||
virtual void *alloc(unsigned int req_size) = 0;
|
||||
|
||||
virtual void free(void *ptr) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
#include "BumpAllocator.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: BumpAllocator::init *
|
||||
*---------------------------------------------------------------------------*
|
||||
@ -22,7 +24,7 @@ void BumpAllocator::init() {
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
allocations = 0;
|
||||
next = reinterpret_cast<uint8_t*>(heap_start);
|
||||
next = reinterpret_cast<uint8_t *>(heap_start);
|
||||
|
||||
log.info() << "Initialized Bump Allocator" << endl;
|
||||
}
|
||||
@ -36,7 +38,7 @@ void BumpAllocator::dump_free_memory() {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
kout << "Freier Speicher:" << endl
|
||||
Kernel::kout << "Freier Speicher:" << endl
|
||||
<< " - Next: " << hex << reinterpret_cast<uint32_t>(next)
|
||||
<< ", Allocations: " << dec << allocations << endl;
|
||||
}
|
||||
@ -46,7 +48,7 @@ void BumpAllocator::dump_free_memory() {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Einen neuen Speicherblock allozieren. *
|
||||
*****************************************************************************/
|
||||
void* BumpAllocator::alloc(uint32_t req_size) {
|
||||
void *BumpAllocator::alloc(uint32_t req_size) {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
@ -57,8 +59,8 @@ void* BumpAllocator::alloc(uint32_t req_size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* allocated = next;
|
||||
next = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(next) + req_size);
|
||||
void *allocated = next;
|
||||
next = reinterpret_cast<uint8_t *>(reinterpret_cast<uint32_t>(next) + req_size);
|
||||
allocations = allocations + 1;
|
||||
|
||||
log.trace() << " - Allocated " << hex << req_size << " Bytes." << endl;
|
||||
@ -71,6 +73,8 @@ void* BumpAllocator::alloc(uint32_t req_size) {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Nicht implementiert. *
|
||||
*****************************************************************************/
|
||||
void BumpAllocator::free(void* ptr) {
|
||||
void BumpAllocator::free(void *ptr) {
|
||||
log.error() << " mm_free: ptr= " << hex << reinterpret_cast<uint32_t>(ptr) << ", not supported" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -13,26 +13,33 @@
|
||||
#define BumpAllocator_include__
|
||||
|
||||
#include "Allocator.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class BumpAllocator : Allocator {
|
||||
private:
|
||||
uint8_t* next;
|
||||
uint8_t *next;
|
||||
uint32_t allocations;
|
||||
|
||||
NamedLogger log;
|
||||
|
||||
public:
|
||||
BumpAllocator(Allocator& copy) = delete; // Verhindere Kopieren
|
||||
BumpAllocator(Allocator ©) = delete; // Verhindere Kopieren
|
||||
|
||||
BumpAllocator() : log("BMP-Alloc") {}; // Allocator() called implicitely in C++
|
||||
|
||||
// ~BumpAllocator() override = default;
|
||||
|
||||
void init() override;
|
||||
|
||||
void dump_free_memory() override;
|
||||
void* alloc(uint32_t req_size) override;
|
||||
void free(void* ptr) override;
|
||||
|
||||
void *alloc(uint32_t req_size) override;
|
||||
|
||||
void free(void *ptr) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
// memory addresses of each block
|
||||
// (That was the plan at least)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
/*****************************************************************************
|
||||
* Methode: LinkedListAllocator::init *
|
||||
*---------------------------------------------------------------------------*
|
||||
@ -31,7 +33,7 @@ void LinkedListAllocator::init() {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
free_start = reinterpret_cast<free_block_t*>(heap_start);
|
||||
free_start = reinterpret_cast<free_block_t *>(heap_start);
|
||||
free_start->allocated = false;
|
||||
free_start->size = heap_size - sizeof(free_block_t);
|
||||
free_start->next = free_start; // Only one block, points to itself
|
||||
@ -48,16 +50,16 @@ void LinkedListAllocator::dump_free_memory() {
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
kout << "Freier Speicher:" << endl;
|
||||
Kernel::kout << "Freier Speicher:" << endl;
|
||||
|
||||
if (free_start == nullptr) {
|
||||
kout << " - No free Blocks" << endl;
|
||||
Kernel::kout << " - No free Blocks" << endl;
|
||||
} else {
|
||||
kout << " - Freelist start: " << hex << reinterpret_cast<uint32_t>(free_start) << endl;
|
||||
Kernel::kout << " - Freelist start: " << hex << reinterpret_cast<uint32_t>(free_start) << endl;
|
||||
|
||||
free_block_t* current = free_start;
|
||||
free_block_t *current = free_start;
|
||||
do {
|
||||
kout << " - Free Block (Start: " << hex << reinterpret_cast<uint32_t>(current)
|
||||
Kernel::kout << " - Free Block (Start: " << hex << reinterpret_cast<uint32_t>(current)
|
||||
<< " Size: " << hex << current->size << ")" << endl;
|
||||
current = current->next;
|
||||
} while (current != free_start);
|
||||
@ -69,7 +71,7 @@ void LinkedListAllocator::dump_free_memory() {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Einen neuen Speicherblock allozieren. *
|
||||
*****************************************************************************/
|
||||
void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
void *LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
lock.acquire();
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
@ -90,7 +92,7 @@ void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
log.trace() << " - Rounded to word border (+" << dec << req_size_diff << " bytes)" << endl;
|
||||
}
|
||||
|
||||
free_block_t* current = free_start;
|
||||
free_block_t *current = free_start;
|
||||
do {
|
||||
if (current->size >= rreq_size) { // Size doesn't contain header, only usable
|
||||
// Current block large enough
|
||||
@ -104,8 +106,9 @@ void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
// [<> | current | new_next | <>]
|
||||
// In case of only one freeblock:
|
||||
// [current | new_next]
|
||||
free_block_t* new_next =
|
||||
reinterpret_cast<free_block_t*>(reinterpret_cast<uint32_t>(current) + sizeof(free_block_t) + rreq_size);
|
||||
free_block_t *new_next =
|
||||
reinterpret_cast<free_block_t *>(reinterpret_cast<uint32_t>(current) + sizeof(free_block_t) +
|
||||
rreq_size);
|
||||
|
||||
// If only one block exists, current->next is current
|
||||
// This shouldn't be a problem since the block gets removed from the list later
|
||||
@ -138,7 +141,7 @@ void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
// If block was cut this is obvious, because current->next is a free block
|
||||
// If block wasn't cut it also works as current was a free block before, so it's next
|
||||
// block should also be free
|
||||
free_block_t* previous = LinkedListAllocator::find_previous_block(current);
|
||||
free_block_t *previous = LinkedListAllocator::find_previous_block(current);
|
||||
previous->next = current->next; // Current block was free so previous block pointed at it
|
||||
current->allocated = true;
|
||||
|
||||
@ -154,9 +157,11 @@ void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
// }
|
||||
// log.debug() << "Finished check" << endl;
|
||||
|
||||
log.debug() << "returning memory address " << hex << reinterpret_cast<uint32_t>(current) + sizeof(free_block_t) << endl;
|
||||
log.debug() << "returning memory address " << hex
|
||||
<< reinterpret_cast<uint32_t>(current) + sizeof(free_block_t) << endl;
|
||||
lock.release();
|
||||
return reinterpret_cast<void*>(reinterpret_cast<uint32_t>(current) + sizeof(free_block_t)); // Speicheranfang, nicht header
|
||||
return reinterpret_cast<void *>(reinterpret_cast<uint32_t>(current) +
|
||||
sizeof(free_block_t)); // Speicheranfang, nicht header
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
@ -172,13 +177,14 @@ void* LinkedListAllocator::alloc(uint32_t req_size) {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Einen Speicherblock freigeben. *
|
||||
*****************************************************************************/
|
||||
void LinkedListAllocator::free(void* ptr) {
|
||||
void LinkedListAllocator::free(void *ptr) {
|
||||
lock.acquire();
|
||||
|
||||
/* Hier muess Code eingefuegt werden */
|
||||
|
||||
// Account for header
|
||||
free_block_t* block_start = reinterpret_cast<free_block_t*>(reinterpret_cast<uint32_t>(ptr) - sizeof(free_block_t));
|
||||
free_block_t *block_start = reinterpret_cast<free_block_t *>(reinterpret_cast<uint32_t>(ptr) -
|
||||
sizeof(free_block_t));
|
||||
|
||||
log.debug() << "Freeing " << hex << reinterpret_cast<uint32_t>(ptr) << ", Size: " << block_start->size << endl;
|
||||
|
||||
@ -200,18 +206,20 @@ void LinkedListAllocator::free(void* ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
free_block_t* next_block =
|
||||
reinterpret_cast<free_block_t*>(reinterpret_cast<uint32_t>(block_start) + sizeof(free_block_t) + block_start->size);
|
||||
free_block_t *next_block =
|
||||
reinterpret_cast<free_block_t *>(reinterpret_cast<uint32_t>(block_start) + sizeof(free_block_t) +
|
||||
block_start->size);
|
||||
|
||||
// Find the next free block, multiple next blocks can be allocated so walk through them
|
||||
free_block_t* next_free = block_start->next;
|
||||
free_block_t *next_free = block_start->next;
|
||||
while (next_free->allocated) {
|
||||
next_free = next_free->next;
|
||||
}
|
||||
|
||||
free_block_t* previous_free = LinkedListAllocator::find_previous_block(next_free);
|
||||
free_block_t* previous_free_next =
|
||||
reinterpret_cast<free_block_t*>(reinterpret_cast<uint32_t>(previous_free) + sizeof(free_block_t) + previous_free->size);
|
||||
free_block_t *previous_free = LinkedListAllocator::find_previous_block(next_free);
|
||||
free_block_t *previous_free_next =
|
||||
reinterpret_cast<free_block_t *>(reinterpret_cast<uint32_t>(previous_free) + sizeof(free_block_t) +
|
||||
previous_free->size);
|
||||
|
||||
// We have: [previous_free | previous_free_next | <> | block_start | next_block | <> | next_free]
|
||||
// The <> spaces don't have to exist and next_block could be the same as next_free
|
||||
@ -284,7 +292,8 @@ void LinkedListAllocator::free(void* ptr) {
|
||||
|
||||
if (free_start == block_start) {
|
||||
// block_start is now invalid after merge
|
||||
log.trace() << " - Moving freelist start to " << hex << reinterpret_cast<unsigned int>(previous_free) << endl;
|
||||
log.trace() << " - Moving freelist start to " << hex << reinterpret_cast<unsigned int>(previous_free)
|
||||
<< endl;
|
||||
free_start = previous_free;
|
||||
}
|
||||
}
|
||||
@ -294,17 +303,19 @@ void LinkedListAllocator::free(void* ptr) {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
free_block_t* LinkedListAllocator::find_previous_block(free_block_t* next_block) {
|
||||
free_block_t *LinkedListAllocator::find_previous_block(free_block_t *next_block) {
|
||||
// Durchlaufe die ganze freispeicherliste bis zum Block der auf next_block zeigt
|
||||
free_block_t* current = next_block;
|
||||
free_block_t *current = next_block;
|
||||
while (current->next != next_block) {
|
||||
// NOTE: This will get stuck if called on the wrong block
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
// if (current == next_block) {
|
||||
// kout << "LinkedListAllocator::find_previous_block returned the input block" << endl;
|
||||
// Kernel::kout << "LinkedListAllocator::find_previous_block returned the input block" << endl;
|
||||
// }
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,45 +14,52 @@
|
||||
|
||||
#include "Allocator.h"
|
||||
#include "lib/async/SpinLock.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// Format eines freien Blocks, 4 + 4 + 4 Byte
|
||||
typedef struct free_block {
|
||||
bool allocated; // NOTE: I added this to allow easier merging of free blocks:
|
||||
// When freeing an allocated block, its next-pointer can
|
||||
// point to another allocated block, the next free block
|
||||
// can be found by traversing the leading allocated blocks.
|
||||
// We only need a way to determine when the free block is reached.
|
||||
// This also means that the whole list has to be traversed
|
||||
// to merge blocks. Would be faster with doubly linked list.
|
||||
// When freeing an allocated block, its next-pointer can
|
||||
// point to another allocated block, the next free block
|
||||
// can be found by traversing the leading allocated blocks.
|
||||
// We only need a way to determine when the free block is reached.
|
||||
// This also means that the whole list has to be traversed
|
||||
// to merge blocks. Would be faster with doubly linked list.
|
||||
uint32_t size;
|
||||
struct free_block* next;
|
||||
struct free_block *next;
|
||||
} free_block_t;
|
||||
|
||||
class LinkedListAllocator : Allocator {
|
||||
private:
|
||||
// freie Bloecke werden verkettet
|
||||
struct free_block* free_start = nullptr;
|
||||
struct free_block *free_start = nullptr;
|
||||
|
||||
// Traverses the whole list forward till previous block is reached.
|
||||
// This can only be called on free blocks as allocated blocks
|
||||
// aren't reachable from the freelist.
|
||||
static struct free_block* find_previous_block(struct free_block*);
|
||||
static struct free_block *find_previous_block(struct free_block *);
|
||||
|
||||
NamedLogger log;
|
||||
SpinLock lock;
|
||||
Async::SpinLock lock;
|
||||
|
||||
public:
|
||||
LinkedListAllocator(Allocator& copy) = delete; // Verhindere Kopieren
|
||||
LinkedListAllocator(Allocator ©) = delete; // Verhindere Kopieren
|
||||
|
||||
LinkedListAllocator() : log("LL-Alloc") {}
|
||||
|
||||
// ~LinkedListAllocator() override = default;
|
||||
|
||||
void init() override;
|
||||
|
||||
void dump_free_memory() override;
|
||||
void* alloc(uint32_t req_size) override;
|
||||
void free(void* ptr) override;
|
||||
|
||||
void *alloc(uint32_t req_size) override;
|
||||
|
||||
void free(void *ptr) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -50,7 +50,9 @@
|
||||
*****************************************************************************/
|
||||
#include "kernel/memory/Paging.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// Bits fuer Eintraege in der Page-Table
|
||||
constexpr const unsigned int PAGE_PRESENT = 0x001;
|
||||
@ -74,10 +76,10 @@ constexpr const unsigned int LST_ALLOCABLE_PAGE = 0x2FF000;
|
||||
* Beschreibung: Alloziert eine 4 KB Seite. Allozieren heisst hier *
|
||||
* lediglich Setzen eines eigenen RESERVED-Bits. *
|
||||
*****************************************************************************/
|
||||
uint32_t* pg_alloc_page() {
|
||||
uint32_t* p_page;
|
||||
uint32_t *pg_alloc_page() {
|
||||
uint32_t *p_page;
|
||||
|
||||
p_page = reinterpret_cast<uint32_t*>(PAGE_TABLE);
|
||||
p_page = reinterpret_cast<uint32_t *>(PAGE_TABLE);
|
||||
|
||||
// 1. Eintrag ist fuer Null-Pointer-Exception reserviert
|
||||
// ausserdem liegt die Page-Table an Adresse PAGE_TABLE
|
||||
@ -87,7 +89,7 @@ uint32_t* pg_alloc_page() {
|
||||
// pruefe ob Page frei
|
||||
if (((*p_page) & PAGE_RESERVED) == 0) {
|
||||
*p_page = (*p_page | PAGE_RESERVED);
|
||||
return reinterpret_cast<uint32_t*>(i << 12); // Address without flags (Offset 0)
|
||||
return reinterpret_cast<uint32_t *>(i << 12); // Address without flags (Offset 0)
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@ -99,11 +101,12 @@ uint32_t* pg_alloc_page() {
|
||||
* Beschreibung: Schreibschutz fuer die uebergebene Seite aktivieren. *
|
||||
* Dies fuer das Debugging nuetzlich. *
|
||||
*****************************************************************************/
|
||||
void pg_write_protect_page(const uint32_t* p_page) {
|
||||
void pg_write_protect_page(const uint32_t *p_page) {
|
||||
|
||||
/* hier muss Code eingefügt werden */
|
||||
|
||||
uint32_t* page = reinterpret_cast<uint32_t*>(PAGE_TABLE) + (reinterpret_cast<uint32_t>(p_page) >> 12); // Pagetable entry
|
||||
uint32_t *page =
|
||||
reinterpret_cast<uint32_t *>(PAGE_TABLE) + (reinterpret_cast<uint32_t>(p_page) >> 12); // Pagetable entry
|
||||
|
||||
uint32_t mask = PAGE_WRITEABLE; // fill to 32bit
|
||||
*page = *page & ~mask; // set writable to 0
|
||||
@ -116,11 +119,12 @@ void pg_write_protect_page(const uint32_t* p_page) {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Seite als ausgelagert markieren. Nur fuer Testzwecke. *
|
||||
*****************************************************************************/
|
||||
void pg_notpresent_page(const uint32_t* p_page) {
|
||||
void pg_notpresent_page(const uint32_t *p_page) {
|
||||
|
||||
/* hier muss Code eingefügt werden */
|
||||
|
||||
uint32_t* page = reinterpret_cast<uint32_t*>(PAGE_TABLE) + (reinterpret_cast<uint32_t>(p_page) >> 12); // Pagetable entry
|
||||
uint32_t *page =
|
||||
reinterpret_cast<uint32_t *>(PAGE_TABLE) + (reinterpret_cast<uint32_t>(p_page) >> 12); // Pagetable entry
|
||||
|
||||
uint32_t mask = PAGE_PRESENT;
|
||||
*page = *page & ~mask; // set present to 0
|
||||
@ -134,7 +138,7 @@ void pg_notpresent_page(const uint32_t* p_page) {
|
||||
* Beschreibung: Gibt eine 4 KB Seite frei. Es wird hierbei das RESERVED- *
|
||||
* Bit geloescht. *
|
||||
*****************************************************************************/
|
||||
void pg_free_page(uint32_t* p_page) {
|
||||
void pg_free_page(uint32_t *p_page) {
|
||||
uint32_t idx = reinterpret_cast<uint32_t>(p_page) >> 12;
|
||||
|
||||
// ausserhalb Page ?
|
||||
@ -143,7 +147,7 @@ void pg_free_page(uint32_t* p_page) {
|
||||
}
|
||||
|
||||
// Eintrag einlesen und aendern (PAGE_WRITEABLE loeschen)
|
||||
p_page = reinterpret_cast<uint32_t*>(PAGE_TABLE);
|
||||
p_page = reinterpret_cast<uint32_t *>(PAGE_TABLE);
|
||||
p_page += idx;
|
||||
|
||||
*p_page = ((idx << 12) | PAGE_WRITEABLE | PAGE_PRESENT);
|
||||
@ -157,8 +161,8 @@ void pg_free_page(uint32_t* p_page) {
|
||||
*****************************************************************************/
|
||||
void pg_init() {
|
||||
uint32_t i;
|
||||
uint32_t* p_pdir; // Zeiger auf Page-Directory
|
||||
uint32_t* p_page; // Zeiger auf einzige Page-Table fuer 4 KB Pages
|
||||
uint32_t *p_pdir; // Zeiger auf Page-Directory
|
||||
uint32_t *p_page; // Zeiger auf einzige Page-Table fuer 4 KB Pages
|
||||
uint32_t num_pages; // Anzahl 4 MB Pages die phys. Adressraum umfassen
|
||||
|
||||
// wie viele 4 MB Seiten sollen als 'Present' angelegt werden,
|
||||
@ -174,7 +178,7 @@ void pg_init() {
|
||||
//
|
||||
|
||||
// Eintrag 0: Zeiger auf 4 KB Page-Table
|
||||
p_pdir = reinterpret_cast<uint32_t*>(PAGE_DIRECTORY);
|
||||
p_pdir = reinterpret_cast<uint32_t *>(PAGE_DIRECTORY);
|
||||
*p_pdir = PAGE_TABLE | PAGE_WRITEABLE | PAGE_PRESENT;
|
||||
|
||||
// Eintraege 1-1023: Direktes Mapping (1:1) auf 4 MB Pages (ohne Page-Table)
|
||||
@ -190,7 +194,7 @@ void pg_init() {
|
||||
//
|
||||
// 1. Page-Table
|
||||
//
|
||||
p_page = reinterpret_cast<uint32_t*>(PAGE_TABLE);
|
||||
p_page = reinterpret_cast<uint32_t *>(PAGE_TABLE);
|
||||
|
||||
// ersten Eintrag loeschen -> not present, write protected -> Null-Pointer abfangen
|
||||
*p_page = 0;
|
||||
@ -209,5 +213,7 @@ void pg_init() {
|
||||
}
|
||||
|
||||
// Paging aktivieren (in startup.asm)
|
||||
paging_on(reinterpret_cast<uint32_t*>(PAGE_DIRECTORY));
|
||||
paging_on(reinterpret_cast<uint32_t *>(PAGE_DIRECTORY));
|
||||
}
|
||||
|
||||
}
|
||||
@ -56,23 +56,27 @@
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
void paging_on(uint32_t* p_pdir); // Paging einschalten
|
||||
void invalidate_tlb_entry(const uint32_t* ptr); // Page in TLB invalid.
|
||||
void paging_on(uint32_t *p_pdir); // Paging einschalten
|
||||
void invalidate_tlb_entry(const uint32_t *ptr); // Page in TLB invalid.
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// ativiert paging
|
||||
extern void pg_init();
|
||||
|
||||
// alloziert eine 4 KB Page
|
||||
extern uint32_t* pg_alloc_page();
|
||||
extern uint32_t *pg_alloc_page();
|
||||
|
||||
// Schreibschutz auf Seite setzen -> fuer debugging nuetzlich
|
||||
extern void pg_write_protect_page(const uint32_t* p_page);
|
||||
extern void pg_write_protect_page(const uint32_t *p_page);
|
||||
|
||||
// Present Bit loeschen
|
||||
extern void pg_notpresent_page(const uint32_t* p_page);
|
||||
extern void pg_notpresent_page(const uint32_t *p_page);
|
||||
|
||||
// gibt eine 4 KB Page frei
|
||||
extern void pg_free_page(uint32_t* p_page);
|
||||
extern void pg_free_page(uint32_t *p_page);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,25 +1,27 @@
|
||||
#include "TreeAllocator.h"
|
||||
#include "kernel/system/Globals.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void TreeAllocator::init() {
|
||||
free_start = reinterpret_cast<tree_block_t*>(heap_start);
|
||||
free_start = reinterpret_cast<tree_block_t *>(heap_start);
|
||||
free_start->allocated = false;
|
||||
free_start->left = nullptr;
|
||||
free_start->right = nullptr;
|
||||
free_start->parent = nullptr;
|
||||
free_start->red = false; // The root is always black
|
||||
free_start->next = reinterpret_cast<list_block_t*>(free_start);
|
||||
free_start->previous = reinterpret_cast<list_block_t*>(free_start);
|
||||
free_start->next = reinterpret_cast<list_block_t *>(free_start);
|
||||
free_start->previous = reinterpret_cast<list_block_t *>(free_start);
|
||||
|
||||
log.info() << "Initialized Tree Allocator" << endl;
|
||||
}
|
||||
|
||||
void TreeAllocator::dump_free_memory() {
|
||||
kout << "Free Memory:" << endl;
|
||||
list_block_t* current = reinterpret_cast<list_block_t*>(heap_start);
|
||||
Kernel::kout << "Free Memory:" << endl;
|
||||
list_block_t *current = reinterpret_cast<list_block_t *>(heap_start);
|
||||
do {
|
||||
if (!current->allocated) {
|
||||
kout << " - Free Block at " << reinterpret_cast<uint32_t>(current) << ", Size: "
|
||||
Kernel::kout << " - Free Block at " << reinterpret_cast<uint32_t>(current) << ", Size: "
|
||||
<< reinterpret_cast<uint32_t>(current->next) - reinterpret_cast<uint32_t>(current)
|
||||
<< endl;
|
||||
}
|
||||
@ -27,7 +29,7 @@ void TreeAllocator::dump_free_memory() {
|
||||
} while (reinterpret_cast<uint32_t>(current) != heap_start);
|
||||
}
|
||||
|
||||
void* TreeAllocator::alloc(uint32_t req_size) {
|
||||
void *TreeAllocator::alloc(uint32_t req_size) {
|
||||
log.debug() << "Requested " << dec << req_size << " Bytes" << endl;
|
||||
|
||||
// Round to word borders + tree_block size
|
||||
@ -45,7 +47,7 @@ void* TreeAllocator::alloc(uint32_t req_size) {
|
||||
}
|
||||
|
||||
// Finds smallest block that is large enough
|
||||
tree_block_t* best_fit = rbt_search_bestfit(rreq_size);
|
||||
tree_block_t *best_fit = rbt_search_bestfit(rreq_size);
|
||||
if (best_fit == nullptr) {
|
||||
log.error() << " - No block found" << endl;
|
||||
return nullptr;
|
||||
@ -66,7 +68,7 @@ void* TreeAllocator::alloc(uint32_t req_size) {
|
||||
tree_block_t dummy;
|
||||
dummy.allocated = false;
|
||||
rbt_insert(&dummy); // I use the address of the stack allocated struct because it is
|
||||
// removed before exiting the function
|
||||
// removed before exiting the function
|
||||
|
||||
rbt_remove(best_fit); // BUG: Can trigger bluescreen
|
||||
if (size > HEAP_MIN_FREE_BLOCK_SIZE + rreq_size + sizeof(list_block_t)) {
|
||||
@ -74,8 +76,9 @@ void* TreeAllocator::alloc(uint32_t req_size) {
|
||||
log.trace() << " - Allocating " << dec << rreq_size << " Bytes with cutting" << endl;
|
||||
|
||||
// [best_fit_start | sizeof(list_block_t) | rreq_size | new_block_start]
|
||||
tree_block_t* new_block
|
||||
= reinterpret_cast<tree_block_t*>(reinterpret_cast<char*>(best_fit) + sizeof(list_block_t) + rreq_size);
|
||||
tree_block_t *new_block
|
||||
= reinterpret_cast<tree_block_t *>(reinterpret_cast<char *>(best_fit) + sizeof(list_block_t) +
|
||||
rreq_size);
|
||||
new_block->allocated = false;
|
||||
dll_insert(best_fit, new_block);
|
||||
rbt_insert(new_block);
|
||||
@ -90,27 +93,27 @@ void* TreeAllocator::alloc(uint32_t req_size) {
|
||||
rbt_remove(&dummy);
|
||||
|
||||
log.trace() << " - Returned address " << hex
|
||||
<< reinterpret_cast<uint32_t>(reinterpret_cast<char*>(best_fit) + sizeof(list_block_t))
|
||||
<< reinterpret_cast<uint32_t>(reinterpret_cast<char *>(best_fit) + sizeof(list_block_t))
|
||||
<< endl;
|
||||
return reinterpret_cast<void*>(reinterpret_cast<char*>(best_fit) + sizeof(list_block_t));
|
||||
return reinterpret_cast<void *>(reinterpret_cast<char *>(best_fit) + sizeof(list_block_t));
|
||||
}
|
||||
|
||||
void TreeAllocator::free(void* ptr) {
|
||||
void TreeAllocator::free(void *ptr) {
|
||||
log.info() << "Freeing " << hex << reinterpret_cast<uint32_t>(ptr) << endl;
|
||||
|
||||
list_block_t* block = reinterpret_cast<list_block_t*>(reinterpret_cast<char*>(ptr) - sizeof(list_block_t));
|
||||
list_block_t *block = reinterpret_cast<list_block_t *>(reinterpret_cast<char *>(ptr) - sizeof(list_block_t));
|
||||
if (!block->allocated) {
|
||||
// Block already free
|
||||
return;
|
||||
}
|
||||
block->allocated = false; // If the block is merged backwards afterwards this is unnecessary
|
||||
|
||||
list_block_t* previous = block->previous;
|
||||
list_block_t* next = block->next;
|
||||
list_block_t *previous = block->previous;
|
||||
list_block_t *next = block->next;
|
||||
|
||||
if (next->allocated && previous->allocated) {
|
||||
// No merge
|
||||
rbt_insert(reinterpret_cast<tree_block_t*>(block));
|
||||
rbt_insert(reinterpret_cast<tree_block_t *>(block));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -125,10 +128,11 @@ void TreeAllocator::free(void* ptr) {
|
||||
|
||||
// Remove the next block from all lists as it is now part of our freed block
|
||||
dll_remove(next);
|
||||
rbt_remove(reinterpret_cast<tree_block_t*>(next)); // BUG: Bluescreen if next is the only block in the freelist
|
||||
rbt_remove(
|
||||
reinterpret_cast<tree_block_t *>(next)); // BUG: Bluescreen if next is the only block in the freelist
|
||||
if (previous->allocated) {
|
||||
// Don't insert if removed later because of backward merge
|
||||
rbt_insert(reinterpret_cast<tree_block_t*>(block));
|
||||
rbt_insert(reinterpret_cast<tree_block_t *>(block));
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,15 +143,15 @@ void TreeAllocator::free(void* ptr) {
|
||||
// Remove the current block from all lists as it is now part of the previous block
|
||||
// It doesn't have to be removed from rbt as it wasn't in there as it was allocated before
|
||||
dll_remove(block);
|
||||
rbt_remove(reinterpret_cast<tree_block_t*>(previous));
|
||||
rbt_insert(reinterpret_cast<tree_block_t*>(previous)); // Reinsert with new size
|
||||
rbt_remove(reinterpret_cast<tree_block_t *>(previous));
|
||||
rbt_insert(reinterpret_cast<tree_block_t *>(previous)); // Reinsert with new size
|
||||
}
|
||||
|
||||
// HACK: Same as when allocating
|
||||
rbt_remove(&dummy);
|
||||
}
|
||||
|
||||
uint32_t TreeAllocator::get_size(list_block_t* block) const {
|
||||
uint32_t TreeAllocator::get_size(list_block_t *block) const {
|
||||
if (block->next == block) {
|
||||
// Only one block exists
|
||||
return heap_end - (reinterpret_cast<uint32_t>(block) + sizeof(list_block_t));
|
||||
@ -155,9 +159,12 @@ uint32_t TreeAllocator::get_size(list_block_t* block) const {
|
||||
|
||||
if (reinterpret_cast<uint32_t>(block->next) > reinterpret_cast<unsigned int>(block)) {
|
||||
// Next block is placed later in memory
|
||||
return reinterpret_cast<unsigned int>(block->next) - (reinterpret_cast<unsigned int>(block) + sizeof(list_block_t));
|
||||
return reinterpret_cast<unsigned int>(block->next) -
|
||||
(reinterpret_cast<unsigned int>(block) + sizeof(list_block_t));
|
||||
}
|
||||
|
||||
// Next block is placed earlier in memory which means block is at memory end
|
||||
return reinterpret_cast<unsigned int>(heap_end) - (reinterpret_cast<unsigned int>(block) + sizeof(list_block_t));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,15 +2,17 @@
|
||||
#define TreeAllocator_include__
|
||||
|
||||
#include "Allocator.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// I can't imagine that this is fast with all the tree logic?
|
||||
|
||||
typedef struct list_block {
|
||||
// Doubly linked list for every block
|
||||
bool allocated;
|
||||
struct list_block* next;
|
||||
struct list_block* previous;
|
||||
struct list_block *next;
|
||||
struct list_block *previous;
|
||||
} list_block_t;
|
||||
|
||||
// The free blocks are organized in a red-black tree to enable fast insertion with best-fit strategy.
|
||||
@ -22,60 +24,75 @@ typedef struct tree_block {
|
||||
// Doubly linked list for every block
|
||||
// Locate this at the beginning so we can just cast to allocated_block_t and overwrite the rbt data
|
||||
bool allocated;
|
||||
struct list_block* next;
|
||||
struct list_block* previous;
|
||||
struct list_block *next;
|
||||
struct list_block *previous;
|
||||
// RB tree for free blocks
|
||||
struct tree_block* left;
|
||||
struct tree_block* right;
|
||||
struct tree_block* parent;
|
||||
struct tree_block *left;
|
||||
struct tree_block *right;
|
||||
struct tree_block *parent;
|
||||
bool red; // RB tree node color
|
||||
} tree_block_t;
|
||||
|
||||
class TreeAllocator : Allocator {
|
||||
private:
|
||||
// Root of the rbt
|
||||
tree_block_t* free_start;
|
||||
tree_block_t *free_start;
|
||||
|
||||
NamedLogger log;
|
||||
|
||||
// Returns the size of the usable memory of a block
|
||||
uint32_t get_size(list_block_t* block) const;
|
||||
uint32_t get_size(tree_block_t* block) const { return get_size(reinterpret_cast<list_block_t*>(block)); }
|
||||
uint32_t get_size(list_block_t *block) const;
|
||||
|
||||
void dump_free_memory(tree_block_t* node);
|
||||
uint32_t get_size(tree_block_t *block) const { return get_size(reinterpret_cast<list_block_t *>(block)); }
|
||||
|
||||
void dump_free_memory(tree_block_t *node);
|
||||
|
||||
// NOTE: Would be nice to have this stuff somewhere else for general use (scheduling?),
|
||||
// makes no sense to have this as members. I'll move it later
|
||||
void rbt_rot_l(tree_block_t* x);
|
||||
void rbt_rot_r(tree_block_t* x);
|
||||
void rbt_transplant(tree_block_t* a, tree_block_t* b);
|
||||
tree_block_t* rbt_minimum(tree_block_t* node);
|
||||
void rbt_rot_l(tree_block_t *x);
|
||||
|
||||
void rbt_insert(tree_block_t* node);
|
||||
void rbt_fix_insert(tree_block_t* k);
|
||||
void rbt_remove(tree_block_t* z);
|
||||
void rbt_fix_remove(tree_block_t* x);
|
||||
void rbt_rot_r(tree_block_t *x);
|
||||
|
||||
tree_block_t* rbt_search_bestfit(tree_block_t* node, uint32_t req_size);
|
||||
tree_block_t* rbt_search_bestfit(uint32_t req_size) { return rbt_search_bestfit(free_start, req_size); }
|
||||
void rbt_transplant(tree_block_t *a, tree_block_t *b);
|
||||
|
||||
void dll_insert(list_block_t* previous, list_block_t* node);
|
||||
void dll_insert(tree_block_t* previous, tree_block_t* node) {
|
||||
dll_insert(reinterpret_cast<list_block_t*>(previous), reinterpret_cast<list_block_t*>(node));
|
||||
tree_block_t *rbt_minimum(tree_block_t *node);
|
||||
|
||||
void rbt_insert(tree_block_t *node);
|
||||
|
||||
void rbt_fix_insert(tree_block_t *k);
|
||||
|
||||
void rbt_remove(tree_block_t *z);
|
||||
|
||||
void rbt_fix_remove(tree_block_t *x);
|
||||
|
||||
tree_block_t *rbt_search_bestfit(tree_block_t *node, uint32_t req_size);
|
||||
|
||||
tree_block_t *rbt_search_bestfit(uint32_t req_size) { return rbt_search_bestfit(free_start, req_size); }
|
||||
|
||||
void dll_insert(list_block_t *previous, list_block_t *node);
|
||||
|
||||
void dll_insert(tree_block_t *previous, tree_block_t *node) {
|
||||
dll_insert(reinterpret_cast<list_block_t *>(previous), reinterpret_cast<list_block_t *>(node));
|
||||
}
|
||||
void dll_remove(list_block_t* node);
|
||||
|
||||
void dll_remove(list_block_t *node);
|
||||
|
||||
public:
|
||||
TreeAllocator(Allocator& copy) = delete; // Verhindere Kopieren
|
||||
TreeAllocator(Allocator ©) = delete; // Verhindere Kopieren
|
||||
|
||||
TreeAllocator() : log("RBT-Alloc") {};
|
||||
|
||||
// ~TreeAllocator() override = default;
|
||||
|
||||
void init() override;
|
||||
|
||||
void dump_free_memory() override;
|
||||
void* alloc(uint32_t req_size) override;
|
||||
void free(void* ptr) override;
|
||||
|
||||
void *alloc(uint32_t req_size) override;
|
||||
|
||||
void free(void *ptr) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -2,8 +2,10 @@
|
||||
|
||||
// RBT code taken from https://github.com/Bibeknam/algorithmtutorprograms
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// START copy from algorithmtutorprograms
|
||||
void TreeAllocator::rbt_transplant(tree_block_t* a, tree_block_t* b) {
|
||||
void TreeAllocator::rbt_transplant(tree_block_t *a, tree_block_t *b) {
|
||||
if (a->parent == nullptr) {
|
||||
free_start = b;
|
||||
} else if (a == a->parent->left) {
|
||||
@ -16,15 +18,15 @@ void TreeAllocator::rbt_transplant(tree_block_t* a, tree_block_t* b) {
|
||||
|
||||
// insert the key to the tree in its appropriate position
|
||||
// and fix the tree
|
||||
void TreeAllocator::rbt_insert(tree_block_t* node) {
|
||||
void TreeAllocator::rbt_insert(tree_block_t *node) {
|
||||
// Ordinary Binary Search Insertion
|
||||
node->parent = nullptr;
|
||||
node->left = nullptr;
|
||||
node->right = nullptr;
|
||||
node->red = true; // new node must be red
|
||||
|
||||
tree_block_t* y = nullptr;
|
||||
tree_block_t* x = free_start;
|
||||
tree_block_t *y = nullptr;
|
||||
tree_block_t *x = free_start;
|
||||
|
||||
while (x != nullptr) {
|
||||
y = x;
|
||||
@ -61,8 +63,8 @@ void TreeAllocator::rbt_insert(tree_block_t* node) {
|
||||
}
|
||||
|
||||
// fix the red-black tree
|
||||
void TreeAllocator::rbt_fix_insert(tree_block_t* k) {
|
||||
tree_block_t* u;
|
||||
void TreeAllocator::rbt_fix_insert(tree_block_t *k) {
|
||||
tree_block_t *u;
|
||||
while (k->parent->red) {
|
||||
if (k->parent == k->parent->parent->right) {
|
||||
u = k->parent->parent->left; // uncle
|
||||
@ -112,8 +114,8 @@ void TreeAllocator::rbt_fix_insert(tree_block_t* k) {
|
||||
}
|
||||
|
||||
// rotate left at node x
|
||||
void TreeAllocator::rbt_rot_l(tree_block_t* x) {
|
||||
tree_block_t* y = x->right;
|
||||
void TreeAllocator::rbt_rot_l(tree_block_t *x) {
|
||||
tree_block_t *y = x->right;
|
||||
x->right = y->left;
|
||||
if (y->left != nullptr) {
|
||||
y->left->parent = x;
|
||||
@ -131,8 +133,8 @@ void TreeAllocator::rbt_rot_l(tree_block_t* x) {
|
||||
}
|
||||
|
||||
// rotate right at node x
|
||||
void TreeAllocator::rbt_rot_r(tree_block_t* x) {
|
||||
tree_block_t* y = x->left;
|
||||
void TreeAllocator::rbt_rot_r(tree_block_t *x) {
|
||||
tree_block_t *y = x->left;
|
||||
x->left = y->right;
|
||||
if (y->right != nullptr) {
|
||||
y->right->parent = x;
|
||||
@ -150,16 +152,16 @@ void TreeAllocator::rbt_rot_r(tree_block_t* x) {
|
||||
}
|
||||
|
||||
// find the node with the minimum key
|
||||
tree_block_t* TreeAllocator::rbt_minimum(tree_block_t* node) {
|
||||
tree_block_t *TreeAllocator::rbt_minimum(tree_block_t *node) {
|
||||
while (node->left != nullptr) {
|
||||
node = node->left;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void TreeAllocator::rbt_remove(tree_block_t* z) {
|
||||
tree_block_t* x;
|
||||
tree_block_t* y;
|
||||
void TreeAllocator::rbt_remove(tree_block_t *z) {
|
||||
tree_block_t *x;
|
||||
tree_block_t *y;
|
||||
|
||||
y = z;
|
||||
bool y_original_red = y->red;
|
||||
@ -192,8 +194,8 @@ void TreeAllocator::rbt_remove(tree_block_t* z) {
|
||||
}
|
||||
|
||||
// fix the rb tree modified by the delete operation
|
||||
void TreeAllocator::rbt_fix_remove(tree_block_t* x) {
|
||||
tree_block_t* s;
|
||||
void TreeAllocator::rbt_fix_remove(tree_block_t *x) {
|
||||
tree_block_t *s;
|
||||
while (x != free_start && !x->red) {
|
||||
if (x == x->parent->left) {
|
||||
s = x->parent->right;
|
||||
@ -262,7 +264,7 @@ void TreeAllocator::rbt_fix_remove(tree_block_t* x) {
|
||||
// END copy from algorithmtutorprograms
|
||||
|
||||
// This is recursive and depends on luck
|
||||
tree_block_t* TreeAllocator::rbt_search_bestfit(tree_block_t* node, uint32_t req_size) {
|
||||
tree_block_t *TreeAllocator::rbt_search_bestfit(tree_block_t *node, uint32_t req_size) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -289,14 +291,16 @@ tree_block_t* TreeAllocator::rbt_search_bestfit(tree_block_t* node, uint32_t req
|
||||
}
|
||||
|
||||
// DLL code
|
||||
void TreeAllocator::dll_insert(list_block_t* previous, list_block_t* node) {
|
||||
void TreeAllocator::dll_insert(list_block_t *previous, list_block_t *node) {
|
||||
previous->next->previous = node;
|
||||
node->next = previous->next;
|
||||
node->previous = previous;
|
||||
previous->next = node;
|
||||
}
|
||||
|
||||
void TreeAllocator::dll_remove(list_block_t* node) {
|
||||
void TreeAllocator::dll_remove(list_block_t *node) {
|
||||
node->previous->next = node->next;
|
||||
node->next->previous = node->previous;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,9 +14,11 @@
|
||||
#include "kernel/system/Globals.h"
|
||||
#include "Thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class IdleThread : public Thread {
|
||||
public:
|
||||
IdleThread(const Thread& copy) = delete; // Verhindere Kopieren
|
||||
IdleThread(const Thread ©) = delete; // Verhindere Kopieren
|
||||
|
||||
IdleThread() : Thread("IdleThread") {}
|
||||
|
||||
@ -29,10 +31,12 @@ public:
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// kout << "Idle!" << endl;
|
||||
// Kernel::kout << "Idle!" << endl;
|
||||
scheduler.yield();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
#include "IdleThread.h"
|
||||
#include <utility>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr const bool INSANE_TRACE = false;
|
||||
|
||||
/*****************************************************************************
|
||||
@ -35,7 +37,7 @@ constexpr const bool INSANE_TRACE = false;
|
||||
* Parameter: *
|
||||
* next Thread der die CPU::erhalten soll. *
|
||||
*****************************************************************************/
|
||||
void Scheduler::start(bse::vector<bse::unique_ptr<Thread>>::iterator next) {
|
||||
void Scheduler::start(Container::vector<Memory::unique_ptr<Thread>>::iterator next) {
|
||||
active = next;
|
||||
if (active >= ready_queue.end()) {
|
||||
active = ready_queue.begin();
|
||||
@ -47,7 +49,7 @@ void Scheduler::start(bse::vector<bse::unique_ptr<Thread>>::iterator next) {
|
||||
(*active)->start(); // First dereference the Iterator, then the unique_ptr to get Thread
|
||||
}
|
||||
|
||||
void Scheduler::switch_to(Thread* prev_raw, bse::vector<bse::unique_ptr<Thread>>::iterator next) {
|
||||
void Scheduler::switch_to(Thread *prev_raw, Container::vector<Memory::unique_ptr<Thread>>::iterator next) {
|
||||
active = next;
|
||||
if (active >= ready_queue.end()) {
|
||||
active = ready_queue.begin();
|
||||
@ -73,7 +75,7 @@ void Scheduler::schedule() {
|
||||
// Otherwise preemption will be blocked and nothing will happen if the first threads
|
||||
// run() function is blocking
|
||||
|
||||
ready_queue.push_back(bse::make_unique<IdleThread>());
|
||||
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);
|
||||
}
|
||||
@ -83,11 +85,11 @@ void Scheduler::schedule() {
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Thread in readyQueue eintragen. *
|
||||
*****************************************************************************/
|
||||
void Scheduler::ready(bse::unique_ptr<Thread>&& thread) {
|
||||
CPU::disable_int();
|
||||
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));
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -103,18 +105,18 @@ void Scheduler::exit() {
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
// Thread-Wechsel durch PIT verhindern
|
||||
CPU::disable_int();
|
||||
Device::CPU::disable_int();
|
||||
|
||||
if (ready_queue.size() == 1) {
|
||||
log.error() << "Can't exit last thread, active ID: " << dec << (*active)->tid << endl;
|
||||
CPU::enable_int();
|
||||
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)
|
||||
// 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
|
||||
@ -131,19 +133,19 @@ void Scheduler::exit() {
|
||||
* Parameter: *
|
||||
* that Zu terminierender Thread *
|
||||
*****************************************************************************/
|
||||
void Scheduler::kill(uint32_t tid, bse::unique_ptr<Thread>* ptr) {
|
||||
CPU::disable_int();
|
||||
void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
uint32_t prev_tid = (*active)->tid;
|
||||
|
||||
// Block queue, can always kill
|
||||
for (bse::vector<bse::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
||||
for (Container::vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
||||
if ((*it)->tid == tid) {
|
||||
// Found thread to kill
|
||||
|
||||
if (ptr != nullptr) {
|
||||
// Move old thread out of queue to return it
|
||||
uint32_t pos = bse::distance(block_queue.begin(), it);
|
||||
uint32_t pos = distance(block_queue.begin(), it);
|
||||
*ptr = std::move(block_queue[pos]); // Return the killed thread
|
||||
}
|
||||
|
||||
@ -151,7 +153,7 @@ void Scheduler::kill(uint32_t tid, bse::unique_ptr<Thread>* ptr) {
|
||||
block_queue.erase(it);
|
||||
log.info() << "Killed thread from block_queue with id: " << tid << endl;
|
||||
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -159,17 +161,17 @@ void Scheduler::kill(uint32_t tid, bse::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;
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
|
||||
for (bse::vector<bse::unique_ptr<Thread>>::iterator it = ready_queue.begin(); it != ready_queue.end(); ++it) {
|
||||
for (Container::vector<Memory::unique_ptr<Thread>>::iterator it = ready_queue.begin(); it != ready_queue.end(); ++it) {
|
||||
if ((*it)->tid == tid) {
|
||||
// Found thread to kill
|
||||
|
||||
if (ptr != nullptr) {
|
||||
// Move old thread out of queue to return it
|
||||
uint32_t pos = bse::distance(ready_queue.begin(), it);
|
||||
uint32_t pos = distance(ready_queue.begin(), it);
|
||||
*ptr = std::move(ready_queue[pos]); // Return the killed thread
|
||||
}
|
||||
|
||||
@ -185,43 +187,43 @@ void Scheduler::kill(uint32_t tid, bse::unique_ptr<Thread>* ptr) {
|
||||
ready_queue.erase(it);
|
||||
log.info() << "Killed thread from ready_queue with id: " << tid << endl;
|
||||
|
||||
CPU::enable_int();
|
||||
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;
|
||||
CPU::enable_int();
|
||||
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, bse::unique_ptr<Thread>* ptr) {
|
||||
CPU::disable_int();
|
||||
void Scheduler::nice_kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
||||
Device::CPU::disable_int();
|
||||
|
||||
for (bse::unique_ptr<Thread>& thread : block_queue) {
|
||||
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);
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (bse::unique_ptr<Thread>& thread : ready_queue) {
|
||||
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;
|
||||
CPU::enable_int();
|
||||
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;
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -240,13 +242,13 @@ void Scheduler::yield() {
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
// Thread-Wechsel durch PIT verhindern
|
||||
CPU::disable_int();
|
||||
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;
|
||||
}
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
if constexpr (INSANE_TRACE) {
|
||||
@ -266,7 +268,7 @@ void Scheduler::preempt() {
|
||||
|
||||
/* Hier muss Code eingefuegt werden */
|
||||
|
||||
CPU::disable_int();
|
||||
Device::CPU::disable_int();
|
||||
yield();
|
||||
}
|
||||
|
||||
@ -284,16 +286,16 @@ void Scheduler::block() {
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
CPU::disable_int();
|
||||
Device::CPU::disable_int();
|
||||
|
||||
if (ready_queue.size() == 1) {
|
||||
log.error() << "Can't block last thread, active ID: " << dec << (*active)->tid << endl;
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
|
||||
Thread* prev_raw = (*active).get();
|
||||
std::size_t pos = bse::distance(ready_queue.begin(), active);
|
||||
Thread *prev_raw = (*active).get();
|
||||
std::size_t pos = distance(ready_queue.begin(), active);
|
||||
block_queue.push_back(std::move(ready_queue[pos]));
|
||||
|
||||
if constexpr (INSANE_TRACE) {
|
||||
@ -318,24 +320,26 @@ void Scheduler::deblock(uint32_t tid) {
|
||||
|
||||
/* hier muss Code eingefuegt werden */
|
||||
|
||||
CPU::disable_int();
|
||||
Device::CPU::disable_int();
|
||||
|
||||
for (bse::vector<bse::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
||||
for (Container::vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
||||
if ((*it)->tid == tid) {
|
||||
// Found thread with correct tid
|
||||
|
||||
std::size_t pos = bse::distance(block_queue.begin(), it);
|
||||
std::size_t pos = distance(block_queue.begin(), it);
|
||||
ready_queue.insert(active + 1, std::move(block_queue[pos])); // We insert the thread after the active
|
||||
// thread to prefer deblocked threads
|
||||
// thread to prefer deblocked threads
|
||||
block_queue.erase(it);
|
||||
if constexpr (INSANE_TRACE) {
|
||||
log.trace() << "Deblocked thread with id: " << tid << endl;
|
||||
}
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.error() << "Couldn't deblock thread with id: " << tid << endl;
|
||||
CPU::enable_int();
|
||||
Device::CPU::enable_int();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,36 +14,39 @@
|
||||
|
||||
#include "Thread.h"
|
||||
#include "lib/mem/UniquePointer.h"
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/util/Vector.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
#include "lib/container/Vector.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class Scheduler {
|
||||
private:
|
||||
NamedLogger log;
|
||||
|
||||
bse::vector<bse::unique_ptr<Thread>> ready_queue;
|
||||
bse::vector<bse::unique_ptr<Thread>> block_queue;
|
||||
Container::vector<Memory::unique_ptr<Thread>> ready_queue;
|
||||
Container::vector<Memory::unique_ptr<Thread>> block_queue;
|
||||
|
||||
// NOTE: 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
|
||||
bse::vector<bse::unique_ptr<Thread>>::iterator active = nullptr;
|
||||
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 = 0U;
|
||||
|
||||
// Roughly the old dispatcher functionality
|
||||
void start(bse::vector<bse::unique_ptr<Thread>>::iterator next); // Start next without prev
|
||||
void switch_to(Thread* prev_raw, bse::vector<bse::unique_ptr<Thread>>::iterator next); // Switch from prev to next
|
||||
void start(Container::vector<Memory::unique_ptr<Thread>>::iterator next); // Start next without prev
|
||||
void switch_to(Thread *prev_raw, Container::vector<Memory::unique_ptr<Thread>>::iterator next); // Switch from prev to next
|
||||
|
||||
// Kann nur vom Idle-Thread aufgerufen werden (erster Thread der vom Scheduler gestartet wird)
|
||||
void enable_preemption(uint32_t tid) { idle_tid = tid; }
|
||||
|
||||
friend class IdleThread;
|
||||
|
||||
void ready(bse::unique_ptr<Thread>&& thread);
|
||||
void ready(Memory::unique_ptr<Thread> &&thread);
|
||||
|
||||
public:
|
||||
Scheduler(const Scheduler& copy) = delete; // Verhindere Kopieren
|
||||
Scheduler(const Scheduler ©) = delete; // Verhindere Kopieren
|
||||
|
||||
Scheduler() : log("SCHED"), ready_queue(true), block_queue(true) {} // lazy queues, wait for allocator
|
||||
|
||||
@ -68,7 +71,7 @@ public:
|
||||
// Helper that directly constructs the thread, then readys it
|
||||
template<typename T, typename... Args>
|
||||
uint32_t ready(Args... args) {
|
||||
bse::unique_ptr<Thread> thread = bse::make_unique<T>(std::forward<Args>(args)...);
|
||||
Memory::unique_ptr<Thread> thread = Memory::make_unique<T>(std::forward<Args>(args)...);
|
||||
uint32_t tid = thread->tid;
|
||||
|
||||
ready(std::move(thread));
|
||||
@ -83,14 +86,16 @@ public:
|
||||
void exit(); // Returns on error because we don't have exceptions
|
||||
|
||||
// Thread mit 'Gewalt' terminieren
|
||||
void kill(uint32_t tid, bse::unique_ptr<Thread>* ptr);
|
||||
void kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
|
||||
void kill(uint32_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, bse::unique_ptr<Thread>* ptr);
|
||||
void nice_kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr);
|
||||
|
||||
void nice_kill(uint32_t tid) { nice_kill(tid, nullptr); }
|
||||
|
||||
// CPU freiwillig abgeben und Auswahl des naechsten Threads
|
||||
@ -106,4 +111,6 @@ public:
|
||||
void deblock(uint32_t tid);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -26,13 +26,15 @@
|
||||
// extern "C" deklariert werden, da sie nicht dem Name-Mangeling von C++
|
||||
// entsprechen.
|
||||
extern "C" {
|
||||
void Thread_start(uint32_t esp);
|
||||
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
|
||||
void Thread_switch(uint32_t* esp_prev, uint32_t esp_next);
|
||||
// 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
|
||||
|
||||
/*****************************************************************************
|
||||
@ -41,7 +43,7 @@ uint32_t ThreadCnt = 1; // Skip tid 0 as the scheduler indicates no preemption
|
||||
* Beschreibung: Bereitet den Kontext der Koroutine fuer den ersten *
|
||||
* Aufruf vor. *
|
||||
*****************************************************************************/
|
||||
void Thread_init(uint32_t* esp, uint32_t* stack, void (*kickoff)(Thread*), void* object) {
|
||||
void Thread_init(uint32_t *esp, uint32_t *stack, void (*kickoff)(Thread *), void *object) {
|
||||
|
||||
// NOTE: c++17 doesn't allow register
|
||||
// register uint32_t** sp = (uint32_t**)stack;
|
||||
@ -82,7 +84,7 @@ void Thread_init(uint32_t* esp, uint32_t* stack, void (*kickoff)(Thread*), void*
|
||||
* wuerde ein sinnloser Wert als Ruecksprungadresse *
|
||||
* interpretiert werden und der Rechner abstuerzen. *
|
||||
*****************************************************************************/
|
||||
[[noreturn]] void kickoff(Thread* object) {
|
||||
[[noreturn]] void kickoff(Thread *object) {
|
||||
object->run();
|
||||
|
||||
// object->run() kehrt (hoffentlich) nie hierher zurueck
|
||||
@ -97,7 +99,7 @@ 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(char *name) : stack(new uint32_t[1024]), esp(0), log(name), name(name), tid(ThreadCnt++) {
|
||||
if (stack == nullptr) {
|
||||
log.error() << "Couldn't initialize Thread (couldn't alloc stack)" << endl;
|
||||
return;
|
||||
@ -112,7 +114,7 @@ Thread::Thread(char* name) : stack(new uint32_t[1024]), esp(0), log(name), name(
|
||||
*---------------------------------------------------------------------------*
|
||||
* Beschreibung: Auf die nächste Koroutine umschalten. *
|
||||
*****************************************************************************/
|
||||
void Thread::switchTo(Thread& next) {
|
||||
void Thread::switchTo(Thread &next) {
|
||||
|
||||
/* hier muss Code eingefügt werden */
|
||||
|
||||
@ -131,3 +133,5 @@ void Thread::start() const {
|
||||
|
||||
Thread_start(esp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -28,25 +28,27 @@
|
||||
#ifndef Thread_include__
|
||||
#define Thread_include__
|
||||
|
||||
#include "kernel/log/Logger.h"
|
||||
#include "lib/stream/Logger.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class Thread {
|
||||
private:
|
||||
uint32_t* stack;
|
||||
uint32_t *stack;
|
||||
uint32_t esp;
|
||||
|
||||
protected:
|
||||
Thread(char* name);
|
||||
Thread(char *name);
|
||||
|
||||
NamedLogger log;
|
||||
|
||||
bool running = true; // For soft exit, if thread uses infinite loop inside run(), use this as condition
|
||||
char* name; // For logging
|
||||
char *name; // For logging
|
||||
uint32_t tid; // Thread-ID (wird im Konstruktor vergeben)
|
||||
friend class Scheduler; // Scheduler can access tid
|
||||
|
||||
public:
|
||||
Thread(const Thread& copy) = delete; // Verhindere Kopieren
|
||||
Thread(const Thread ©) = delete; // Verhindere Kopieren
|
||||
|
||||
virtual ~Thread() {
|
||||
log.info() << "Uninitialized thread, ID: " << dec << tid << " (" << name << ")" << endl;
|
||||
@ -57,7 +59,7 @@ public:
|
||||
void start() const;
|
||||
|
||||
// Umschalten auf Thread 'next'
|
||||
void switchTo(Thread& next);
|
||||
void switchTo(Thread &next);
|
||||
|
||||
// Ask thread to terminate itself
|
||||
void suicide() { running = false; }
|
||||
@ -66,4 +68,6 @@ public:
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -10,15 +10,17 @@
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
CGA_Stream kout; // Ausgabe-Strom fuer Kernel
|
||||
const BIOS& bios = BIOS::instance(); // Schnittstelle zum 16-Bit BIOS
|
||||
VESA vesa; // VESA-Treiber
|
||||
namespace Kernel {
|
||||
|
||||
PIC pic; // Interrupt-Controller
|
||||
CGA_Stream kout; // Ausgabe-Strom fuer Kernel
|
||||
const Device::BIOS &bios = Device::BIOS::instance(); // Schnittstelle zum 16-Bit BIOS
|
||||
Device::VESA vesa; // VESA-Treiber
|
||||
|
||||
Device::PIC pic; // Interrupt-Controller
|
||||
IntDispatcher intdis; // Unterbrechungsverteilung
|
||||
PIT pit(10000); // 10000
|
||||
PCSPK pcspk; // PC-Lautsprecher
|
||||
Keyboard kb; // Tastatur
|
||||
Device::PIT pit(10000); // 10000
|
||||
Device::PCSPK pcspk; // PC-Lautsprecher
|
||||
Device::Keyboard kb; // Tastatur
|
||||
|
||||
// BumpAllocator allocator;
|
||||
LinkedListAllocator allocator;
|
||||
@ -27,7 +29,9 @@ LinkedListAllocator allocator;
|
||||
Scheduler scheduler;
|
||||
|
||||
KeyEventManager kevman;
|
||||
SerialOut serial;
|
||||
Device::SerialOut serial;
|
||||
|
||||
unsigned int total_mem; // RAM total
|
||||
uint64_t systime = 0;
|
||||
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#ifndef Globals_include__
|
||||
#define Globals_include__
|
||||
|
||||
#include "device/graphics/CGA_Stream.h"
|
||||
#include "lib/stream/CGA_Stream.h"
|
||||
#include "device/hid/Keyboard.h"
|
||||
#include "device/sound/PCSPK.h"
|
||||
#include "device/time/PIT.h"
|
||||
@ -27,17 +27,19 @@
|
||||
#include "device/port/SerialOut.h"
|
||||
#include "kernel/event/KeyEventManager.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// I wanted to make more of these singletons but there were problems with atexit missing because of nostdlib I guess
|
||||
|
||||
extern CGA_Stream kout; // Ausgabe-Strom fuer Kernel
|
||||
extern const BIOS& bios; // Schnittstelle zum 16-Bit BIOS
|
||||
extern VESA vesa; // VESA-Treiber
|
||||
extern const Device::BIOS &bios; // Schnittstelle zum 16-Bit BIOS
|
||||
extern Device::VESA vesa; // VESA-Treiber
|
||||
|
||||
extern PIC pic; // Interrupt-Controller
|
||||
extern Device::PIC pic; // Interrupt-Controller
|
||||
extern IntDispatcher intdis; // Unterbrechungsverteilung
|
||||
extern PIT pit; // Zeitgeber
|
||||
extern PCSPK pcspk; // PC-Lautsprecher
|
||||
extern Keyboard kb; // Tastatur
|
||||
extern Device::PIT pit; // Zeitgeber
|
||||
extern Device::PCSPK pcspk; // PC-Lautsprecher
|
||||
extern Device::Keyboard kb; // Tastatur
|
||||
|
||||
// extern BumpAllocator allocator;
|
||||
extern LinkedListAllocator allocator;
|
||||
@ -46,9 +48,11 @@ extern LinkedListAllocator allocator;
|
||||
extern Scheduler scheduler;
|
||||
|
||||
extern KeyEventManager kevman;
|
||||
extern SerialOut serial;
|
||||
extern Device::SerialOut serial;
|
||||
|
||||
extern uint32_t total_mem; // RAM total
|
||||
extern uint64_t systime; // wird all 10ms hochgezaehlt
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user