Make everythign even worse than before

This commit is contained in:
Baptiste Wicht 2014-03-30 23:02:12 +02:00
parent 9cc34c05d7
commit 5feda76c93
14 changed files with 461 additions and 141 deletions

View File

@ -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
View File

@ -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

View 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

View File

@ -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));

View File

@ -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();
}
}
};

View File

@ -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();

View File

@ -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);
}
};

View File

@ -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(){}

View File

@ -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, "", "", ""};

View File

@ -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();

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}
};