This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
hilbert-os/kernel/source/application.cpp

324 lines
8.8 KiB
C++

#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/utility.hpp>
#include <hilbert/kernel/input.hpp>
namespace hilbert::kernel::application {
//returns pointer to copy
extern "C" void *copy_syscall_stack(const uint8_t *bottom) {
uint64_t len = 0xfffffffffffff000 - (uint64_t)bottom;
uint8_t *buffer = new uint8_t[len];
for (uint64_t i = 0; i < len; ++i)
buffer[i] = bottom[i];
return buffer;
}
extern "C" void restore_syscall_stack(uint8_t *from, uint8_t *to) {
uint64_t len = 0xfffffffffffff000 - (uint64_t)to;
for (uint64_t i = 0; i < len; ++i)
to[i] = from[i];
delete[] from;
}
utility::id_allocator<process *> *all_processes;
utility::queue<thread *> *paused_threads;
thread *running_thread;
struct socket_listener_registration {
socket_listener *listener;
utility::string id;
};
utility::list<socket_listener_registration> *all_running_socket_listeners;
extern "C" void init_applications_asm();
void init_applications() {
all_processes = new utility::id_allocator<process *>();
paused_threads = new utility::queue<thread *>();
running_thread = 0;
all_running_socket_listeners =
new utility::list<socket_listener_registration>();
init_applications_asm();
}
uint64_t add_process(process *p) {
return p->id = all_processes->add_new(utility::move(p));
}
socket_listener *try_register_socket_listener(const utility::string &id) {
for (auto *n = all_running_socket_listeners->first; n; n = n->next)
if (n->value.id == id)
return 0;
socket_listener *sl = new socket_listener();
all_running_socket_listeners->insert_end({.listener = sl, .id = id});
return sl;
}
socket_listener *try_get_socket_listener(const utility::string &id) {
for (auto *n = all_running_socket_listeners->first; n; n = n->next)
if (n->value.id == id)
return n->value.listener;
return 0;
}
void remove_socket_listener(socket_listener *sl) {
for (auto *n = all_running_socket_listeners->first; n; n = n->next)
if (n->value.listener == sl) {
all_running_socket_listeners->remove(n);
delete sl;
return;
}
}
//cpu argument not on stack.
extern "C" [[noreturn]] void resume_thread(const cpu_state &cpu);
extern "C" [[noreturn]] void resume_next_thread() {
running_thread = 0;
while (paused_threads->count == 0)
asm volatile ("sti\nhlt\ncli");
thread *t = paused_threads->take();
running_thread = t;
resume_thread(t->saved_state);
}
process::process(app_memory *memory, const utility::string &name)
: name(name), memory(memory) {}
process::~process() {
delete memory; //:p
}
process::string_pair *process::find_environment_variable(
const utility::string &name) {
for (auto *n = environment_variables.first; n; n = n->next)
if (n->value.a == name)
return &n->value;
return 0;
}
void process::set_environment_variable(
utility::string &&name, utility::string &&value) {
auto *sp = find_environment_variable(name);
if (sp)
sp->b = utility::move(value);
else
environment_variables.insert_end({
.a = utility::move(name),
.b = utility::move(value)
});
}
void process::set_environment_variable(
const utility::string &name, const utility::string &value) {
auto *sp = find_environment_variable(name);
if (sp)
sp->b = value;
else
environment_variables.insert_end({
.a = name, .b = value
});
}
utility::string *process::get_environment_variable(
const utility::string &name) {
for (auto *i = environment_variables.first; i; i = i->next)
if (i->value.a == name)
return &i->value.b;
return 0;
}
void process::add_thread(thread *t) {
threads.insert_end(t);
}
void process::notify_thread_ended(thread *t, int exit_code) {
threads.remove_first_of(t);
if (threads.first == 0)
on_end_process(exit_code);
}
void process::on_end_process(int exit_code) {
while (threads.first) {
threads.first->value->on_end_thread();
delete threads.first->value;
threads.remove(threads.first);
}
//TODO: destroy file streams
//TODO: destroy socket streams
//TODO: destroy socket listeners
this->exit_code = exit_code;
}
bool process::has_ended() const {
return threads.first == 0;
}
unsigned process::add_file_stream(file_stream *stream) {
return open_streams.add_new({
.is_socket = false, .as_file_stream = stream });
}
unsigned process::add_socket_stream(socket_stream_end *stream) {
return open_streams.add_new({
.is_socket = true, .as_socket_stream = stream });
}
unsigned process::add_socket_listener(socket_listener *sl) {
return running_socket_listeners.add_new(utility::move(sl));
}
generic_stream_ptr process::get_stream(unsigned handle) {
if (open_streams.has_id(handle))
return open_streams.get(handle);
return null_gsp;
}
generic_stream_ptr process::take_stream(unsigned handle) {
auto ptr = open_streams.get(handle);
open_streams.remove_id(handle);
return ptr;
}
void process::add_stream_with_handle(
unsigned handle, generic_stream_ptr ptr) {
open_streams.add_id(new generic_stream_ptr(ptr), handle);
}
socket_listener *process::get_socket_listener(unsigned handle) {
if (running_socket_listeners.has_id(handle))
return running_socket_listeners.get(handle);
return 0;
}
socket_listener *process::take_socket_listener(unsigned handle) {
if (running_socket_listeners.has_id(handle)) {
socket_listener *listener = running_socket_listeners.get(handle);
running_socket_listeners.remove_id(handle);
return listener;
}
return 0;
}
void process::close_stream(unsigned handle) {
if (!open_streams.has_id(handle))
return;
auto ptr = open_streams.get(handle);
open_streams.remove_id(handle);
if (ptr.is_socket) {
auto stream = ptr.as_socket_stream;
if (stream->is_other_side_open) {
stream->other_end->is_other_side_open = false;
auto &q = stream->other_end->waiting_to_read;
while (q.count > 0)
paused_threads->insert(q.take());
}
else
delete stream->the_socket;
delete stream;
}
}
thread::thread(process *owner, uint64_t entry)
: stack_top(owner->memory->map_new_stack()), waiting_for_socket_stream(0),
waiting_to_accept_from(0), waiting_to_connect_to(0), waiting_for_input(false),
name(utility::string("main", 4)), owner(owner) {
saved_state.rax = 0;
saved_state.rbx = 0;
saved_state.rcx = 0;
saved_state.rdx = 0;
saved_state.rdi = 0;
saved_state.rsi = 0;
saved_state.rbp = 0;
saved_state.rsp = stack_top;
saved_state.r8 = 0;
saved_state.r9 = 0;
saved_state.r10 = 0;
saved_state.r11 = 0;
saved_state.r12 = 0;
saved_state.r13 = 0;
saved_state.r14 = 0;
saved_state.r15 = 0;
saved_state.rflags = 0x200;
saved_state.rip = entry;
saved_state.cr3 = owner->memory->p4_paddr;
saved_state.in_syscall = false;
}
void thread::on_end_thread() {
owner->memory->unmap_stack(stack_top);
if (waiting_for_socket_stream)
waiting_for_socket_stream->waiting_to_read.remove(this);
else if (waiting_to_accept_from)
waiting_to_accept_from->waiting_to_accept.remove(this);
else if (waiting_to_connect_to)
waiting_to_connect_to->waiting_to_connect.remove(this);
else if (waiting_for_input)
input::waiting_for_input->remove(this);
}
void thread::wait_for_socket_stream(socket_stream_end *the_socket_stream) {
waiting_for_socket_stream = the_socket_stream;
the_socket_stream->waiting_to_read.insert(this);
yield(saved_state);
waiting_for_socket_stream = 0;
}
utility::maybe<unsigned> thread::wait_to_accept_from(
socket_listener *the_socket_listener) {
waiting_to_accept_from = the_socket_listener;
the_socket_listener->waiting_to_accept.insert(this);
yield(saved_state);
waiting_to_accept_from = 0;
return new_socket_stream_id;
}
utility::maybe<unsigned> thread::wait_to_connect_to(
socket_listener *the_socket_listener) {
waiting_to_connect_to = the_socket_listener;
the_socket_listener->waiting_to_connect.insert(this);
yield(saved_state);
waiting_to_connect_to = 0;
return new_socket_stream_id;
}
void thread::wait_for_input() {
waiting_for_input = true;
input::waiting_for_input->insert(this);
yield(saved_state);
waiting_for_input = false;
}
void thread::notify_no_socket_stream() {
new_socket_stream_id.has_value = false;
paused_threads->insert(this);
}
void thread::notify_new_socket_stream(unsigned id) {
new_socket_stream_id.has_value = true;
new_socket_stream_id.value = id;
paused_threads->insert(this);
}
}