#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace LibELF { class ELF; } namespace Kernel { class Process { BAN_NON_COPYABLE(Process); BAN_NON_MOVABLE(Process); public: using entry_t = Thread::entry_t; struct userspace_info_t { uintptr_t entry { 0 }; int argc { 0 }; char** argv { nullptr }; char** envp { nullptr }; }; public: static Process* create_kernel(entry_t, void*); static BAN::ErrorOr create_userspace(const Credentials&, BAN::StringView); ~Process(); void cleanup_function(); void exit(int status, int signal); void add_thread(Thread*); void on_thread_exit(Thread&); pid_t pid() const { return m_pid; } BAN::ErrorOr sys_exit(int status); BAN::ErrorOr sys_gettermios(::termios*); BAN::ErrorOr sys_settermios(const ::termios*); BAN::ErrorOr sys_fork(uintptr_t rsp, uintptr_t rip); BAN::ErrorOr sys_exec(BAN::StringView path, const char* const* argv, const char* const* envp); BAN::ErrorOr sys_wait(pid_t pid, int* stat_loc, int options); BAN::ErrorOr sys_sleep(int seconds); BAN::ErrorOr sys_setenvp(char** envp); BAN::ErrorOr sys_setpwd(const char* path); BAN::ErrorOr sys_getpwd(char* buffer, size_t size); BAN::ErrorOr sys_setuid(uid_t); BAN::ErrorOr sys_setgid(gid_t); BAN::ErrorOr sys_seteuid(uid_t); BAN::ErrorOr sys_setegid(gid_t); BAN::ErrorOr sys_setreuid(uid_t, uid_t); BAN::ErrorOr sys_setregid(gid_t, gid_t); BAN::ErrorOr sys_getuid() const { return m_credentials.ruid(); } BAN::ErrorOr sys_getgid() const { return m_credentials.rgid(); } BAN::ErrorOr sys_geteuid() const { return m_credentials.euid(); } BAN::ErrorOr sys_getegid() const { return m_credentials.egid(); } BAN::ErrorOr sys_open(BAN::StringView, int, mode_t = 0); BAN::ErrorOr sys_openat(int, BAN::StringView, int, mode_t = 0); BAN::ErrorOr sys_close(int fd); BAN::ErrorOr sys_read(int fd, void* buffer, size_t count); BAN::ErrorOr sys_write(int fd, const void* buffer, size_t count); BAN::ErrorOr sys_creat(BAN::StringView name, mode_t); BAN::ErrorOr sys_pipe(int fildes[2]); BAN::ErrorOr sys_dup2(int fildes, int fildes2); BAN::ErrorOr sys_seek(int fd, off_t offset, int whence); BAN::ErrorOr sys_tell(int fd); BAN::ErrorOr sys_fstat(int fd, struct stat*); BAN::ErrorOr mount(BAN::StringView source, BAN::StringView target); BAN::ErrorOr sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size); BAN::ErrorOr sys_alloc(size_t); BAN::ErrorOr sys_free(void*); BAN::ErrorOr sys_signal(int, void (*)(int)); BAN::ErrorOr sys_raise(int signal); static BAN::ErrorOr sys_kill(pid_t pid, int signal); BAN::ErrorOr sys_tcsetpgrp(int fd, pid_t pgid); BAN::ErrorOr sys_termid(char*) const; BAN::ErrorOr sys_clock_gettime(clockid_t, timespec*) const; TTY& tty() { ASSERT(m_tty); return *m_tty; } static Process& current() { return Thread::current().process(); } PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); } bool is_userspace() const { return m_is_userspace; } const userspace_info_t& userspace_info() const { return m_userspace_info; } private: Process(const Credentials&, pid_t); static Process* create_process(const Credentials&); static void register_process(Process*); // Load an elf file to virtual address space of the current page table static BAN::ErrorOr> load_elf_for_exec(const Credentials&, BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env); // Copy an elf file from the current page table to the processes own void load_elf_to_memory(LibELF::ELF&); int block_until_exit(); BAN::ErrorOr absolute_path_of(BAN::StringView) const; private: struct ExitStatus { Semaphore semaphore; int exit_code { 0 }; bool exited { false }; int waiting { 0 }; }; Credentials m_credentials; OpenFileDescriptorSet m_open_file_descriptors; BAN::Vector> m_mapped_ranges; mutable RecursiveSpinLock m_lock; const pid_t m_pid = 0; BAN::String m_working_directory; BAN::Vector m_threads; BAN::Vector> m_fixed_width_allocators; BAN::UniqPtr m_general_allocator; vaddr_t m_signal_handlers[_SIGMAX + 1] { }; uint64_t m_signal_pending_mask { 0 }; bool m_is_userspace { false }; userspace_info_t m_userspace_info; ExitStatus m_exit_status; BAN::UniqPtr m_page_table; BAN::RefPtr m_tty; friend class Thread; }; }