mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-08 11:58:36 -04:00
Make everythign even worse than before
This commit is contained in:
parent
9cc34c05d7
commit
5feda76c93
3
Makefile
3
Makefile
@ -45,6 +45,9 @@ bochs: default
|
||||
bochs -qf tools/bochsrc.txt -rc commands
|
||||
rm commands
|
||||
|
||||
bochs_simple: default
|
||||
bochs -qf tools/bochsrc.txt
|
||||
|
||||
debug: default
|
||||
echo "c" > commands
|
||||
bochs -qf tools/debug_bochsrc.txt -rc commands
|
||||
|
2
cpp.mk
2
cpp.mk
@ -4,7 +4,7 @@ OC=x86_64-elf-objcopy
|
||||
AR=x86_64-elf-ar
|
||||
|
||||
WARNING_FLAGS=-Wall -Wextra -pedantic -Wold-style-cast
|
||||
COMMON_CPP_FLAGS=-masm=intel -I../../tstl/include/ -I../printf/include/ -I../tstl/include/ -I../tlib/include/ -Iinclude/ -nostdlib -g -Os -std=c++11 -fno-stack-protector -fno-exceptions -funsigned-char -fno-rtti -ffreestanding -fomit-frame-pointer -mno-red-zone -mno-3dnow -mno-mmx -fno-asynchronous-unwind-tables
|
||||
COMMON_CPP_FLAGS=-masm=intel -I../../tstl/include/ -I../printf/include/ -I../tstl/include/ -I../tlib/include/ -Iinclude/ -nostdlib -g -std=c++11 -fno-stack-protector -fno-exceptions -funsigned-char -fno-rtti -ffreestanding -mno-red-zone -mno-3dnow -mno-mmx -fno-asynchronous-unwind-tables
|
||||
|
||||
DISABLE_SSE_FLAGS=-mno-sse -mno-sse2 -mno-sse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2
|
||||
ENABLE_SSE_FLAGS=-msse -msse2 -msse3 -msse4 -msse4.1 -msse4.2
|
||||
|
54
kernel/include/irq_wait_queue.hpp
Normal file
54
kernel/include/irq_wait_queue.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
//=======================================================================
|
||||
// Copyright Baptiste Wicht 2013-2014.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//=======================================================================
|
||||
|
||||
#ifndef IRQ_WAIT_QUEUE_HPP
|
||||
#define IRQ_WAIT_QUEUE_HPP
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "lock_guard.hpp"
|
||||
#include "spinlock.hpp"
|
||||
|
||||
template<size_t S>
|
||||
struct irq_wait_queue {
|
||||
private:
|
||||
volatile size_t head = 0;
|
||||
volatile size_t tail = 0;
|
||||
|
||||
scheduler::pid_t pids[S];
|
||||
|
||||
spinlock lock;
|
||||
|
||||
public:
|
||||
bool empty() const {
|
||||
return tail - head == 0;
|
||||
}
|
||||
|
||||
scheduler::pid_t signal(){
|
||||
auto pid = pids[head % S];
|
||||
++head;
|
||||
|
||||
scheduler::soft_unblock(pid);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
void wait(){
|
||||
auto pid = scheduler::get_pid();
|
||||
|
||||
scheduler::soft_block(pid);
|
||||
|
||||
lock.acquire();
|
||||
|
||||
pids[tail % S] = pid;
|
||||
++tail;
|
||||
|
||||
lock.release();
|
||||
scheduler::soft_reschedule(pid);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -17,12 +17,40 @@ namespace scheduler {
|
||||
|
||||
constexpr const size_t MAX_PROCESS = 128;
|
||||
|
||||
struct sleep_queue_ptr {
|
||||
sleep_queue_ptr* next;
|
||||
sleep_queue_ptr* prev;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct tasklet {
|
||||
void (*fun)(size_t,size_t);
|
||||
size_t d1;
|
||||
size_t d2;
|
||||
};
|
||||
|
||||
bool is_started();
|
||||
|
||||
pid_t get_pid();
|
||||
scheduler::process_t& get_process(pid_t pid);
|
||||
|
||||
void block_process(pid_t pid);
|
||||
void unblock_process(pid_t pid);
|
||||
|
||||
scheduler::sleep_queue_ptr* queue_ptr(scheduler::pid_t pid);
|
||||
|
||||
|
||||
|
||||
//TODO Probably should be pruned
|
||||
void soft_block(pid_t pid);
|
||||
void soft_unblock(pid_t pid);
|
||||
void soft_reschedule(pid_t pid);
|
||||
|
||||
|
||||
void irq_register_tasklet(const tasklet& task, size_t priority);
|
||||
|
||||
|
||||
|
||||
void init();
|
||||
void start() __attribute__((noreturn));
|
||||
|
||||
|
@ -8,31 +8,31 @@
|
||||
#ifndef SEMAPHORE_H
|
||||
#define SEMAPHORE_H
|
||||
|
||||
#include <queue.hpp>
|
||||
#include <lock_guard.hpp>
|
||||
|
||||
#include "spinlock.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "sleep_queue.hpp"
|
||||
|
||||
struct semaphore {
|
||||
private:
|
||||
spinlock lock;
|
||||
volatile size_t value;
|
||||
std::queue<scheduler::pid_t> queue;
|
||||
//std::queue<scheduler::pid_t> queue;
|
||||
sleep_queue queue;
|
||||
|
||||
public:
|
||||
void init(size_t v){
|
||||
value = v;
|
||||
}
|
||||
|
||||
//TODO Make sure it doesn't have the lost wake up problem
|
||||
void wait(){
|
||||
lock.acquire();
|
||||
|
||||
if(!value){
|
||||
queue.push(scheduler::get_pid());
|
||||
scheduler::set_current_state(scheduler::process_state::BLOCKED);
|
||||
lock.release();
|
||||
scheduler::reschedule();
|
||||
queue.sleep();
|
||||
lock.acquire();
|
||||
}
|
||||
|
||||
@ -47,10 +47,7 @@ public:
|
||||
++value;
|
||||
|
||||
if(!queue.empty()){
|
||||
auto pid = queue.top();
|
||||
queue.pop();
|
||||
|
||||
scheduler::unblock_process(pid);
|
||||
queue.wake_up();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -8,41 +8,42 @@
|
||||
#ifndef SLEEP_QUEUE_H
|
||||
#define SLEEP_QUEUE_H
|
||||
|
||||
#include <queue.hpp>
|
||||
#include <lock_guard.hpp>
|
||||
|
||||
#include "spinlock.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include "console.hpp"
|
||||
|
||||
struct sleep_queue {
|
||||
private:
|
||||
mutable spinlock lock;
|
||||
typedef spinlock lock_type;
|
||||
|
||||
std::queue<scheduler::pid_t> queue;
|
||||
mutable lock_type lock;
|
||||
|
||||
scheduler::sleep_queue_ptr* head = nullptr;
|
||||
scheduler::sleep_queue_ptr* tail = nullptr;
|
||||
|
||||
public:
|
||||
bool empty() const {
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
std::lock_guard<lock_type> l(lock);
|
||||
|
||||
return queue.empty();
|
||||
return head == nullptr;
|
||||
}
|
||||
|
||||
scheduler::pid_t top_process() const {
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
std::lock_guard<lock_type> l(lock);
|
||||
|
||||
return queue.top();
|
||||
return head->pid;
|
||||
}
|
||||
|
||||
scheduler::pid_t wake_up(){
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
|
||||
//Get the first process
|
||||
auto pid = queue.top();
|
||||
std::lock_guard<lock_type> l(lock);
|
||||
|
||||
//Remove the process from the queue
|
||||
queue.pop();
|
||||
auto queue_ptr = head;
|
||||
head = head->next;
|
||||
|
||||
//Get the first process
|
||||
auto pid = queue_ptr->pid;
|
||||
|
||||
//Indicate to the scheduler that this process will be able
|
||||
//to run
|
||||
@ -57,8 +58,18 @@ public:
|
||||
//Get the current process information
|
||||
auto pid = scheduler::get_pid();
|
||||
|
||||
auto queue_ptr = scheduler::queue_ptr(pid);
|
||||
queue_ptr->pid = pid;
|
||||
queue_ptr->next = nullptr;
|
||||
queue_ptr->prev = nullptr;
|
||||
|
||||
//Enqueue the process in the sleep queue
|
||||
queue.push(pid);
|
||||
if(!head){
|
||||
head = queue_ptr;
|
||||
} else {
|
||||
tail->next = queue_ptr;
|
||||
tail = queue_ptr;
|
||||
}
|
||||
|
||||
lock.release();
|
||||
|
||||
|
@ -14,13 +14,15 @@ private:
|
||||
|
||||
public:
|
||||
void acquire(){
|
||||
//while(!__sync_bool_compare_and_swap(&lock, 0, 1));
|
||||
while(!__sync_lock_test_and_set(&lock, 1)){}
|
||||
while(__sync_lock_test_and_set(&lock, 1)){
|
||||
while(lock){
|
||||
//Wait
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void release(){
|
||||
__sync_synchronize();
|
||||
lock = 0;
|
||||
__sync_lock_release(&lock);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <circular_buffer.hpp>
|
||||
|
||||
#include "sleep_queue.hpp"
|
||||
#include "spinlock.hpp"
|
||||
|
||||
namespace stdio {
|
||||
|
||||
@ -22,14 +23,19 @@ struct virtual_terminal {
|
||||
bool active;
|
||||
bool canonical;
|
||||
|
||||
spinlock terminal_lock;
|
||||
|
||||
circular_buffer<char, INPUT_BUFFER_SIZE> input_buffer;
|
||||
circular_buffer<char, INPUT_BUFFER_SIZE> canonical_buffer;
|
||||
|
||||
sleep_queue input_queue;
|
||||
|
||||
void print(char c);
|
||||
void send_input(char c);
|
||||
void handle_input(char c);
|
||||
size_t read_input(char* buffer, size_t max);
|
||||
|
||||
//Perhaps remove that
|
||||
void send_input(char c);
|
||||
|
||||
virtual_terminal(){}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "disks.hpp"
|
||||
|
||||
#include "mutex.hpp"
|
||||
#include "semaphore.hpp"
|
||||
#include "lock_guard.hpp"
|
||||
|
||||
namespace {
|
||||
@ -60,58 +59,65 @@ static constexpr const size_t BLOCK_SIZE = 512;
|
||||
|
||||
ata::drive_descriptor* drives;
|
||||
|
||||
//TODO Use one lock per controller
|
||||
//TODO Separate all the data in structure controller
|
||||
|
||||
mutex controller_lock;
|
||||
|
||||
semaphore primary_sem;
|
||||
semaphore secondary_sem;
|
||||
volatile size_t primary_wait_pid = 0;
|
||||
volatile bool primary_release = false;
|
||||
volatile bool primary_wait = false;
|
||||
|
||||
volatile bool primary_invoked = false;
|
||||
volatile bool secondary_invoked = false;
|
||||
volatile size_t secondary_wait_pid = 0;
|
||||
volatile bool secondary_release = false;
|
||||
volatile bool secondary_wait = false;
|
||||
|
||||
//TODO In the future, the wait for IRQs, could
|
||||
//be done with a semaphore
|
||||
|
||||
void primary_controller_handler(interrupt::syscall_regs*){
|
||||
//primary_invoked = true;
|
||||
primary_sem.signal();
|
||||
//TODO Perhaps not correct
|
||||
//TODO Should choose the controller more safely
|
||||
static void ata_delay(){
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
in_byte(0x1F0 + ATA_STATUS);
|
||||
}
|
||||
|
||||
void secondary_controller_handler(interrupt::syscall_regs*){
|
||||
//secondary_invoked = true;
|
||||
secondary_sem.signal();
|
||||
void primary_controller_handler(interrupt::syscall_regs*){
|
||||
scheduler::soft_unblock(primary_wait_pid);
|
||||
// primary_release = true;
|
||||
// if(!primary_wait){
|
||||
// scheduler::irq_sync_release(primary_wait_pid);
|
||||
// }
|
||||
}
|
||||
|
||||
void ata_wait_irq_primary(){
|
||||
primary_sem.wait();
|
||||
/*while(!primary_invoked){
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
}
|
||||
|
||||
primary_invoked = false;*/
|
||||
scheduler::soft_reschedule(scheduler::get_pid());
|
||||
// primary_wait = true;
|
||||
// if(!primary_release){
|
||||
// scheduler::irq_sync_wait();
|
||||
// }
|
||||
|
||||
//Cleanup
|
||||
//primary_wait = false;
|
||||
//primary_release = false;
|
||||
}
|
||||
|
||||
void secondary_controller_handler(interrupt::syscall_regs*){
|
||||
//TODO
|
||||
}
|
||||
void ata_wait_irq_secondary(){
|
||||
secondary_sem.wait();
|
||||
/*while(!secondary_invoked){
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
}
|
||||
|
||||
secondary_invoked = false;*/
|
||||
//TODO
|
||||
}
|
||||
|
||||
static uint8_t wait_for_controller(uint16_t controller, uint8_t mask, uint8_t value, uint16_t timeout){
|
||||
uint8_t status;
|
||||
do {
|
||||
status = in_byte(controller + ATA_STATUS);
|
||||
timer::sleep_ms(1);
|
||||
ata_delay();
|
||||
//timer::sleep_ms(1);
|
||||
} while ((status & mask) != value && --timeout);
|
||||
|
||||
return timeout;
|
||||
@ -130,7 +136,7 @@ bool select_device(ata::drive_descriptor& drive){
|
||||
out_byte(controller + ATA_DRV_HEAD, 0xA0 | (drive.slave << 4));
|
||||
|
||||
//Sleep at least 400ns before reading the status register
|
||||
timer::sleep_ms(1);
|
||||
ata_delay();
|
||||
|
||||
if(!wait_for_controller(controller, wait_mask, 0, 10000)){
|
||||
return false;
|
||||
@ -152,6 +158,15 @@ bool read_write_sector(ata::drive_descriptor& drive, uint64_t start, void* data,
|
||||
uint8_t ch = (start >> 16) & 0xFF;
|
||||
uint8_t hd = (start >> 24) & 0x0F;
|
||||
|
||||
//Prepare for waiting
|
||||
if(controller == ATA_PRIMARY){
|
||||
primary_wait_pid = scheduler::get_pid();
|
||||
} else {
|
||||
secondary_wait_pid = scheduler::get_pid();
|
||||
}
|
||||
|
||||
scheduler::soft_block(scheduler::get_pid());
|
||||
|
||||
auto command = read ? ATA_READ_BLOCK : ATA_WRITE_BLOCK;
|
||||
|
||||
//Process the command
|
||||
@ -163,7 +178,7 @@ bool read_write_sector(ata::drive_descriptor& drive, uint64_t start, void* data,
|
||||
out_byte(controller + ATA_COMMAND, command);
|
||||
|
||||
//Wait at least 400ns before reading status register
|
||||
timer::sleep_ms(1);
|
||||
ata_delay();
|
||||
|
||||
//Wait at most 30 seconds for BSY flag to be cleared
|
||||
if(!wait_for_controller(controller, ATA_STATUS_BSY, 0, 30000)){
|
||||
@ -339,9 +354,6 @@ void identify(ata::drive_descriptor& drive){
|
||||
void ata::detect_disks(){
|
||||
controller_lock.init();
|
||||
|
||||
primary_sem.init(0);
|
||||
secondary_sem.init(0);
|
||||
|
||||
drives = new drive_descriptor[4];
|
||||
|
||||
drives[0] = {ATA_PRIMARY, 0xE0, false, MASTER_BIT, false, "", "", ""};
|
||||
|
@ -88,10 +88,6 @@ void kernel_main(){
|
||||
timer::install();
|
||||
//acpi::init();
|
||||
keyboard::install_driver();
|
||||
disks::detect_disks();
|
||||
|
||||
//Init the virtual file system
|
||||
vfs::init();
|
||||
|
||||
//Only install system calls when everything else is ready
|
||||
install_system_calls();
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "kernel_utils.hpp"
|
||||
#include "terminal.hpp"
|
||||
|
||||
//TODO REMOVE
|
||||
#include "console.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
char qwertz[128] = {
|
||||
@ -93,7 +96,9 @@ char shifted_qwertz[128] = {
|
||||
void keyboard_handler(interrupt::syscall_regs*){
|
||||
auto key = static_cast<char>(in_byte(0x60));
|
||||
|
||||
stdio::get_active_terminal().send_input(key);
|
||||
if(scheduler::is_started()){
|
||||
stdio::get_active_terminal().send_input(key);
|
||||
}
|
||||
}
|
||||
|
||||
} //end of anonymous namespace
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "mutex.hpp"
|
||||
#include "kernel_utils.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "circular_buffer.hpp"
|
||||
|
||||
constexpr const bool DEBUG_SCHEDULER = false;
|
||||
|
||||
@ -39,11 +40,12 @@ namespace {
|
||||
|
||||
struct process_control_t {
|
||||
scheduler::process_t process;
|
||||
scheduler::process_state state;
|
||||
volatile scheduler::process_state state;
|
||||
size_t rounds;
|
||||
size_t sleep_timeout;
|
||||
std::vector<std::vector<std::string>> handles;
|
||||
std::vector<std::string> working_directory;
|
||||
scheduler::sleep_queue_ptr queue_ptr;
|
||||
};
|
||||
|
||||
//The Process Control Block
|
||||
@ -53,27 +55,70 @@ std::array<process_control_t, scheduler::MAX_PROCESS> pcb;
|
||||
std::array<std::vector<scheduler::pid_t>, scheduler::PRIORITY_LEVELS> run_queues;
|
||||
std::array<mutex, scheduler::PRIORITY_LEVELS> run_queue_locks;
|
||||
|
||||
std::array<circular_buffer<scheduler::tasklet, 32>, scheduler::PRIORITY_LEVELS> tasklets;
|
||||
|
||||
constexpr size_t priority_to_index(size_t priority){
|
||||
return priority - scheduler::MIN_PRIORITY;
|
||||
}
|
||||
|
||||
std::vector<scheduler::pid_t>& run_queue(size_t priority){
|
||||
return run_queues[priority - scheduler::MIN_PRIORITY];
|
||||
return run_queues[priority_to_index(priority)];
|
||||
}
|
||||
|
||||
mutex& run_queue_lock(size_t priority){
|
||||
return run_queue_locks[priority - scheduler::MIN_PRIORITY];
|
||||
return run_queue_locks[priority_to_index(priority)];
|
||||
}
|
||||
|
||||
bool started = false;
|
||||
|
||||
constexpr const size_t STACK_ALIGNMENT = 16;
|
||||
|
||||
constexpr const size_t TURNOVER = 10;
|
||||
constexpr const size_t QUANTUM_SIZE = 1000;
|
||||
constexpr const size_t QUANTUM_SIZE = 100;
|
||||
|
||||
size_t current_ticks = 0;
|
||||
volatile bool started = false;
|
||||
|
||||
size_t current_pid;
|
||||
size_t next_pid = 0;
|
||||
volatile size_t current_ticks = 0;
|
||||
|
||||
size_t gc_pid = 0;
|
||||
volatile size_t current_pid = 0;
|
||||
volatile size_t next_pid = 0;
|
||||
|
||||
scheduler::pid_t init_pid = 0;
|
||||
scheduler::pid_t idle_pid = 0;
|
||||
scheduler::pid_t gc_pid = 0;
|
||||
|
||||
std::array<scheduler::pid_t, scheduler::PRIORITY_LEVELS> tasklets_executors_pids;
|
||||
|
||||
size_t select_next_process();
|
||||
void switch_to_process(size_t pid);
|
||||
|
||||
template<size_t priority>
|
||||
void tasklet_executor_task() {
|
||||
auto index = priority_to_index(priority);
|
||||
|
||||
while(true){
|
||||
|
||||
while(!tasklets[index].empty()){
|
||||
auto task = tasklets[index].pop();
|
||||
task.fun(task.d1, task.d2);
|
||||
}
|
||||
|
||||
k_print_line("executor");
|
||||
|
||||
//Wait until there is something to do
|
||||
//scheduler::block_process(current_pid);
|
||||
|
||||
asm volatile ("cli");
|
||||
|
||||
pcb[current_pid].state = scheduler::process_state::BLOCKED;
|
||||
|
||||
switch_to_process(select_next_process());
|
||||
|
||||
asm volatile ("sti");
|
||||
|
||||
k_print_line(current_pid);
|
||||
|
||||
k_print_line("executorafter");
|
||||
}
|
||||
}
|
||||
|
||||
void idle_task(){
|
||||
while(true){
|
||||
@ -84,7 +129,7 @@ void idle_task(){
|
||||
void gc_task(){
|
||||
while(true){
|
||||
//Wait until there is something to do
|
||||
scheduler::block_process(scheduler::get_pid());
|
||||
scheduler::block_process(current_pid);
|
||||
|
||||
//2. Clean up each killed process
|
||||
|
||||
@ -114,15 +159,17 @@ void gc_task(){
|
||||
paging::unmap_pages(desc.virtual_kernel_stack, scheduler::kernel_stack_size / paging::PAGE_SIZE);
|
||||
|
||||
//6. Remove process from run queue
|
||||
asm volatile("cli");
|
||||
size_t index = 0;
|
||||
for(; index < run_queue(desc.priority).size(); ++index){
|
||||
std::lock_guard<mutex> l(run_queue_lock(desc.priority));
|
||||
//std::lock_guard<mutex> l(run_queue_lock(desc.priority));
|
||||
|
||||
if(run_queue(desc.priority)[index] == desc.pid){
|
||||
run_queue(desc.priority).erase(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
asm volatile("sti");
|
||||
|
||||
//7. Clean process
|
||||
desc.pid = 0;
|
||||
@ -148,10 +195,16 @@ void gc_task(){
|
||||
|
||||
//TODO tsh should be configured somewhere
|
||||
void init_task(){
|
||||
//Starting from here, the logging system can output logs to file
|
||||
logging::to_file();
|
||||
//Detect disks
|
||||
disks::detect_disks();
|
||||
|
||||
logging::log("init_task started");
|
||||
//Init the virtual file system
|
||||
vfs::init();
|
||||
|
||||
//Starting from here, the logging system can output logs to file
|
||||
//logging::to_file();
|
||||
|
||||
//logging::log("init_task started");
|
||||
|
||||
std::vector<std::string> params;
|
||||
|
||||
@ -174,6 +227,9 @@ char init_kernel_stack[scheduler::kernel_stack_size];
|
||||
char gc_stack[scheduler::user_stack_size];
|
||||
char gc_kernel_stack[scheduler::kernel_stack_size];
|
||||
|
||||
std::array<char[scheduler::user_stack_size], scheduler::PRIORITY_LEVELS> tasklet_executor_stacks;
|
||||
std::array<char[scheduler::kernel_stack_size], scheduler::PRIORITY_LEVELS> tasklet_executor_kernel_stacks;
|
||||
|
||||
scheduler::process_t& new_process(){
|
||||
//TODO use get_free_pid() that searchs through the PCB
|
||||
auto pid = next_pid++;
|
||||
@ -203,8 +259,9 @@ void queue_process(scheduler::pid_t pid){
|
||||
|
||||
process.state = scheduler::process_state::READY;
|
||||
|
||||
std::lock_guard<mutex> l(run_queue_lock(process.process.priority));
|
||||
asm volatile("cli");
|
||||
run_queue(process.process.priority).push_back(pid);
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
scheduler::process_t& create_kernel_task(char* user_stack, char* kernel_stack, void (*fun)()){
|
||||
@ -244,6 +301,8 @@ void create_idle_task(){
|
||||
idle_process.priority = scheduler::MIN_PRIORITY;
|
||||
|
||||
queue_process(idle_process.pid);
|
||||
|
||||
idle_pid = idle_process.pid;
|
||||
}
|
||||
|
||||
void create_init_task(){
|
||||
@ -253,6 +312,8 @@ void create_init_task(){
|
||||
init_process.priority = scheduler::MIN_PRIORITY + 1;
|
||||
|
||||
queue_process(init_process.pid);
|
||||
|
||||
init_pid = init_process.pid;
|
||||
}
|
||||
|
||||
void create_gc_task(){
|
||||
@ -266,6 +327,36 @@ void create_gc_task(){
|
||||
gc_pid = gc_process.pid;
|
||||
}
|
||||
|
||||
template<size_t priority>
|
||||
std::enable_if_t<(priority > scheduler::MAX_PRIORITY)> create_tasklet_executor(){
|
||||
//Break recursion
|
||||
}
|
||||
|
||||
template<size_t priority>
|
||||
std::enable_if_t<(priority <= scheduler::MAX_PRIORITY)> create_tasklet_executor(){
|
||||
auto index = priority_to_index(priority);
|
||||
|
||||
auto& process = create_kernel_task(
|
||||
tasklet_executor_stacks[index],
|
||||
tasklet_executor_kernel_stacks[index],
|
||||
&tasklet_executor_task<priority>);
|
||||
|
||||
process.ppid = 1;
|
||||
process.priority = priority;
|
||||
|
||||
queue_process(process.pid);
|
||||
|
||||
pcb[process.pid].state = scheduler::process_state::BLOCKED;
|
||||
|
||||
tasklets_executors_pids[index] = process.pid;
|
||||
|
||||
create_tasklet_executor<priority+1>();
|
||||
}
|
||||
|
||||
void create_tasklet_executors(){
|
||||
create_tasklet_executor<scheduler::MIN_PRIORITY>();
|
||||
}
|
||||
|
||||
void switch_to_process(size_t pid){
|
||||
auto old_pid = current_pid;
|
||||
current_pid = pid;
|
||||
@ -289,7 +380,7 @@ size_t select_next_process(){
|
||||
|
||||
//1. Run a process of higher priority, if any
|
||||
for(size_t p = scheduler::MAX_PRIORITY; p > current_priority; --p){
|
||||
std::lock_guard<mutex> l(run_queue_lock(p));
|
||||
//std::lock_guard<mutex> l(run_queue_lock(p));
|
||||
|
||||
for(auto pid : run_queue(p)){
|
||||
if(pcb[pid].state == scheduler::process_state::READY){
|
||||
@ -301,7 +392,7 @@ size_t select_next_process(){
|
||||
//2. Run the next process of the same priority
|
||||
|
||||
{
|
||||
std::lock_guard<mutex> l(run_queue_lock(current_priority));
|
||||
//std::lock_guard<mutex> l(run_queue_lock(current_priority));
|
||||
|
||||
auto& current_run_queue = run_queue(current_priority);
|
||||
|
||||
@ -323,12 +414,10 @@ size_t select_next_process(){
|
||||
}
|
||||
}
|
||||
|
||||
thor_assert(current_priority > 0, "The idle task should always be ready");
|
||||
|
||||
//3. Run a process of lower priority
|
||||
|
||||
for(size_t p = current_priority - 1; p >= scheduler::MIN_PRIORITY; --p){
|
||||
std::lock_guard<mutex> l(run_queue_lock(p));
|
||||
//std::lock_guard<mutex> l(run_queue_lock(p));
|
||||
|
||||
for(auto pid : run_queue(p)){
|
||||
if(pcb[pid].state == scheduler::process_state::READY){
|
||||
@ -337,6 +426,8 @@ size_t select_next_process(){
|
||||
}
|
||||
}
|
||||
|
||||
thor_assert(pcb[idle_pid].state == scheduler::process_state::READY, "The idle task should always be ready");
|
||||
|
||||
thor_unreachable("No process is READY");
|
||||
}
|
||||
|
||||
@ -588,6 +679,7 @@ void scheduler::init(){ //Create the idle task
|
||||
create_idle_task();
|
||||
create_init_task();
|
||||
create_gc_task();
|
||||
create_tasklet_executors();
|
||||
|
||||
current_ticks = 0;
|
||||
|
||||
@ -602,7 +694,33 @@ void scheduler::start(){
|
||||
init_task_switch(current_pid);
|
||||
}
|
||||
|
||||
bool scheduler::is_started(){
|
||||
return started;
|
||||
}
|
||||
|
||||
void scheduler::irq_register_tasklet(const tasklet& task, size_t priority){
|
||||
thor_assert(started, "The scheduler must be started before irq_register_tasklet is called");
|
||||
|
||||
tasklets[priority_to_index(priority)].push(task);
|
||||
|
||||
auto pid = tasklets_executors_pids[priority_to_index(priority)];
|
||||
|
||||
thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::RUNNING || pcb[pid].state == process_state::READY, "Invalid state for tasklet executor");
|
||||
|
||||
/*k_print_line("irq_register");
|
||||
k_print_line(current_pid);
|
||||
k_print_line(pid);
|
||||
k_print_line(priority);
|
||||
k_print_line(static_cast<size_t>(pcb[pid].state));*/
|
||||
|
||||
if(pcb[pid].state == process_state::BLOCKED){
|
||||
pcb[pid].state = process_state::READY;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t scheduler::exec(const std::string& file, const std::vector<std::string>& params){
|
||||
thor_assert(started, "The scheduler must be started before exec is called");
|
||||
|
||||
std::string content;
|
||||
auto result = vfs::direct_read(file, content);
|
||||
if(result < 0){
|
||||
@ -653,12 +771,14 @@ int64_t scheduler::exec(const std::string& file, const std::vector<std::string>&
|
||||
pcb[process.pid].working_directory.push_back(p);
|
||||
}
|
||||
|
||||
logging::logf("Exec process pid=%u, ppid=%u", process.pid, process.ppid);
|
||||
//logging::logf("Exec process pid=%u, ppid=%u", process.pid, process.ppid);
|
||||
|
||||
return process.pid;
|
||||
}
|
||||
|
||||
void scheduler::sbrk(size_t inc){
|
||||
thor_assert(started, "The scheduler must be started before sbrk is called");
|
||||
|
||||
auto& process = pcb[current_pid].process;
|
||||
|
||||
size_t size = (inc + paging::PAGE_SIZE - 1) & ~(paging::PAGE_SIZE - 1);
|
||||
@ -689,6 +809,8 @@ void scheduler::sbrk(size_t inc){
|
||||
}
|
||||
|
||||
void scheduler::await_termination(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before await_termination is called");
|
||||
|
||||
while(true){
|
||||
bool found = false;
|
||||
for(auto& process : pcb){
|
||||
@ -705,12 +827,16 @@ void scheduler::await_termination(pid_t pid){
|
||||
return;
|
||||
}
|
||||
|
||||
asm volatile("cli");
|
||||
pcb[current_pid].state = process_state::WAITING;
|
||||
reschedule();
|
||||
asm volatile("sti");
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler::kill_current_process(){
|
||||
thor_assert(started, "The scheduler must be started before kill_current_process is called");
|
||||
|
||||
if(DEBUG_SCHEDULER){
|
||||
printf("Kill %u\n", current_pid);
|
||||
}
|
||||
@ -752,11 +878,11 @@ void scheduler::tick(){
|
||||
if(current_ticks % QUANTUM_SIZE == 0){
|
||||
auto& process = pcb[current_pid];
|
||||
|
||||
if(process.rounds == TURNOVER){
|
||||
if(process.rounds == TURNOVER){
|
||||
process.rounds = 0;
|
||||
|
||||
process.state = process_state::READY;
|
||||
|
||||
|
||||
auto pid = select_next_process();
|
||||
|
||||
//If it is the same, no need to go to the switching process
|
||||
@ -776,29 +902,39 @@ void scheduler::tick(){
|
||||
void scheduler::reschedule(){
|
||||
thor_assert(started, "No interest in rescheduling before start");
|
||||
|
||||
//asm volatile ("cli");
|
||||
|
||||
auto& process = pcb[current_pid];
|
||||
|
||||
//The process just got blocked or put to sleep, choose another one
|
||||
if(process.state != process_state::RUNNING){
|
||||
auto index = select_next_process();
|
||||
auto pid = select_next_process();
|
||||
|
||||
switch_to_process(index);
|
||||
switch_to_process(pid);
|
||||
}
|
||||
|
||||
//asm volatile ("sti");
|
||||
|
||||
//At this point we just have to return to the current process
|
||||
}
|
||||
|
||||
scheduler::pid_t scheduler::get_pid(){
|
||||
thor_assert(started, "The scheduler must be started before get_pid is called");
|
||||
|
||||
return current_pid;
|
||||
}
|
||||
|
||||
scheduler::process_t& scheduler::get_process(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before get_process is called");
|
||||
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
|
||||
return pcb[pid].process;
|
||||
}
|
||||
|
||||
void scheduler::block_process(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before block_process is called");
|
||||
thor_assert(pid != idle_pid, "Cannot block the idle task");
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
thor_assert(pcb[pid].state == process_state::RUNNING, "Can only block RUNNING processes");
|
||||
|
||||
@ -806,12 +942,16 @@ void scheduler::block_process(pid_t pid){
|
||||
printf("Block process %u\n", pid);
|
||||
}
|
||||
|
||||
asm volatile("cli");
|
||||
pcb[pid].state = process_state::BLOCKED;
|
||||
|
||||
reschedule();
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void scheduler::unblock_process(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before unblock_process is called");
|
||||
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::WAITING, "Can only unblock BLOCKED/WAITING processes");
|
||||
|
||||
@ -819,10 +959,48 @@ void scheduler::unblock_process(pid_t pid){
|
||||
printf("Unblock process %u\n", pid);
|
||||
}
|
||||
|
||||
asm volatile("cli");
|
||||
pcb[pid].state = process_state::READY;
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
scheduler::sleep_queue_ptr* scheduler::queue_ptr(scheduler::pid_t pid){
|
||||
return &pcb[pid].queue_ptr;
|
||||
}
|
||||
|
||||
void scheduler::soft_block(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before soft_block is called");
|
||||
thor_assert(pid != idle_pid, "Cannot soft block the idle task");
|
||||
|
||||
|
||||
asm volatile("cli");
|
||||
pcb[pid].state = process_state::BLOCKED;
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void scheduler::soft_unblock(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before soft_unblock is called");
|
||||
|
||||
asm volatile("cli");
|
||||
pcb[pid].state = process_state::READY;
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void scheduler::soft_reschedule(pid_t pid){
|
||||
thor_assert(started, "The scheduler must be started before soft_reschedule is called");
|
||||
|
||||
asm volatile("cli");
|
||||
if(pcb[pid].state == process_state::READY){
|
||||
pcb[pid].state = process_state::RUNNING;
|
||||
} else {
|
||||
reschedule();
|
||||
}
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void scheduler::sleep_ms(pid_t pid, size_t time){
|
||||
thor_assert(started, "The scheduler must be started before sleep_ms is called");
|
||||
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
thor_assert(pcb[pid].state == process_state::RUNNING, "Only RUNNING processes can sleep");
|
||||
|
||||
@ -837,27 +1015,39 @@ void scheduler::sleep_ms(pid_t pid, size_t time){
|
||||
}
|
||||
|
||||
size_t scheduler::register_new_handle(const std::vector<std::string>& path){
|
||||
thor_assert(started, "The scheduler must be started before new_handle is called");
|
||||
|
||||
pcb[current_pid].handles.push_back(path);
|
||||
|
||||
return pcb[current_pid].handles.size() - 1;
|
||||
}
|
||||
|
||||
void scheduler::release_handle(size_t fd){
|
||||
thor_assert(started, "The scheduler must be started before release_handle is called");
|
||||
|
||||
pcb[current_pid].handles[fd].clear();
|
||||
}
|
||||
|
||||
bool scheduler::has_handle(size_t fd){
|
||||
thor_assert(started, "The scheduler must be started before has_handle is called");
|
||||
|
||||
return fd < pcb[current_pid].handles.size();
|
||||
}
|
||||
|
||||
const std::vector<std::string>& scheduler::get_handle(size_t fd){
|
||||
thor_assert(started, "The scheduler must be started before get_handle is called");
|
||||
|
||||
return pcb[current_pid].handles[fd];
|
||||
}
|
||||
|
||||
const std::vector<std::string>& scheduler::get_working_directory(){
|
||||
thor_assert(started, "The scheduler must be started before get_working_directory is called");
|
||||
|
||||
return pcb[current_pid].working_directory;
|
||||
}
|
||||
|
||||
void scheduler::set_working_directory(const std::vector<std::string>& directory){
|
||||
thor_assert(started, "The scheduler must be started before set_working_directory is called");
|
||||
|
||||
pcb[current_pid].working_directory = directory;
|
||||
}
|
||||
|
@ -21,6 +21,13 @@ bool shift = false;
|
||||
|
||||
std::array<stdio::virtual_terminal, MAX_TERMINALS> terminals;
|
||||
|
||||
void tasklet_handle_input(size_t d1, size_t d2){
|
||||
auto key = static_cast<char>(d1);
|
||||
auto term = reinterpret_cast<stdio::virtual_terminal*>(d2);
|
||||
|
||||
term->handle_input(key);
|
||||
}
|
||||
|
||||
} //end of anonymous namespace
|
||||
|
||||
void stdio::virtual_terminal::print(char key){
|
||||
@ -29,7 +36,18 @@ void stdio::virtual_terminal::print(char key){
|
||||
}
|
||||
|
||||
void stdio::virtual_terminal::send_input(char key){
|
||||
scheduler::tasklet task;
|
||||
task.fun = &tasklet_handle_input;
|
||||
task.d1 = key;
|
||||
task.d2 = reinterpret_cast<size_t>(this);
|
||||
|
||||
scheduler::irq_register_tasklet(task, scheduler::DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
void stdio::virtual_terminal::handle_input(char key){
|
||||
if(canonical){
|
||||
std::lock_guard<spinlock> l(terminal_lock);
|
||||
|
||||
//Key released
|
||||
if(key & 0x80){
|
||||
key &= ~(0x80);
|
||||
@ -74,37 +92,41 @@ size_t stdio::virtual_terminal::read_input(char* buffer, size_t max){
|
||||
char c;
|
||||
|
||||
while(true){
|
||||
while(read < max && !input_buffer.empty()){
|
||||
c = input_buffer.pop();
|
||||
{
|
||||
std::lock_guard<spinlock> l(terminal_lock);
|
||||
|
||||
canonical_buffer.push(c);
|
||||
while(read < max && !input_buffer.empty()){
|
||||
c = input_buffer.pop();
|
||||
|
||||
if(c == '\b'){
|
||||
if(read > 0){
|
||||
--read;
|
||||
}
|
||||
} else {
|
||||
++read;
|
||||
canonical_buffer.push(c);
|
||||
|
||||
if(c == '\n'){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(read > 0 && (c == '\n' || read == max)){
|
||||
read = 0;
|
||||
while(!canonical_buffer.empty()){
|
||||
auto value = canonical_buffer.pop();
|
||||
|
||||
if(value == '\b'){
|
||||
--read;
|
||||
if(c == '\b'){
|
||||
if(read > 0){
|
||||
--read;
|
||||
}
|
||||
} else {
|
||||
buffer[read++] = value;
|
||||
++read;
|
||||
|
||||
if(c == '\n'){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
if(read > 0 && (c == '\n' || read == max)){
|
||||
read = 0;
|
||||
while(!canonical_buffer.empty()){
|
||||
auto value = canonical_buffer.pop();
|
||||
|
||||
if(value == '\b'){
|
||||
--read;
|
||||
} else {
|
||||
buffer[read++] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
input_queue.sleep();
|
||||
|
@ -15,36 +15,30 @@ private:
|
||||
|
||||
T buffer[Size];
|
||||
|
||||
volatile size_t start;
|
||||
volatile size_t end;
|
||||
volatile size_t tail;
|
||||
volatile size_t head;
|
||||
|
||||
public:
|
||||
circular_buffer() : start(0), end(0) {
|
||||
circular_buffer() : tail(0), head(0) {
|
||||
//Nothing to init
|
||||
}
|
||||
|
||||
bool full() const {
|
||||
return (end + 1) % Size == start;
|
||||
return tail - head == S;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return end == start;
|
||||
return tail - head == 0;
|
||||
}
|
||||
|
||||
bool push(T value){
|
||||
if(full()){
|
||||
return false;
|
||||
} else {
|
||||
buffer[end] = value;
|
||||
end = (end + 1) % Size;
|
||||
|
||||
return true;
|
||||
}
|
||||
void push(T value){
|
||||
buffer[tail % S] = value;
|
||||
++tail;
|
||||
}
|
||||
|
||||
T pop(){
|
||||
auto value = buffer[start];
|
||||
start = (start + 1) % Size;
|
||||
auto value = buffer[head % S];
|
||||
++head;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user