#include #include #include 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 *all_processes; utility::queue *paused_threads; thread *running_thread; struct socket_listener_registration { socket_listener *listener; utility::string id; }; utility::list *all_running_socket_listeners; extern "C" void init_applications_asm(); void init_applications() { all_processes = new utility::id_allocator(); paused_threads = new utility::queue(); running_thread = 0; all_running_socket_listeners = new utility::list(); 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) : 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}); } 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), 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(); waiting_for_socket_stream = 0; } utility::maybe 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(); waiting_to_accept_from = 0; return new_socket_stream_id; } utility::maybe 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(); waiting_to_connect_to = 0; return new_socket_stream_id; } void thread::wait_for_input() { waiting_for_input = false; input::waiting_for_input->insert(this); yield(); 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); } }