Compare commits

..

37 Commits

Author SHA1 Message Date
Simon
6951311c9c foo 2025-07-14 16:46:33 +02:00
Simon
9d525a9602 hopefully added semaphores 2025-07-14 15:24:46 +02:00
Simon
42f2dd6028 fooo 2025-07-13 16:34:52 +02:00
Eggert Jung
68cb30210f :wq 2025-07-08 13:53:14 +02:00
Eggert Jung
370e76bfc4 Merge branch 'test2' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 into test2 2025-07-08 13:50:14 +02:00
Eggert Jung
fd021c98a7 more or less works (with kill) 2025-07-08 13:49:52 +02:00
Simon
5611b7f886 killing all bugs 2025-07-08 13:47:57 +02:00
Simon
c175c49945 works mostly 2025-07-08 13:46:02 +02:00
Simon
9023944e92 remove second timer 2025-07-08 13:33:01 +02:00
Eggert Jung
cc412f4902 test2 2025-07-08 02:40:29 +02:00
Simon
9ffd22e941 adding new vault sch 2025-07-08 01:25:50 +02:00
Simon
698d0c155b fixed scheduler in vault. insert borderline reference 2025-07-08 01:19:05 +02:00
Eggert Jung
68f0381c01 Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-07-08 01:14:30 +02:00
Eggert Jung
bc0a94b705 timer/scheduler working 2025-07-08 01:11:22 +02:00
Simon
2a7d1bdedc fixing typos 2025-07-08 00:40:33 +02:00
Eggert Jung
689c77f19e remove crap 2025-07-07 23:43:33 +02:00
Simon
38a10f2010 anfang aufgabe 5 und notizen 2025-06-27 15:49:07 +02:00
Simon
f5c42a8e77 notes 2025-06-25 17:36:46 +02:00
Eggert Jung
638aa9b636 5 applications running on 4 cores (qemu kvm)
maybe need to add more apps if hardware has more cores
2025-06-23 21:30:43 +02:00
Eggert Jung
7322a9ed70 schedule with 4 application 2025-06-23 21:27:57 +02:00
Eggert Jung
e6d6e7521c scheduler + 2 instances of application 2025-06-23 20:21:19 +02:00
Eggert Jung
da34f7cada fix stack usage and readylist 2025-06-23 14:55:08 +02:00
Eggert Jung
94249eda37 changes 2025-06-22 11:45:31 +02:00
Niklas Gollenstede
d9978ddc37 simplify Qeue, update some comments and include paths 2025-06-17 16:09:25 +02:00
Eggert Jung
68e11c9793 rumgedümpel 2025-06-17 15:58:08 +02:00
Eggert Jung
5b664840d8 progress on scheduler/dispatcher implementation 2025-06-17 15:41:56 +02:00
Eggert Jung
944d4991cb Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-06-17 14:19:42 +02:00
Eggert Jung
76eb2420bd thread implementation 2025-06-17 14:17:30 +02:00
Simon
b422ee176a foooo 2025-06-17 13:59:56 +02:00
Eggert Jung
c1145d28f8 context switching between two functions 2025-06-17 13:56:33 +02:00
Simon
ab76afa30a offset works now 2025-06-17 02:22:47 +02:00
Simon
3d659e0eab gooooo 2025-06-17 02:11:57 +02:00
Simon
e8ec76112b fooo 2025-06-17 01:16:52 +02:00
Eggert Jung
a0e2a59f96 test 2025-06-17 01:15:19 +02:00
Simon
24a0888760 fake fake is missing 2025-06-16 23:55:59 +02:00
Simon
f90eaa3fcd context switch seems to do stuff 2025-06-16 23:27:26 +02:00
Eggert Jung
a38b6cbdb2 vbl 2025-06-16 23:04:11 +02:00
29 changed files with 713 additions and 207 deletions

195
1 Normal file
View File

@@ -0,0 +1,195 @@
#include "arch/lapic.h"
#include "boot/startup_ap.h"
#include "arch/core_interrupt.h"
#include "debug/copystream.h"
#include "debug/output.h"
#include "debug/assert.h"
#include "arch/cga.h"
#include "arch/textwindow.h"
#include "arch/serial.h"
#include "device/serialstream.h"
#include "device/textstream.h"
#include "device/ps2controller.h"
#include "arch/ioapic.h"
#include "thread/scheduler.h"
#include "user/app1/appl.h"
#include "sync/ticketlock.h"
#include "interrupt/guard.h"
#include "arch/context.h"
#include "thread/thread.h"
///TextStream kout = TextStream(0, 80, 0, 10, true);
Ticketlock koutlock;
Scheduler sch;
//TextStream dout[8] = {
// TextStream(0 ,20,12,25,false),
// TextStream(20,40,12,25,false),
// TextStream(40,60,12,25,false),
// TextStream(60,80,12,25,false),
// TextStream(0 ,0 ,0, 0,false),
// TextStream(0 ,0 ,0, 0,false),
// TextStream(0 ,0 ,0, 0,false),
// TextStream(0 ,0 ,0, 0,false),
//};
TextStream dout[Core::MAX] = {
{0, 40, 10, 14},
{40, 80, 10, 14},
{0, 40, 14, 18},
{40, 80, 14, 18},
{0, 40, 18, 22},
{40, 80, 18, 22},
{0, 40, 22, 25},
{40, 80, 22, 25},
};
CopyStream copystream[Core::MAX]{
{&dout[0], &sout},
{&dout[1], &sout},
{&dout[2], &sout},
{&dout[3], &sout},
{&dout[4], &sout},
{&dout[5], &sout},
{&dout[6], &sout},
{&dout[7], &sout},
};
OutputStream* copyout[Core::MAX]{
&dout[0],
&copystream[1],
&dout[2],
&dout[3],
&dout[4],
&dout[5],
&dout[6],
&dout[7]
};
unsigned int testx, testy;
uint8_t test1_stack[1024];
uint8_t test2_stack[1024];
uint8_t test3_stack[1024];
uint8_t test4_stack[1024];
uint8_t test5_stack[1024];
uint8_t test6_stack[1024];
uint8_t test7_stack[1024];
uint8_t test8_stack[1024];
uint8_t test9_stack[1024];
//Thread test1_thread = Thread(&test1_stack[sizeof(test1_stack)-1]);
Application application1 = Application(&test1_stack[sizeof(test1_stack)-1]);
Application application2 = Application(&test2_stack[sizeof(test2_stack)-1]);
Application application3 = Application(&test3_stack[sizeof(test3_stack)-1]);
Application application4 = Application(&test4_stack[sizeof(test4_stack)-1]);
Application application5 = Application(&test5_stack[sizeof(test5_stack)-1]);
Application application6 = Application(&test6_stack[sizeof(test5_stack)-1]);
Application application7 = Application(&test7_stack[sizeof(test5_stack)-1]);
Application application8 = Application(&test8_stack[sizeof(test5_stack)-1]);
Application application9 = Application(&test9_stack[sizeof(test5_stack)-1]);
//Context test2;
//uint8_t test2_stack[256];
//Thread test2_thread = Thread(&test2_stack[sizeof(test2_stack)-1]);
//void test_func1(){
// while(1){
// {
// Guarded g = Guard::enter();
// g.vault().kout << "test 1\n" << flush;
// }
// context_switch(&test2, &test1);
// }
//}
//
//void test_func2(){
// while(1){
// {
// Guarded g = Guard::enter();
// g.vault().kout << "test 2\n" << flush;
// }
// context_switch(&test1, &test2);
// }
//}
// Main function
// (the bootstrap processor starts here)}
extern "C" int main() {
CGA::setCursor(0, 0);
unsigned int numCPUs = Core::count();
/* Start application processors
* To avoid unexpected behaviour, make sure that interrupts are not
* enabled before the APs are booted. Otherwise it might interfere with the
* Startup IPIs or even block devices like keyboard because of a missing EOI
*/
{
Guarded g = Guard::enter();
sch.ready(&application1);
sch.ready(&application2);
sch.ready(&application3);
sch.ready(&application4);
sch.ready(&application5);
sch.ready(&application6);
sch.ready(&application7);
sch.ready(&application8);
sch.ready(&application9);
}
ApplicationProcessor::boot();
PS2Controller::init();
IOAPIC::init();
IOAPIC::config(1, Core::Interrupt::KEYBOARD);
IOAPIC::allow(1);
Core::Interrupt::enable();
PS2Controller::drainBuffer();
DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush;
{
Guarded g = Guard::enter();
sch.schedule();
}
//Application{}.action();
while (true){
//DBG << "pos: " << testx << ", " << testy << endl << flush;
//Core::pause();
}
return 0;
}
// Main function for application processors
extern "C" int main_ap() {
DBG_VERBOSE << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC "
<< static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl;
Core::Interrupt::enable();
DBG << "App CPU " << static_cast<int>(Core::getID()) << endl << flush;
{
Guarded g = Guard::enter();
sch.schedule();
}
//assert(Core::getID() != 1);
//Application{}.action();
return 0;
}

View File

@@ -7,14 +7,30 @@
; and populates the registers from the the next context. ; and populates the registers from the the next context.
align 16 align 16
context_switch: context_switch:
mov [rsi + 0], rbx
mov [rsi + 8], rbp
mov [rsi + 16], r12
mov [rsi + 24], r13
mov [rsi + 32], r14
mov [rsi + 40], r15
mov [rsi + 48], rsp
; context_launch populates the register set from the next context structure. ; context_launch populates the register set from the next context structure.
; It does not save the current registers. ; It does not save the current registers.
align 16 ; When only one parameter is used for `align`, it will use NOP align 16 ; When only one parameter is used for `align`, it will use NOP
context_launch: context_launch:
mov rbx, [rdi + 0]
mov rbp, [rdi + 8]
mov r12, [rdi + 16]
mov r13, [rdi + 24]
mov r14, [rdi + 32]
mov r15, [rdi + 40]
mov rsp, [rdi + 48]
ret
; fake_systemv_abi is used to populate the volatile argument registers used by the systemv abi (rdi, rsi, ...) ; fake_systemv_abi is used to populate the volatile argument registers used by the systemv abi (rdi, rsi, ...)
; with values from the non-volatile registers saved within the thread context (r15, r14, ...) ; with values from the non-volatile registers saved within the thread context (r15, r14, ...)
align 16 align 16
fake_systemv_abi: fake_systemv_abi:
mov rdi, r15
mov rsi, r14
ret

View File

@@ -1,9 +1,21 @@
#include "context.h" #include "context.h"
#include "../debug/output.h"
void panic(){
DBG << "panic!\n" << flush;
while(1);
}
void prepareContext(void* tos, Context& context, void (*kickoff)(void*), void prepareContext(void* tos, Context& context, void (*kickoff)(void*),
void* param1) { void* param1) {
(void)tos; ((uint64_t*)tos)[0] = (uint64_t)panic;
(void)context; ((uint64_t*)tos)[-1] = (uint64_t)kickoff;
(void)kickoff; ((uint64_t*)tos)[-2] = (uint64_t)fake_systemv_abi;
(void)param1; context.rsp = (void*)(((uint64_t) tos)-16);
context.rbx = 0;
context.rbp = 0;
context.r12 = 0;
context.r13 = 0;
context.r14 = 0;
context.r15 = (uint64_t)param1;
} }

View File

@@ -68,7 +68,9 @@ enum Vector {
// Interrupts // Interrupts
KEYBOARD=32, KEYBOARD=32,
PANIC=33 PANIC=33,
TIMER=34,
ASSASSIN=35
}; };
constexpr size_t VECTORS = 256; constexpr size_t VECTORS = 256;

View File

@@ -156,7 +156,7 @@ void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
* *
* Initializes the \ref LAPIC::Timer * Initializes the \ref LAPIC::Timer
* in such a way that regular interrupts are triggered approx. every `us` * in such a way that regular interrupts are triggered approx. every `us`
* microseconds when \ref LAPIC::Timer:::activate() is called. * microseconds when \ref LAPIC::Timer::activate() is called.
* For this purpose, a suitable timer divisor is determined * For this purpose, a suitable timer divisor is determined
* based on the timer frequency determined with \ref LAPIC::Timer::ticks(). * based on the timer frequency determined with \ref LAPIC::Timer::ticks().
* This timer divisor has to be as small as possible, but large enough to * This timer divisor has to be as small as possible, but large enough to

View File

@@ -1,5 +1,9 @@
#include "lapic.h" #include "lapic.h"
#include "lapic_registers.h" #include "lapic_registers.h"
#include "core.h"
#include "pit.h"
#include "../debug/output.h"
namespace LAPIC { namespace LAPIC {
namespace Timer { namespace Timer {
@@ -56,36 +60,120 @@ static const Register div_masks[] = {
* \param div Divider, must be power of two: 1, 2, 4, 8, 16, 32, 64, 128 * \param div Divider, must be power of two: 1, 2, 4, 8, 16, 32, 64, 128
* \return Bit mask for LAPIC::setTimer() or `0xff` if `div` is invalid. * \return Bit mask for LAPIC::setTimer() or `0xff` if `div` is invalid.
*/ */
Register getClockDiv(uint8_t div) { static Register getClockDiv(uint8_t div) {
(void)div; switch (div) {
return 0; case 1: return div_masks[0];
case 2: return div_masks[1];
case 4: return div_masks[2];
case 8: return div_masks[3];
case 16: return div_masks[4];
case 32: return div_masks[5];
case 64: return div_masks[6];
case 128: return div_masks[7];
default : return 0xff;
}
}
/*! \brief Calculate the LAPIC-timer divider for the bit mask.
* \param div_mask The bit mask, must be one of: 0xb, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa
* \return LAPIC-timer divider or `0xff` if `div_mask` is invalid.
*/
static uint8_t fromClockDiv(Register div_mask) {
if (div_mask == div_masks[0]) return 1;
if (div_mask == div_masks[1]) return 2;
if (div_mask == div_masks[2]) return 4;
if (div_mask == div_masks[3]) return 8;
if (div_mask == div_masks[4]) return 16;
if (div_mask == div_masks[5]) return 32;
if (div_mask == div_masks[6]) return 64;
if (div_mask == div_masks[7]) return 128;
return 0xff;
} }
uint32_t ticks(void) { uint32_t ticks(void) {
uint32_t ticks = 0; // ticks per millisecond static uint32_t ticks = 0; // ticks per millisecond
// Calculation (Assignment 5) if (ticks != 0) return ticks;
// Prepare Counter
LAPIC::Timer::set(0, 1, 0, false, true);
// Set timer for 10ms
PIT::set(10 * 1000);
// Start LAPIC-Timer
LAPIC::write(TIMER_INITIAL_COUNTER, UINT32_MAX);
PIT::waitForTimeout();
// Get final Count
uint32_t counter = LAPIC::read(TIMER_CURRENT_COUNTER);
// Disable LAPIC-Timer
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
// Calculate tick count.
ticks = (UINT32_MAX - counter) / 10;
DBG << "LAPIC-Timer calibration using PIT" << endl;
return ticks; return ticks;
} }
void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic, void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
bool masked) { bool masked) {
(void)counter; if (divide == 0 || (divide & (divide - 1)) != 0) {
(void)divide; // Not a power of 2
(void)vector; return;
(void)periodic; }
(void)masked;
ControlRegister tcr;
tcr.vector = Core::Interrupt::Vector::TIMER;
tcr.timer_mode = periodic ? PERIODIC : ONE_SHOT;
tcr.masked = masked ? MASKED : NOT_MASKED;
LAPIC::write(TIMER_CONTROL, tcr.value);
LAPIC::write(TIMER_DIVIDE_CONFIGURATION, getClockDiv(divide));
LAPIC::write(TIMER_INITIAL_COUNTER, counter);
} }
uint64_t time_tick;
uint8_t dividender;
bool setup(uint32_t us) { bool setup(uint32_t us) {
(void)us; time_tick = (static_cast<uint64_t>(ticks()) * us) / 1000ULL;
return false;
dividender = 1;
while (time_tick > UINT32_MAX) {
// While timer_ticks is to large to fit in 32bits.
time_tick >>= 1;
dividender <<= 1;
}
if (dividender > 128)
return false; // Timer interval is to large.
// Setup Masked interrupts to effectively disable the timer.
return true;
} }
uint32_t interval() { return 0; } uint32_t interval() {
uint32_t timer_ticks = LAPIC::read(TIMER_INITIAL_COUNTER);
uint32_t divisor = fromClockDiv(LAPIC::read(TIMER_DIVIDE_CONFIGURATION));
void activate() {} uint64_t us = (static_cast<uint64_t>(timer_ticks) * divisor * 1000ULL) / static_cast<uint64_t>(ticks());
return static_cast<uint32_t>(us);
}
void setMasked(bool masked) { (void)masked; } void activate() {
// Disable Counter to avoid spouriose interrupts.
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
set(static_cast<uint32_t>(time_tick), dividender, Core::Interrupt::TIMER, true, true);
// Activate Timer interrupts.
setMasked(false);
// enable counter with correct value.
LAPIC::write(TIMER_INITIAL_COUNTER, time_tick);
}
void setMasked(bool masked) {
ControlRegister tcr;
tcr.value = LAPIC::read(TIMER_CONTROL);
tcr.masked = masked ? MASKED : NOT_MASKED;
LAPIC::write(TIMER_CONTROL, tcr.value);
}
} // namespace Timer } // namespace Timer
} // namespace LAPIC } // namespace LAPIC

View File

@@ -1,4 +1,4 @@
#include "boot/multiboot/data.h" #include "./data.h"
/*! \brief Multiboot Information Structure according to Specification /*! \brief Multiboot Information Structure according to Specification
* \see [Multiboot Specification]{@ref multiboot} * \see [Multiboot Specification]{@ref multiboot}

View File

@@ -3,6 +3,7 @@
#include "../arch/system.h" #include "../arch/system.h"
#include "../arch/core_interrupt.h" #include "../arch/core_interrupt.h"
#include "../arch/ioport.h" #include "../arch/ioport.h"
#include "../arch/ioapic.h"
#include "../compiler/fix.h" #include "../compiler/fix.h"
#include "../debug/output.h" #include "../debug/output.h"
#include "keydecoder.h" #include "keydecoder.h"
@@ -106,6 +107,10 @@ void init() {
// Set to maximum speed & minimum delay // Set to maximum speed & minimum delay
setRepeatRate(SPEED_30_0CPS, DELAY_250MS); setRepeatRate(SPEED_30_0CPS, DELAY_250MS);
IOAPIC::config(1, Core::Interrupt::KEYBOARD);
IOAPIC::allow(1);
PS2Controller::drainBuffer();
} }
bool fetch(Key &pressed) { bool fetch(Key &pressed) {

View File

@@ -1,19 +1,43 @@
#include "epilogues.h" #include "epilogues.h"
#include "../debug/output.h" #include "../debug/output.h"
#include "../arch/core.h"
#include "../arch/lapic.h"
#include "guard.h" #include "guard.h"
#include "../thread/scheduler.h"
extern Key kout_key; extern Key kout_key;
#include "../user/app1/appl.h"
extern Application application1;
namespace Epilogues { namespace Epilogues {
void keyboard(Vault& g) { void keyboard(Vault& v) {
g.kout.setPos(0,0); v.kout.setPos(0,0);
g.kout << kout_key.ascii() << flush ; v.kout << kout_key.ascii() << flush ;
if(kout_key.scancode == Key::KEY_K)
v.sch.kill(v.sch.dispatcher.lifePointer[3]);
} }
void timer(Vault& g) { (void)g; } void timer(Vault& v) {
static int counter = 0;
int x, y;
if(Core::getID() == 0) {
v.kout.getPos(x, y);
v.kout.setPos(65, 0);
v.kout << counter++ << flush;
v.kout.setPos(x, y);
}
DBG << "timer C:" << dec << Core::getID() << " L:" << LAPIC::getID() << "\n" << flush;
void assassin(Vault& g) { (void)g; } v.sch.resume(true);
}
void assassin(Vault& v) {
DBG << "assassin epilog\n"<< endl;
if (v.sch.active()->kill_flag) {
v.sch.exit();
}
}
}; // namespace Epilogues }; // namespace Epilogues

View File

@@ -28,7 +28,7 @@ namespace Epilogues {
* \todo(15) Store the key to the keyboard buffer for user threads. Wake user * \todo(15) Store the key to the keyboard buffer for user threads. Wake user
* threads waiting for a key using the key semaphore. * threads waiting for a key using the key semaphore.
* *
* @param g * @param v The vault.
*/ */
void keyboard(Vault& g); void keyboard(Vault& g);
@@ -37,7 +37,7 @@ void keyboard(Vault& g);
* \todo(15) Preemptively reschedule threads * \todo(15) Preemptively reschedule threads
* \todo(16) Check the bellringer * \todo(16) Check the bellringer
* \todo(17) Refresh screen with fixed FPS rate * \todo(17) Refresh screen with fixed FPS rate
* @param g * @param v The vault.
*/ */
void timer(Vault& g); void timer(Vault& g);
@@ -45,6 +45,7 @@ void timer(Vault& g);
* it is set. * it is set.
* *
* \todo(15) Implement the rescheduling (in \MPStuBS only) * \todo(15) Implement the rescheduling (in \MPStuBS only)
* @param v The vault.
*/ */
void assassin(Vault& g); void assassin(Vault& g);
}; // namespace Epilogues }; // namespace Epilogues

View File

@@ -1,5 +1,4 @@
#include "guard.h" #include "guard.h"
#include "../arch/core.h" #include "../arch/core.h"
#include "../debug/output.h" #include "../debug/output.h"
#include "../object/bbuffer.h" #include "../object/bbuffer.h"
@@ -24,9 +23,11 @@ Vault::Vault() {
Guarded::~Guarded() { Guard::leave(); } Guarded::~Guarded() { Guard::leave(); }
Guarded Guard::enter() { Guarded Guard::enter() {
bool status = Core::Interrupt::disable();
epi_flag FOR_CURRENT_CORE = true; epi_flag FOR_CURRENT_CORE = true;
//Core::Interrupt::enable(); Core::Interrupt::restore(status);
global_lock.lock(); global_lock.lock();
Bellringer bellringer;
return Guarded(global_vault); return Guarded(global_vault);
} }
@@ -57,7 +58,7 @@ void Guard::relay(Epilogue handler) {
Core::Interrupt::enable(); // goto level 0.5 Core::Interrupt::enable(); // goto level 0.5
if(epi_flag FOR_CURRENT_CORE){ if(epi_flag FOR_CURRENT_CORE){
epilogue_queue->produce(handler); epilogue_queue FOR_CURRENT_CORE.produce(handler);
} }
else{ else{
epi_flag FOR_CURRENT_CORE = true; epi_flag FOR_CURRENT_CORE = true;

View File

@@ -2,21 +2,26 @@
* \brief \ref Guard synchronizes access to epilogue level * \brief \ref Guard synchronizes access to epilogue level
*/ */
#pragma once //#pragma once
#include "sync/bellringer.h"
#include "../object/bbuffer.h" #include "../object/bbuffer.h"
#include "../object/key.h" #include "../object/key.h"
#include "../types.h" #include "../types.h"
#include "epilogues.h" #include "epilogues.h"
#include "../device/textstream.h" #include "../device/textstream.h"
#include "../thread/scheduler.h"
//! \brief The epilogue vault contains the protected data for the epilogue level //! \brief The epilogue vault contains the protected data for the epilogue level
struct Vault { struct Vault {
Vault(); Vault();
TextStream kout = TextStream(0, 80, 0, 10, true); TextStream kout = TextStream(0, 80, 0, 10, true);
Scheduler sch = Scheduler();
// no copy // no copy
Vault(const Vault&) = delete; Vault(const Vault&) = delete;
Vault& operator=(const Vault&) = delete; Vault& operator=(const Vault&) = delete;
uint8_t counter;
Bellringer bellringer;
}; };
/*! \brief Lock guard that provides access to the epilogue \ref Vault /*! \brief Lock guard that provides access to the epilogue \ref Vault

View File

@@ -1,4 +1,4 @@
#include "handlers.h" #include "./handlers.h"
#include "../arch/core_cr.h" #include "../arch/core_cr.h"
#include "../arch/idt.h" #include "../arch/idt.h"
@@ -10,9 +10,11 @@
#include "../device/ps2controller.h" #include "../device/ps2controller.h"
#include "../sync/ticketlock.h" #include "../sync/ticketlock.h"
#include "../arch/core_interrupt.h"
#include "epilogues.h" #include "epilogues.h"
#include "guard.h" #include "guard.h"
Key kout_key = Key(); Key kout_key = Key();
void printContext(const InterruptContext *context) { void printContext(const InterruptContext *context) {
@@ -29,8 +31,7 @@ void printContext(const InterruptContext *context) {
[[gnu::interrupt]] void handle_double_fault(InterruptContext *context, [[gnu::interrupt]] void handle_double_fault(InterruptContext *context,
uint64_t error) { uint64_t error) {
(void)error; DBG << "Double fault encountered. Error code: " << dec << error << endl;
DBG << "Double fault encoutered" << endl;
printContext(context); printContext(context);
kernelpanic("Double fault!"); kernelpanic("Double fault!");
} }
@@ -61,8 +62,7 @@ enum PAGE_FAULT_ERROR {
[[gnu::interrupt]] void handle_page_fault(InterruptContext *context, [[gnu::interrupt]] void handle_page_fault(InterruptContext *context,
uint64_t error) { uint64_t error) {
(void)error; DBG << "Page fault encountered at linear address " << hex
DBG << "Page fault encoutered at linear address " << hex
<< Core::CR<2>::read() << endl << Core::CR<2>::read() << endl
<< (error & PF_ERR_PRESENT ? "present" : "non-present") << " page|" << (error & PF_ERR_PRESENT ? "present" : "non-present") << " page|"
<< (error & PF_ERR_WRITE ? "write" : "read") << " access|" << (error & PF_ERR_WRITE ? "write" : "read") << " access|"
@@ -73,19 +73,14 @@ enum PAGE_FAULT_ERROR {
kernelpanic("Page fault!"); kernelpanic("Page fault!");
} }
extern Ticketlock koutlock;
extern Vault keyboard_vault;
void handle_keyboard() { void handle_keyboard() {
//Key key = Key(); //Key key = Key();
if (PS2Controller::fetch(kout_key)) { if (PS2Controller::fetch(kout_key)) {
LAPIC::endOfInterrupt(); LAPIC::endOfInterrupt();
if (kout_key.ctrl() && kout_key.alt() && kout_key.scancode == Key::KEY_DEL) if (kout_key.ctrl() && kout_key.alt() && kout_key.scancode == Key::KEY_DEL)
System::reboot(); System::reboot();
Guard::relay(Epilogues::keyboard); Guard::relay(Epilogues::keyboard);
//koutlock.lock();
//kout << key.ascii() << endl << flush ;
//koutlock.unlock();
} }
else else
LAPIC::endOfInterrupt(); LAPIC::endOfInterrupt();
@@ -99,10 +94,15 @@ void handle_keyboard() {
[[gnu::interrupt]] void handle_timer(InterruptContext *context) { [[gnu::interrupt]] void handle_timer(InterruptContext *context) {
(void)context; (void)context;
LAPIC::endOfInterrupt();
Guard::relay(Epilogues::timer);
} }
[[gnu::interrupt]] void handle_assassin(InterruptContext *context) { [[gnu::interrupt]] void handle_assassin(InterruptContext *context) {
(void)context; (void)context;
LAPIC::endOfInterrupt();
DBG << "assassin handler\n"<< endl;
Guard::relay(Epilogues::assassin);
} }
[[gnu::interrupt]] void handle_wakeup(InterruptContext *context) { [[gnu::interrupt]] void handle_wakeup(InterruptContext *context) {
(void)context; (void)context;
@@ -122,10 +122,16 @@ void initInterruptHandlers() {
IDT::set(Core::Interrupt::Vector::PAGE_FAULT, IDT::set(Core::Interrupt::Vector::PAGE_FAULT,
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault)); IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
IDT::set(Core::Interrupt::Vector::TIMER,
IDT::InterruptDescriptor::Returning(handle_timer));
// TODO: Add more handlers here // TODO: Add more handlers here
IDT::set(Core::Interrupt::Vector::KEYBOARD, IDT::set(Core::Interrupt::Vector::KEYBOARD,
IDT::InterruptDescriptor::Returning(handle_keyboard_asm)); IDT::InterruptDescriptor::Returning(handle_keyboard_asm));
IDT::set(Core::Interrupt::Vector::TIMER,
IDT::InterruptDescriptor::Returning(handle_timer));
IDT::set(Core::Interrupt::Vector::ASSASSIN,
IDT::InterruptDescriptor::Returning(handle_assassin));
// Load the idt pointer // Load the idt pointer
IDT::load(); IDT::load();
} }

78
main.cc
View File

@@ -12,12 +12,17 @@
#include "device/textstream.h" #include "device/textstream.h"
#include "device/ps2controller.h" #include "device/ps2controller.h"
#include "arch/ioapic.h" #include "arch/ioapic.h"
#include "thread/scheduler.h"
#include "user/app1/appl.h" #include "user/app1/appl.h"
#include "sync/ticketlock.h" #include "sync/ticketlock.h"
#include "interrupt/guard.h" #include "interrupt/guard.h"
///TextStream kout = TextStream(0, 80, 0, 10, true); #include "arch/context.h"
#include "thread/thread.h"
TextStream kout = TextStream(0, 80, 0, 10, true);
Ticketlock koutlock; Ticketlock koutlock;
//Scheduler sch;
//TextStream dout[8] = { //TextStream dout[8] = {
// TextStream(0 ,20,12,25,false), // TextStream(0 ,20,12,25,false),
@@ -30,6 +35,7 @@ Ticketlock koutlock;
// TextStream(0 ,0 ,0, 0,false), // TextStream(0 ,0 ,0, 0,false),
//}; //};
TextStream dout[Core::MAX] = { TextStream dout[Core::MAX] = {
{0, 40, 10, 14}, {0, 40, 10, 14},
{40, 80, 10, 14}, {40, 80, 10, 14},
@@ -65,6 +71,29 @@ OutputStream* copyout[Core::MAX]{
unsigned int testx, testy; unsigned int testx, testy;
uint8_t test1_stack[1024];
uint8_t test2_stack[1024];
uint8_t test3_stack[1024];
uint8_t test4_stack[1024];
uint8_t test5_stack[1024];
uint8_t test6_stack[1024];
uint8_t test7_stack[1024];
uint8_t test8_stack[1024];
uint8_t test9_stack[1024];
Application application1 = Application(&test1_stack[sizeof(test1_stack)-1]);
Application application2 = Application(&test2_stack[sizeof(test2_stack)-1]);
Application application3 = Application(&test3_stack[sizeof(test3_stack)-1]);
Application application4 = Application(&test4_stack[sizeof(test4_stack)-1]);
Application application5 = Application(&test5_stack[sizeof(test5_stack)-1]);
Application application6 = Application(&test6_stack[sizeof(test5_stack)-1]);
Application application7 = Application(&test7_stack[sizeof(test5_stack)-1]);
Application application8 = Application(&test8_stack[sizeof(test5_stack)-1]);
Application application9 = Application(&test9_stack[sizeof(test5_stack)-1]);
// Main function // Main function
// (the bootstrap processor starts here)} // (the bootstrap processor starts here)}
extern "C" int main() { extern "C" int main() {
@@ -77,21 +106,36 @@ extern "C" int main() {
* Startup IPIs or even block devices like keyboard because of a missing EOI * Startup IPIs or even block devices like keyboard because of a missing EOI
*/ */
ApplicationProcessor::boot(); {
Guarded g = Guard::enter();
PS2Controller::init(); Scheduler &sch =g.vault().sch;
sch.ready(&application1);
sch.ready(&application2);
sch.ready(&application3);
sch.ready(&application4);
sch.ready(&application5);
sch.ready(&application6);
sch.ready(&application7);
sch.ready(&application8);
sch.ready(&application9);
}
LAPIC::Timer::setup(1000000);
IOAPIC::init(); IOAPIC::init();
IOAPIC::config(1, Core::Interrupt::KEYBOARD); PS2Controller::init();
IOAPIC::allow(1); ApplicationProcessor::boot();
Core::Interrupt::enable(); Core::Interrupt::enable();
LAPIC::Timer::activate();
PS2Controller::drainBuffer();
DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush; DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush;
Application{}.action(); {
Guarded g = Guard::enter();
g.vault().sch.schedule();
}
//Application{}.action();
while (true){ while (true){
//DBG << "pos: " << testx << ", " << testy << endl << flush; //DBG << "pos: " << testx << ", " << testy << endl << flush;
//Core::pause(); //Core::pause();
@@ -102,14 +146,20 @@ extern "C" int main() {
// Main function for application processors // Main function for application processors
extern "C" int main_ap() { extern "C" int main_ap() {
DBG_VERBOSE << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC " DBG << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC "
<< static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl; << static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl;
Core::Interrupt::enable();
DBG << "App CPU " << static_cast<int>(Core::getID()) << endl << flush;
Core::Interrupt::enable();
LAPIC::Timer::activate();
{
Guarded g = Guard::enter();
g.vault().sch.schedule();
}
//assert(Core::getID() != 1); //assert(Core::getID() != 1);
Application{}.action(); //Application{}.action();
return 0; return 0;
} }

4
notes Normal file
View File

@@ -0,0 +1,4 @@
scheduler in vault
next implementieren
thread kill nicht in die liste enqueuen, scheduler.cc zeile 26
setzen von epi flags interrupt vermutlich disablen.

View File

@@ -11,39 +11,16 @@
/*! \brief Templated Queue for arbitrary objects. /*! \brief Templated Queue for arbitrary objects.
* *
* Queue is implemented by a head-object (Queue<T>) and next-pointers embedded * Queue is implemented by a head-object (Queue<T>) and next-pointers embedded
* in the queued objects. This Queue supports arrays of next-pointers by passing * in the queued objects. By passing a different get_link function into the
* an index into the constructor identifying the index into the next-pointer * constructor, the member name of the next-pointer can be changed and objects
* array. By passing a different get_link function into the constructor, the * can be contained in different independent queues.
* member name of the next-pointer array can be changed and objects can be
* contained in different independent queues.
*/ */
template <class T> template <class T>
class Queue { class Queue {
/*! \brief Default get_link implementation returns a pointer to the /// Default get_link implementation returns a pointer to the next-pointer.
* link_index'th element of the next-pointer array. static T** default_get_link(T& obj) { return &obj.queue_link; }
* The function assumes a member named "queue_link" that stores the
* next-pointer.
*
* If your object contains a queue_link member you can just ignore this
* function and the get_link keyword argument of the constructor.
*
* \param[in] obj the object whose link should be accessed.
* \param[in] link_index the index within the array.
*
* \return A pointer to the next-object pointer.
*/
static T** default_get_link(T& obj, unsigned link_index) {
assert(link_index < sizeof(T::queue_link) / sizeof(void*));
return &obj.queue_link[link_index];
}
/// Type definition for the get_link function /// Type definition for the get_link function
typedef T** (*NextFunc)(T&, unsigned); typedef T** (*NextFunc)(T&);
/// Queue-local index into the next-pointer array
unsigned link_index;
/// Provides the same signature for single- and multi-core Queue
T** get_link_wrapped(T& obj) { return get_link(obj, link_index); }
/// Function pointer to the get_link function, called whenever the /// Function pointer to the get_link function, called whenever the
/// next pointer array is referenced /// next pointer array is referenced
@@ -106,18 +83,15 @@ class Queue {
constexpr Queue(Queue&&) = default; constexpr Queue(Queue&&) = default;
/*! \brief Constructor /*! \brief Constructor
* \param[in] link_index denotes the index into the next-pointer array
* to be used by this
*queue-object
* \param[in] get_link A function pointer to the get_link, i.e. a function * \param[in] get_link A function pointer to the get_link, i.e. a function
* which returns a pointer to the * which returns a pointer to the
*next-pointer of an element in the Queue. *next-pointer of an element in the Queue.
*/ */
explicit Queue(unsigned link_index, NextFunc get_link = default_get_link) explicit Queue(NextFunc get_link = default_get_link)
: link_index(link_index), : get_link(get_link), head(nullptr), tail(nullptr) {
get_link(get_link), assert(get_link != nullptr &&
head(nullptr), "get_link function pointer must not be nullptr!");
tail(nullptr) {} };
/*! \brief Enqueues the provided item at the end of the queue. If the element /*! \brief Enqueues the provided item at the end of the queue. If the element
* is already contained in the queue, false will be returned * is already contained in the queue, false will be returned
@@ -126,7 +100,7 @@ class Queue {
* or not (and it is now enqueued, then true) * or not (and it is now enqueued, then true)
*/ */
bool enqueue(T& item) { bool enqueue(T& item) {
T** nextptr = get_link_wrapped(item); T** nextptr = get_link(item);
if (*nextptr != nullptr || (head != nullptr && tail == &item)) { if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
return false; return false;
} }
@@ -136,7 +110,7 @@ class Queue {
head = tail = &item; head = tail = &item;
} else { } else {
assert(tail != nullptr); assert(tail != nullptr);
*get_link_wrapped(*tail) = &item; *get_link(*tail) = &item;
tail = &item; tail = &item;
} }
return true; return true;
@@ -147,7 +121,7 @@ class Queue {
* \return true if successful, false if item was already in the queue * \return true if successful, false if item was already in the queue
**/ **/
bool insertFirst(T& item) { bool insertFirst(T& item) {
T** nextptr = get_link_wrapped(item); T** nextptr = get_link(item);
if (*nextptr != nullptr || (head != nullptr && tail == &item)) { if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
return false; return false;
} }
@@ -177,13 +151,13 @@ class Queue {
if (&after == tail) { if (&after == tail) {
return enqueue(item); return enqueue(item);
} }
T** nextptr = get_link_wrapped(item); T** nextptr = get_link(item);
// if item is already in the list return false // if item is already in the list return false
if (*nextptr != nullptr || tail == &item) { if (*nextptr != nullptr || tail == &item) {
return false; return false;
} }
T** pnextptr = get_link_wrapped(after); T** pnextptr = get_link(after);
// if after is NOT in the list, return false // if after is NOT in the list, return false
if (!(pnextptr != nullptr || tail == &after)) { if (!(pnextptr != nullptr || tail == &after)) {
return false; return false;
@@ -201,8 +175,7 @@ class Queue {
*not in this list *not in this list
**/ **/
T* next(T& item) { T* next(T& item) {
T** nextptr = get_link_wrapped(item); T** nextptr = get_link(item);
// if item is already in the list return nullptr
if (head == nullptr || (*nextptr == nullptr && tail != &item)) { if (head == nullptr || (*nextptr == nullptr && tail != &item)) {
return nullptr; return nullptr;
} }
@@ -222,7 +195,7 @@ class Queue {
T* dequeue() { T* dequeue() {
T* out = head; T* out = head;
if (head != nullptr) { if (head != nullptr) {
T** nextptr = get_link_wrapped(*head); T** nextptr = get_link(*head);
head = *nextptr; head = *nextptr;
*nextptr = nullptr; *nextptr = nullptr;
} }
@@ -239,21 +212,21 @@ class Queue {
T** next_link; T** next_link;
if (head == that) { if (head == that) {
head = *get_link_wrapped(*head); head = *get_link(*head);
*get_link_wrapped(*that) = nullptr; *get_link(*that) = nullptr;
return that; return that;
} }
while (cur) { while (cur) {
next_link = get_link_wrapped(*cur); next_link = get_link(*cur);
if (*next_link == that) { if (*next_link == that) {
*next_link = *get_link_wrapped(**next_link); *next_link = *get_link(**next_link);
if (that == tail) { if (that == tail) {
tail = cur; tail = cur;
} }
*get_link_wrapped(*that) = nullptr; *get_link(*that) = nullptr;
return that; return that;
} }
cur = *next_link; cur = *next_link;

View File

@@ -1,29 +1,38 @@
#include "bellringer.h" #include "./bellringer.h"
#include "../interrupt/guard.h" #include "../interrupt/guard.h"
#include "../thread/thread.h"
struct Bell {
// link pointer to the next bell in the bellringers bell list
Bell *queue_link[1] = {nullptr};
Thread *thread;
size_t counter;
};
Bell **Bellringer::bell_link(Bell &obj, unsigned link_index) {
return &obj.queue_link[link_index];
}
// check: Checks whether bells are running out of time and rings them if // check: Checks whether bells are running out of time and rings them if
// necessary // necessary
void Bellringer::check(Vault &vault) { (void)vault; } void Bellringer::check(Vault &vault) {
auto first = vault.bellringer.bells.dequeue();
first->counter--;
if (vault.bellringer.bellPending()){
vault.bellringer.bells.insertFirst(*first);
}
if (vault.bellringer.bellPending()){
if (first->counter < 1) {
vault.sch.ready(vault.bellringer.bells.dequeue()->thread);
}
}
}
// job: Give a bell to the bellringer & ring it when the specified time ran out. // job: Give a bell to the bellringer & ring it when the specified time ran out.
void Bellringer::sleep(Vault &vault, unsigned int ms) { void Bellringer::sleep(Vault &vault, unsigned int ms) {
(void)vault; Bell bell;
(void)ms; bell.thread = vault.sch.dispatcher.active();
auto tmp = vault.bellringer.bells.dequeue();
vault.bellringer.bells.insertFirst(*tmp);
do{
ms-=tmp->counter;
} while ((tmp=vault.bellringer.bells.next(*tmp)) != nullptr );
bell.counter = ms;
vault.sch.resume(false);
} }
// Are there bells in the queue? // Are there bells in the queue?
bool Bellringer::bellPending() const { return false; } bool Bellringer::bellPending() const {
if (bells.is_empty())
return false;
else
return true;
}

View File

@@ -4,10 +4,10 @@
#pragma once #pragma once
#include "../object/queue.h" #include "../object/queue.h"
#include "../thread/thread.h"
#include "../types.h" #include "../types.h"
struct Vault; struct Vault;
struct Bell;
/*! \brief Manages and activates time-triggered activities. /*! \brief Manages and activates time-triggered activities.
* \ingroup ipc * \ingroup ipc
@@ -24,6 +24,14 @@ class Bellringer {
Bellringer(const Bellringer&) = delete; Bellringer(const Bellringer&) = delete;
Bellringer& operator=(const Bellringer&) = delete; Bellringer& operator=(const Bellringer&) = delete;
struct Bell {
// link pointer to the next bell in the bellringers bell list
Bell* queue_link = nullptr;
Thread* thread;
size_t counter;
};
/*! \brief List of bells currently managed. /*! \brief List of bells currently managed.
* *
* This list contains non-expired bells enqueued by job(). * This list contains non-expired bells enqueued by job().
@@ -34,26 +42,26 @@ class Bellringer {
*/ */
Queue<Bell> bells; Queue<Bell> bells;
//! Link pointer for bells
static Bell** bell_link(Bell& obj, unsigned link_index);
public: public:
// constructor // constructor
Bellringer() : bells(0, bell_link) {} Bellringer() : bells() {}
/*! \brief Checks whether there are bells to be rung. /*! \brief Checks whether there are bells to be rung.
* *
* Every call to check elapses a tick. Once such a tick reduces a bells * Every call to check elapses a tick. Once such a tick reduces a bells
* remaining time to zero, the bell will be rung. * remaining time to zero, the bell will be rung.
* *
* \param vault The vault containing the bellringer instance
*
* \todo(16) Implement Method * \todo(16) Implement Method
*/ */
void check(Vault& vault); void check(Vault& vault);
/*! \brief Passes a `bell` to the bellringer to be rung after `ms` /*! \brief Passes a `bell` to the bellringer to be rung after `ms`
* milliseconds. * milliseconds.
* \param bell Bell that should be rung after `ms` milliseconds *
* \param ms number of milliseconds that should be waited before * \param vault The vault containing the bellringer instance
* \param ms Number of milliseconds that should be waited before
* ringing the bell * ringing the bell
* *
* \todo(16) Implement Method * \todo(16) Implement Method

View File

@@ -1,16 +1,30 @@
#include "./semaphore.h" #include "./semaphore.h"
#include "../interrupt/guard.h" #include "../interrupt/guard.h"
#include "../thread/thread.h" #include "../thread/scheduler.h"
uint8_t counter;
Semaphore::Semaphore(unsigned c) { (void)c; } Queue<Thread> waiting;
Semaphore::Semaphore(unsigned c) {
Thread **Semaphore::thread_link(Thread &obj, unsigned link_index) { counter=c;
(void)obj; }
(void)link_index;
return nullptr;
void Semaphore::p(Vault &vault) {
//resource is frei, läuft direkt weiter
if (vault.counter > 0)
vault.counter--;
else
//thread block, zu aktueller queue hinzufügen und
waiting.enqueue(*vault.sch.active()); //was is der calling thread
//
}
//release
void Semaphore::v(Vault &vault) {
Thread* first = waiting.dequeue();
if (first != nullptr)
vault.sch.ready(first); //wakeup "first" thread
else
vault.counter++;
} }
void Semaphore::p(Vault &vault) { (void)vault; }
void Semaphore::v(Vault &vault) { (void)vault; }

View File

@@ -26,8 +26,6 @@ class Semaphore {
Semaphore(const Semaphore&) = delete; Semaphore(const Semaphore&) = delete;
Semaphore& operator=(const Semaphore&) = delete; Semaphore& operator=(const Semaphore&) = delete;
static Thread** thread_link(Thread& obj, unsigned link_index);
public: public:
/*! \brief Constructor; initialized the counter with provided value `c` /*! \brief Constructor; initialized the counter with provided value `c`
* \param c Initial counter value * \param c Initial counter value

View File

@@ -3,6 +3,7 @@
*/ */
#pragma once #pragma once
#include "../types.h"
#include "../arch/core.h" #include "../arch/core.h"
#include "../arch/cache.h" #include "../arch/cache.h"

View File

@@ -1,17 +1,33 @@
// vim: set noet ts=4 sw=4: // vim: set noet ts=4 sw=4:
#include "dispatcher.h" #include "dispatcher.h"
#include "../arch/core.h"
Dispatcher::Dispatcher() {} Dispatcher::Dispatcher() {
Thread *Dispatcher::active() { return nullptr; }
bool Dispatcher::isActive(const Thread *thread, unsigned *cpu) {
(void)thread;
(void)cpu;
return false;
} }
void Dispatcher::go(Thread *first) { (void)first; } Thread *Dispatcher::active() {
return lifePointer[Core::getID()];
}
void Dispatcher::dispatch(Thread *next) { (void)next; } bool Dispatcher::isActive(const Thread *thread, unsigned *cpu) {
for(uint8_t i=0; i<Core::MAX; i++){
if(thread == lifePointer[i]){
*cpu = i;
return true;
}
}
cpu = nullptr;
return false;
}
void Dispatcher::go(Thread *first) {
lifePointer[Core::getID()] = first;
first->go();
}
void Dispatcher::dispatch(Thread *next) {
Thread* tmp = lifePointer[Core::getID()];
lifePointer[Core::getID()] = next;
tmp->resume(next);
}

View File

@@ -6,6 +6,7 @@
#pragma once #pragma once
#include "../thread/thread.h" #include "../thread/thread.h"
#include "../types.h" #include "../types.h"
#include "../arch/core.h"
/*! \brief The dispatcher dispatches threads and puts the scheduler's /*! \brief The dispatcher dispatches threads and puts the scheduler's
* decisions into action. * decisions into action.
@@ -23,12 +24,14 @@ class Dispatcher {
*/ */
void setActive(Thread* thread) { (void)thread; } void setActive(Thread* thread) { (void)thread; }
public: public:
/*! \brief constructor /*! \brief constructor
* *
* \todo(14) Implement Method * \todo(14) Implement Method
*/ */
Dispatcher(); Dispatcher();
Thread* lifePointer[Core::MAX];
/*! \brief Returns the thread currently running on the CPU core calling /*! \brief Returns the thread currently running on the CPU core calling
* this method * this method

View File

@@ -1,27 +1,70 @@
// vim: set noet ts=4 sw=4: // vim: set noet ts=4 sw=4:
#include "scheduler.h" #include "scheduler.h"
#include "../arch/lapic.h"
#include "dispatcher.h"
#include "../interrupt/guard.h"
#include "../debug/output.h"
Scheduler::Scheduler() {} Queue<Thread> readyList = Queue<Thread>();
Scheduler::Scheduler() {
}
Thread* Scheduler::getNext() { return nullptr; } Thread* Scheduler::getNext() { return nullptr; }
void Scheduler::schedule() {} void Scheduler::schedule() {
// TODO maybe guard?
Thread* next = readyList.dequeue();
assert(next != nullptr);
dispatcher.go(next);
}
void Scheduler::ready(Thread* that) { (void)that; } void Scheduler::ready(Thread* that) {
assert(that != nullptr);
readyList.enqueue(*that);
}
void Scheduler::resume(bool ready) { (void)ready; } void Scheduler::resume(bool ready) {
//if (!active()->kill_flag)
if (ready)
readyList.enqueue(*active());
Thread* thread = readyList.dequeue();
assert(thread != nullptr);
dispatcher.dispatch(thread);
}
void Scheduler::exit() {} void Scheduler::exit() {
Thread* thread = readyList.dequeue();
assert(thread != nullptr);
dispatcher.dispatch(thread);
}
void Scheduler::kill(Thread* that) { (void)that; } void Scheduler::kill(Thread* that) {
readyList.remove(that);
that->kill_flag = true;
bool Scheduler::isActive(const Thread* that, unsigned int* cpu) { DBG << "kill..." << flush;
(void)that;
for(uint8_t i=0;i<Core::MAX; i++)
if(dispatcher.lifePointer[i] == that){
LAPIC::IPI::send(i, Core::Interrupt::Vector::ASSASSIN);
DBG << "found thread on Core" << dec << static_cast<int>(i) << "! killing...\n" << flush;
return;
}
DBG << "not found\n" << flush;
}
bool Scheduler::isActive(const Thread* thread, unsigned int* cpu) {
(void)thread;
(void)cpu; (void)cpu;
return false; return false;
} }
bool Scheduler::isEmpty() const { return false; } bool Scheduler::isEmpty() const { return false; }
void Scheduler::setIdle(IdleThread* that) { (void)that; } void Scheduler::setIdle(IdleThread* that) { (void)that; }

View File

@@ -22,18 +22,20 @@
* taken from the front of the queue. * taken from the front of the queue.
*/ */
class Scheduler { class Scheduler {
/*! \brief Helper to retrieve next Thread
* \return pointer of next thread
*/
Thread* getNext();
public:
Scheduler();
/*! \brief a Dispatcher object, providing the low level context switching /*! \brief a Dispatcher object, providing the low level context switching
* routines. * routines.
*/ */
Dispatcher dispatcher; Dispatcher dispatcher;
/*! \brief Helper to retrieve next Thread
* \return pointer of next thread
*/
Thread* getNext();
public:
Scheduler();
/*! \brief Start scheduling /*! \brief Start scheduling
* *
@@ -103,7 +105,7 @@ class Scheduler {
Thread* active() { return dispatcher.active(); } Thread* active() { return dispatcher.active(); }
/// \copydoc Dispatcher::isActive /// \copydoc Dispatcher::isActive
bool isActive(const Thread* that, unsigned int* cpu = nullptr); bool isActive(const Thread* thread, unsigned int* cpu = nullptr);
/*! \brief Checks whether the ready queue is empty. /*! \brief Checks whether the ready queue is empty.
* *

View File

@@ -1,16 +1,36 @@
// vim: set noet ts=4 sw=4: // vim: set noet ts=4 sw=4:
#include "thread.h" #include "thread.h"
#include "../debug/output.h"
#include "../arch/context.h"
#include "interrupt/guard.h"
// Alias to simplify stuff // Alias to simplify stuff
typedef void (*kickoff_t)(void*); typedef void (*kickoff_t)(void*);
void Thread::kickoff(Thread* object) { (void)object; } void Thread::kickoff(Thread* object) {
Guard::leave();
object->action();
}
Thread::Thread(void* tos) { (void)tos; } Thread::Thread(void* tos) {
prepareContext(tos, context, (void(*)(void*)) &(kickoff), this);
}
void Thread::resume(Thread* next) { (void)next; } #include "../thread/scheduler.h"
void Thread::resume(Thread* next) {
Context *from = &this->context;
Context *to = &next->context;
void Thread::go() {} //g.vault().sch.dispatcher.lifePointer[Core::getID()] = next;
DBG << "from: " << hex << from << endl;
DBG << "to : " << hex << to << endl << flush;
context_switch(to, from);
}
void Thread::action() {} void Thread::go() {
context_launch(&context);
}
void Thread::action() {
while(1);
}

View File

@@ -16,12 +16,11 @@
#include "../arch/context.h" #include "../arch/context.h"
#include "../object/queue.h" #include "../object/queue.h"
#include "../types.h" #include "../types.h"
/*! \brief The Thread is an object used by the scheduler. /*! \brief The Thread is an object used by the scheduler.
* \ingroup thread * \ingroup thread
*/ */
class Thread { class Thread {
protected: public:
/*! \brief The thread's entry point. /*! \brief The thread's entry point.
* *
* For the first activation of a thread, we need a "return address" * For the first activation of a thread, we need a "return address"
@@ -36,13 +35,15 @@ class Thread {
* *
* \param object Thread to be started * \param object Thread to be started
*/ */
/// \todo(14) Implement Method
static void kickoff(Thread* object); static void kickoff(Thread* object);
volatile bool kill_flag;
Context context;
Thread* queue_link;
public: public:
/*! \brief Marker for a dying thread /*! \brief Marker for a dying thread
*/ */
volatile bool kill_flag;
/*! \brief Constructor /*! \brief Constructor
* Initializes the context using \ref prepareContext with the given stack * Initializes the context using \ref prepareContext with the given stack

View File

@@ -8,6 +8,10 @@
#include "../../arch/core.h" #include "../../arch/core.h"
#include "../../interrupt/guard.h" #include "../../interrupt/guard.h"
#include "../../debug/output.h" #include "../../debug/output.h"
#include "../../arch/context.h"
#include "../../sync/semaphore.h"
static uint8_t appl_cnt = 0;
extern TextStream kout;
char text[] = "Ich mag\n\ char text[] = "Ich mag\n\
Saftige Pflaumen voller Aroma\n\ Saftige Pflaumen voller Aroma\n\
Ich knuddel jede Oma ins Koma\n\ Ich knuddel jede Oma ins Koma\n\
@@ -21,8 +25,6 @@ Ich bin Großmuttersniffer\n\
Und wacht sie aus'm Koma auf, kriegt sie von mir 'n Sticker\n\ Und wacht sie aus'm Koma auf, kriegt sie von mir 'n Sticker\n\
\n"; \n";
extern Ticketlock koutlock;
void activeWaitDelay(uint64_t cycles) { void activeWaitDelay(uint64_t cycles) {
uint64_t counter = 0; // Use volatile to prevent optimization uint64_t counter = 0; // Use volatile to prevent optimization
for (uint64_t i = 0; i < cycles; ++i) { for (uint64_t i = 0; i < cycles; ++i) {
@@ -31,26 +33,32 @@ void activeWaitDelay(uint64_t cycles) {
//Core::pause(); //Core::pause();
} }
} }
Semaphore foo= Semaphore(1);
void Application::action() { // NOLINT void Application::action() { // NOLINT
uint16_t cnt = 0; uint16_t cnt = 0;
uint8_t row = appl_cnt++;
while (1) { while (1) {
//koutlock.lock();
//koutlock.lock();
{ {
Guarded g = Guard::enter(); Guarded g= Guard::enter();
//g.vault();
g.vault().kout.setPos((unsigned)0,(unsigned)Core::getID()*2+1);
g.vault().kout << cnt++ << flush; //g.vault();
foo.p(g.vault());
//g.vault().kout << endl << flush; kout.setPos((unsigned)8*row,(unsigned)/*Core::getID()*2+*/1);
//Guard::leave(); kout << cnt++ << flush;
//koutlock.unlock(); foo.v(g.vault());
g.vault().bellringer.sleep(g.vault(),6666);
//g.vault().kout << endl << flush;
//Guard::leave();
//koutlock.unlock();
} }
Core::pause(); //Core::pause();
//activeWaitDelay(1000000000); //activeWaitDelay(10000000);
if(cnt >= sizeof(text)-1) if(cnt >= sizeof(text)-1)
cnt=0; cnt=0;
//context_switch(test2,test1);
} }
} }

View File

@@ -6,13 +6,13 @@
#pragma once #pragma once
#include "../../types.h" #include "../../types.h"
#include "../../thread/thread.h"
//! \brief Test application //! \brief Test application
//! //!
//! \todo(12) Create a test application //! \todo(12) Create a test application
//! \todo(14) Application should inherit from \ref Thread //! \todo(14) Application should inherit from \ref Thread
//! \todo(16) Make some noise using the \ref PIT::pcspeaker "PC Speaker" //! \todo(16) Make some noise using the \ref PIT::pcspeaker "PC Speaker"
class Application { class Application:public Thread {
// Prevent copies and assignments // Prevent copies and assignments
Application(const Application&) = delete; Application(const Application&) = delete;
Application& operator=(const Application&) = delete; Application& operator=(const Application&) = delete;
@@ -24,7 +24,8 @@ class Application {
* *
* \todo(14) Implement Constructor * \todo(14) Implement Constructor
*/ */
Application(void* tos): Thread(tos){
}
/*! \brief Contains the application code. /*! \brief Contains the application code.
* *
* \todo(14) Implement Method * \todo(14) Implement Method