291 lines
8.1 KiB
C++
291 lines
8.1 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
|
|
}
|
|
|
|
void process::add_environment_variable(
|
|
utility::string &&name, utility::string &&value) {
|
|
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);
|
|
}
|
|
|
|
}
|