1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:17:35 +00:00

Kernel: Introduce threads, and refactor everything in support of it.

The scheduler now operates on threads, rather than on processes.
Each process has a main thread, and can have any number of additional
threads. The process exits when the main thread exits.

This patch doesn't actually spawn any additional threads, it merely
does all the plumbing needed to make it possible. :^)
This commit is contained in:
Andreas Kling 2019-03-23 22:03:17 +01:00
parent b0de6aa8d8
commit 60d25f0f4a
32 changed files with 1356 additions and 1098 deletions

View file

@ -1,8 +1,6 @@
#pragma once
#include "types.h"
#include "TSS.h"
#include "i386.h"
#include "TTY.h"
#include "Syscall.h"
#include <Kernel/VirtualFileSystem.h>
@ -12,9 +10,9 @@
#include <AK/Vector.h>
#include <AK/WeakPtr.h>
#include <AK/Weakable.h>
#include <Kernel/Thread.h>
#include <Kernel/Lock.h>
class Alarm;
class FileDescriptor;
class PageDirectory;
class Region;
@ -31,26 +29,11 @@ struct CoolGlobals {
extern CoolGlobals* g_cool_globals;
#endif
enum class ShouldUnblockProcess { No = 0, Yes };
struct SignalActionData {
LinearAddress handler_or_sigaction;
dword mask { 0 };
int flags { 0 };
LinearAddress restorer;
};
struct DisplayInfo {
unsigned width;
unsigned height;
unsigned bpp;
unsigned pitch;
};
void kgettimeofday(timeval&);
class Process : public InlineLinkedListNode<Process>, public Weakable<Process> {
friend class InlineLinkedListNode<Process>;
friend class Thread;
public:
static Process* create_kernel_process(String&& name, void (*entry)());
static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
@ -58,29 +41,6 @@ public:
static Vector<pid_t> all_pids();
static Vector<Process*> all_processes();
static void finalize_dying_processes();
enum State {
Invalid = 0,
Runnable,
Running,
Skip1SchedulerPass,
Skip0SchedulerPasses,
Dying,
Dead,
Stopped,
BeingInspected,
BlockedLurking,
BlockedSleep,
BlockedWait,
BlockedRead,
BlockedWrite,
BlockedSignal,
BlockedSelect,
BlockedConnect,
BlockedReceive,
BlockedSnoozing,
};
enum Priority {
LowPriority,
@ -93,19 +53,20 @@ public:
Ring3 = 3,
};
// FIXME(Thread): Is this really how this should work?
bool is_dead() const { return main_thread().state() == Thread::State::Dead; }
Thread::State state() const { return main_thread().state(); }
Thread& main_thread() { return *m_main_thread; }
const Thread& main_thread() const { return *m_main_thread; }
bool is_ring0() const { return m_ring == Ring0; }
bool is_ring3() const { return m_ring == Ring3; }
bool is_stopped() const { return m_state == Stopped; }
bool is_blocked() const
{
return m_state == BlockedSleep || m_state == BlockedWait || m_state == BlockedRead || m_state == BlockedWrite || m_state == BlockedSignal || m_state == BlockedSelect;
}
PageDirectory& page_directory() { return *m_page_directory; }
const PageDirectory& page_directory() const { return *m_page_directory; }
bool in_kernel() const { return (m_tss.cs & 0x03) == 0; }
static Process* from_pid(pid_t);
void set_priority(Priority p) { m_priority = p; }
@ -115,10 +76,6 @@ public:
pid_t pid() const { return m_pid; }
pid_t sid() const { return m_sid; }
pid_t pgid() const { return m_pgid; }
dword ticks() const { return m_ticks; }
word selector() const { return m_far_ptr.selector; }
TSS32& tss() { return m_tss; }
State state() const { return m_state; }
uid_t uid() const { return m_uid; }
gid_t gid() const { return m_gid; }
const HashTable<gid_t>& gids() const { return m_gids; }
@ -130,34 +87,14 @@ public:
bool in_group(gid_t) const;
const FarPtr& far_ptr() const { return m_far_ptr; }
FileDescriptor* file_descriptor(int fd);
const FileDescriptor* file_descriptor(int fd) const;
void block(Process::State);
void unblock();
void set_wakeup_time(dword t) { m_wakeup_time = t; }
dword wakeup_time() const { return m_wakeup_time; }
void snooze_until(Alarm&);
template<typename Callback> static void for_each(Callback);
template<typename Callback> static void for_each_in_pgrp(pid_t, Callback);
template<typename Callback> static void for_each_in_state(State, Callback);
template<typename Callback> static void for_each_living(Callback);
template<typename Callback> void for_each_child(Callback);
template<typename Callback> void for_each_thread(Callback) const;
bool tick();
void set_ticks_left(dword t) { m_ticks_left = t; }
dword ticks_left() const { return m_ticks_left; }
dword kernel_stack_base() const { return (dword)m_kernel_stack; };
dword kernel_stack_for_signal_handler_base() const { return (dword)m_kernel_stack_for_signal_handler; };
void set_selector(word s) { m_far_ptr.selector = s; }
void set_state(State s) { m_state = s; }
void die();
void finalize();
@ -182,7 +119,6 @@ public:
int sys$stat(const char*, stat*);
int sys$lseek(int fd, off_t, int whence);
int sys$kill(pid_t pid, int sig);
int sys$geterror() { return m_error; }
[[noreturn]] void sys$exit(int status);
[[noreturn]] void sys$sigreturn();
pid_t sys$waitpid(pid_t, int* wstatus, int options);
@ -249,8 +185,6 @@ public:
int sys$seal_shared_buffer(int shared_buffer_id);
int sys$get_shared_buffer_size(int shared_buffer_id);
KResult wait_for_connect(Socket&);
static void initialize();
[[noreturn]] void crash();
@ -263,21 +197,12 @@ public:
const Vector<Retained<Region>>& regions() const { return m_regions; }
void dump_regions();
void did_schedule() { ++m_times_scheduled; }
dword times_scheduled() const { return m_times_scheduled; }
dword m_ticks_in_user { 0 };
dword m_ticks_in_kernel { 0 };
dword m_ticks_in_user_for_dead_children { 0 };
dword m_ticks_in_kernel_for_dead_children { 0 };
pid_t waitee_pid() const { return m_waitee_pid; }
dword frame_ptr() const { return m_tss.ebp; }
dword stack_ptr() const { return m_tss.esp; }
dword stack_top() const { return m_tss.ss == 0x10 ? m_stack_top0 : m_stack_top3; }
bool validate_read_from_kernel(LinearAddress) const;
bool validate_read(const void*, ssize_t) const;
@ -292,13 +217,6 @@ public:
int number_of_open_file_descriptors() const;
int max_open_file_descriptors() const { return m_max_open_file_descriptors; }
void send_signal(byte signal, Process* sender);
ShouldUnblockProcess dispatch_one_pending_signal();
ShouldUnblockProcess dispatch_signal(byte signal);
bool has_unmasked_pending_signals() const;
void terminate_due_to_signal(byte signal);
size_t amount_virtual() const;
size_t amount_resident() const;
size_t amount_shared() const;
@ -308,16 +226,18 @@ public:
bool is_superuser() const { return m_euid == 0; }
FPUState& fpu_state() { return m_fpu_state; }
bool has_used_fpu() const { return m_has_used_fpu; }
void set_has_used_fpu(bool b) { m_has_used_fpu = b; }
Region* allocate_region_with_vmo(LinearAddress, size_t, Retained<VMObject>&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable);
Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr<Inode>&&, String&& name, bool is_readable, bool is_writable);
Region* allocate_region(LinearAddress, size_t, String&& name, bool is_readable = true, bool is_writable = true, bool commit = true);
bool deallocate_region(Region& region);
void set_blocked_socket(Socket* socket) { m_blocked_socket = socket; }
void set_being_inspected(bool b) { m_being_inspected = b; }
bool is_being_inspected() const { return m_being_inspected; }
void terminate_due_to_signal(byte signal);
void send_signal(byte, Process* sender);
int thread_count() const;
private:
friend class MemoryManager;
@ -327,22 +247,21 @@ private:
Process(String&& name, uid_t, gid_t, pid_t ppid, RingLevel, RetainPtr<Inode>&& cwd = nullptr, RetainPtr<Inode>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
int do_exec(String path, Vector<String> arguments, Vector<String> environment);
void push_value_on_stack(dword);
void make_userspace_stack(Vector<String> arguments, Vector<String> environment);
int alloc_fd();
void set_default_signal_dispositions();
void disown_all_shared_buffers();
void create_signal_trampolines_if_needed();
Thread* m_main_thread { nullptr };
RetainPtr<PageDirectory> m_page_directory;
Process* m_prev { nullptr };
Process* m_next { nullptr };
String m_name;
void (*m_entry)() { nullptr };
pid_t m_pid { 0 };
uid_t m_uid { 0 };
gid_t m_gid { 0 };
@ -350,17 +269,9 @@ private:
gid_t m_egid { 0 };
pid_t m_sid { 0 };
pid_t m_pgid { 0 };
dword m_ticks { 0 };
dword m_ticks_left { 0 };
dword m_stack_top0 { 0 };
dword m_stack_top3 { 0 };
FarPtr m_far_ptr;
State m_state { Invalid };
Priority m_priority { NormalPriority };
dword m_wakeup_time { 0 };
TSS32 m_tss;
TSS32 m_tss_to_resume_kernel;
FPUState m_fpu_state;
struct FileDescriptorAndFlags {
operator bool() const { return !!descriptor; }
void clear() { descriptor = nullptr; flags = 0; }
@ -370,23 +281,8 @@ private:
};
Vector<FileDescriptorAndFlags> m_fds;
RingLevel m_ring { Ring0 };
int m_error { 0 };
void* m_kernel_stack { nullptr };
void* m_kernel_stack_for_signal_handler { nullptr };
dword m_times_scheduled { 0 };
pid_t m_waitee_pid { -1 };
int m_blocked_fd { -1 };
Vector<int> m_select_read_fds;
Vector<int> m_select_write_fds;
Vector<int> m_select_exceptional_fds;
timeval m_select_timeout;
bool m_select_has_timeout { false };
int m_max_open_file_descriptors { 16 };
SignalActionData m_signal_action_data[32];
dword m_pending_signals { 0 };
dword m_signal_mask { 0 };
RetainPtr<Socket> m_blocked_socket;
Alarm* m_snoozing_alarm { nullptr };
byte m_termination_status { 0 };
byte m_termination_signal { 0 };
@ -409,34 +305,28 @@ private:
pid_t m_ppid { 0 };
mode_t m_umask { 022 };
bool m_was_interrupted_while_blocked { false };
static void notify_waiters(pid_t waitee, int exit_status, int signal);
HashTable<gid_t> m_gids;
Region* m_signal_stack_user_region { nullptr };
bool m_being_inspected { false };
RetainPtr<Region> m_display_framebuffer_region;
bool m_has_used_fpu { false };
int m_next_tid { 0 };
};
extern Process* current;
class ProcessInspectionHandle {
public:
ProcessInspectionHandle(Process& process)
: m_process(process)
, m_original_state(process.state())
{
if (&process != current)
m_process.set_state(Process::BeingInspected);
if (&process != &current->process()) {
ASSERT(!m_process.is_being_inspected());
m_process.set_being_inspected(true);
}
}
~ProcessInspectionHandle()
{
m_process.set_state(m_original_state);
m_process.set_being_inspected(false);
}
Process& process() { return m_process; }
@ -454,15 +344,10 @@ public:
Process& operator*() { return m_process; }
private:
Process& m_process;
Process::State m_original_state { Process::Invalid };
};
extern const char* to_string(Process::State);
extern const char* to_string(Process::Priority);
extern void block(Process::State);
extern void sleep(dword ticks);
extern InlineLinkedList<Process>* g_processes;
template<typename Callback>
@ -492,6 +377,21 @@ inline void Process::for_each_child(Callback callback)
}
}
template<typename Callback>
inline void Process::for_each_thread(Callback callback) const
{
InterruptDisabler disabler;
pid_t my_pid = pid();
for (auto* thread = g_threads->head(); thread;) {
auto* next_thread = thread->next();
if (thread->pid() == my_pid) {
if (callback(*thread) == IterationDecision::Abort)
break;
}
thread = next_thread;
}
}
template<typename Callback>
inline void Process::for_each_in_pgrp(pid_t pgid, Callback callback)
{
@ -506,30 +406,6 @@ inline void Process::for_each_in_pgrp(pid_t pgid, Callback callback)
}
}
template<typename Callback>
inline void Process::for_each_in_state(State state, Callback callback)
{
ASSERT_INTERRUPTS_DISABLED();
for (auto* process = g_processes->head(); process;) {
auto* next_process = process->next();
if (process->state() == state)
callback(*process);
process = next_process;
}
}
template<typename Callback>
inline void Process::for_each_living(Callback callback)
{
ASSERT_INTERRUPTS_DISABLED();
for (auto* process = g_processes->head(); process;) {
auto* next_process = process->next();
if (process->state() != Process::Dead && process->state() != Process::Dying)
callback(*process);
process = next_process;
}
}
inline bool InodeMetadata::may_read(Process& process) const
{
return may_read(process.euid(), process.gids());
@ -544,3 +420,8 @@ inline bool InodeMetadata::may_execute(Process& process) const
{
return may_execute(process.euid(), process.gids());
}
inline int Thread::pid() const
{
return m_process.pid();
}