#pragma once #include "arch/MMU.h" #include "fs/VFS.h" #include "memory/AddressSpace.h" #include #include #include #include #include #include #include #ifdef ARCH_X86_64 #include "arch/x86_64/CPU.h" #else #error "Unknown architecture." #endif enum class ThreadState { None, Idle, Runnable, Sleeping, Waiting, Exited, Dying }; struct OpenFileDescription : public Shareable { SharedPtr inode; int flags { 0 }; OpenFileDescription(SharedPtr, int); ~OpenFileDescription(); }; struct FileDescriptor { SharedPtr description; usize offset { 0 }; int flags { 0 }; bool should_append(); bool should_block(); bool is_writable(); bool is_readable(); SharedPtr inode() { return description->inode; } int& status_flags() { return description->flags; } }; static constexpr int FD_MAX = 64; struct Credentials { u32 uid { 0 }; u32 euid { 0 }; u32 suid { 0 }; u32 gid { 0 }; u32 egid { 0 }; u32 sgid { 0 }; }; struct Thread : public LinkedListNode { Registers regs; pid_t id; pid_t pgid { 0 }; Credentials auth; u64 user_ticks_self = 0; u64 kernel_ticks_self = 0; u64 user_ticks_children = 0; u64 kernel_ticks_children = 0; u64 ticks_left; u64 sleep_ticks_left; Stack stack; Stack kernel_stack; OwnedPtr address_space; Option fd_table[FD_MAX] = {}; Result allocate_fd(int min); Result resolve_fd(int fd); Result> resolve_atfile(int dirfd, const String& path, bool allow_empty_path, bool follow_last_symlink, SharedPtr* parent_inode = nullptr); struct sigaction signal_handlers[NSIG]; sigset_t signal_mask { 0 }; sigset_t pending_signals { 0 }; bool interrupted { false }; FPData fp_data; ThreadState state = ThreadState::Runnable; bool is_kernel { true }; bool has_called_exec { false }; int status { 0 }; mode_t umask { 0 }; StaticString<128> name; String current_directory_path = {}; SharedPtr current_directory = {}; Thread* parent { nullptr }; Option child_being_waited_for = {}; PageDirectory* self_directory() const { return address_space->page_directory(); } PageDirectory* active_directory { nullptr }; [[noreturn]] void exit_and_signal_parent(int status); bool is_idle() { return state == ThreadState::Idle; } void wake_up() { state = ThreadState::Runnable; } void init_regs_kernel(); void init_regs_user(); void set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4); void set_ip(u64 ip); u64 ip(); void set_sp(u64 sp); u64 sp(); void set_return(u64 ret); u64 return_register(); void process_pending_signals(Registers* current_regs); bool will_invoke_signal_handler(); bool deliver_signal(int signo, Registers* current_regs); void sigreturn(Registers* current_regs); Result push_mem_on_stack(const u8* mem, usize size); Result pop_mem_from_stack(u8* mem, usize size); void send_signal(int signo); static void init(); }; void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs); bool is_in_kernel(Registers* regs); Result new_thread(); pid_t next_thread_id(); extern LinkedList g_threads;