Kernel: Store SchedulerThreadNode directly in Thread

Having the pointer indirection was weird and forced allocations when
adding/binding a new thread :P
This commit is contained in:
2026-08-23 14:21:27 +03:00
parent cce6e417df
commit 17813f3fcf
19 changed files with 103 additions and 144 deletions
+2 -3
View File
@@ -22,7 +22,6 @@ namespace Kernel
class GDT; class GDT;
class IDT; class IDT;
class Scheduler; class Scheduler;
class SchedulerThreadNode;
class Thread; class Thread;
#if ARCH(x86_64) || ARCH(i686) #if ARCH(x86_64) || ARCH(i686)
@@ -54,8 +53,8 @@ namespace Kernel
union union
{ {
TLBEntry flush_tlb; TLBEntry flush_tlb;
SchedulerThreadNode* new_thread; Thread* new_thread;
SchedulerThreadNode* unblock_thread; Thread* unblock_thread;
bool dummy; bool dummy;
}; };
}; };
+2 -6
View File
@@ -41,9 +41,8 @@ namespace Kernel
void on_timer_interrupt(); void on_timer_interrupt();
void on_yield(YieldRegisters*); void on_yield(YieldRegisters*);
static BAN::ErrorOr<void> bind_thread_to_processor(Thread*, ProcessorID); static void bind_thread_to_processor(Thread*, ProcessorID);
// if thread is already bound, this will never fail void add_thread(Thread*);
BAN::ErrorOr<void> add_thread(Thread*);
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns, BaseMutex* mutex); void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns, BaseMutex* mutex);
void unblock_thread(Thread*); void unblock_thread(Thread*);
@@ -68,9 +67,6 @@ namespace Kernel
class ProcessorID find_least_loaded_processor() const; class ProcessorID find_least_loaded_processor() const;
void add_thread(SchedulerThreadNode*);
void unblock_thread(SchedulerThreadNode*);
private: private:
SchedulerQueue m_run_list; SchedulerQueue m_run_list;
SchedulerHeap m_block_list; SchedulerHeap m_block_list;
+2 -1
View File
@@ -7,6 +7,7 @@
#include <kernel/InterruptStack.h> #include <kernel/InterruptStack.h>
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Memory/VirtualRange.h> #include <kernel/Memory/VirtualRange.h>
#include <kernel/SchedulerThreadNode.h>
#include <LibELF/AuxiliaryVector.h> #include <LibELF/AuxiliaryVector.h>
@@ -192,7 +193,7 @@ namespace Kernel
vaddr_t m_fsbase { 0 }; vaddr_t m_fsbase { 0 };
vaddr_t m_gsbase { 0 }; vaddr_t m_gsbase { 0 };
SchedulerThreadNode* m_scheduler_node { nullptr }; SchedulerThreadNode m_scheduler_node;
YieldRegisters m_yield_registers { }; YieldRegisters m_yield_registers { };
+3 -2
View File
@@ -1069,10 +1069,11 @@ acpi_release_global_lock:
if (auto thread_or_error = Thread::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); thread_or_error.is_error()) if (auto thread_or_error = Thread::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); thread_or_error.is_error())
dwarnln("Failed to create ACPI thread, power button will not work: {}", thread_or_error.error()); dwarnln("Failed to create ACPI thread, power button will not work: {}", thread_or_error.error());
else if (auto ret = Processor::scheduler().add_thread(thread_or_error.value()); ret.is_error())
dwarnln("Failed to create ACPI thread, power button will not work: {}", ret.error());
else else
{
Processor::scheduler().add_thread(thread_or_error.value());
dprintln("Initialized ACPI interrupts"); dprintln("Initialized ACPI interrupts");
}
} }
if (auto ret = initialize_embedded_controllers(); ret.is_error()) if (auto ret = initialize_embedded_controllers(); ret.is_error())
+1 -1
View File
@@ -37,7 +37,7 @@ namespace Kernel::ACPI
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto* thread = TRY(Thread::create_kernel([](void* ec) { static_cast<EmbeddedController*>(ec)->thread_task(); }, embedded_controller_ptr)); auto* thread = TRY(Thread::create_kernel([](void* ec) { static_cast<EmbeddedController*>(ec)->thread_task(); }, embedded_controller_ptr));
TRY(Processor::scheduler().add_thread(thread)); Processor::scheduler().add_thread(thread);
auto embedded_controller = BAN::UniqPtr<EmbeddedController>::adopt(embedded_controller_ptr); auto embedded_controller = BAN::UniqPtr<EmbeddedController>::adopt(embedded_controller_ptr);
embedded_controller->m_thread = thread; embedded_controller->m_thread = thread;
+3 -3
View File
@@ -63,7 +63,7 @@ namespace Kernel
} }
}, s_instance }, s_instance
)); ));
MUST(Processor::scheduler().add_thread(updater_thread)); Processor::scheduler().add_thread(updater_thread);
auto* disk_cache_drop_thread = MUST(Thread::create_kernel( auto* disk_cache_drop_thread = MUST(Thread::create_kernel(
[](void* _devfs) [](void* _devfs)
@@ -93,7 +93,7 @@ namespace Kernel
} }
}, s_instance }, s_instance
)); ));
MUST(Processor::scheduler().add_thread(disk_cache_drop_thread)); Processor::scheduler().add_thread(disk_cache_drop_thread);
auto* disk_sync_thread = MUST(Thread::create_kernel( auto* disk_sync_thread = MUST(Thread::create_kernel(
[](void* _devfs) [](void* _devfs)
@@ -129,7 +129,7 @@ namespace Kernel
} }
}, s_instance }, s_instance
)); ));
MUST(Processor::scheduler().add_thread(disk_sync_thread)); Processor::scheduler().add_thread(disk_sync_thread);
} }
void DevFileSystem::initiate_disk_cache_drop() void DevFileSystem::initiate_disk_cache_drop()
+1 -2
View File
@@ -307,8 +307,7 @@ namespace Kernel
BAN::ErrorOr<void> KeyboardDevice::initialize_tty_thread() BAN::ErrorOr<void> KeyboardDevice::initialize_tty_thread()
{ {
auto* thread = TRY(Thread::create_kernel(tty_keyboard_thread, nullptr)); auto* thread = TRY(Thread::create_kernel(tty_keyboard_thread, nullptr));
ASSERT(thread); Processor::scheduler().add_thread(thread);
TRY(Processor::scheduler().add_thread(thread));
return {}; return {};
} }
+1 -1
View File
@@ -551,7 +551,7 @@ namespace Kernel::Input
static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info); static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info);
}, &info }, &info
)); ));
TRY(Processor::scheduler().add_thread(init_thread)); Processor::scheduler().add_thread(init_thread);
while (!info.thread_started) while (!info.thread_started)
Processor::pause(); Processor::pause();
+2 -5
View File
@@ -95,11 +95,8 @@ namespace Kernel
auto* thread = TRY(Thread::create_kernel([](void* e1000_ptr) { auto* thread = TRY(Thread::create_kernel([](void* e1000_ptr) {
static_cast<E1000*>(e1000_ptr)->receive_thread(); static_cast<E1000*>(e1000_ptr)->receive_thread();
}, this)); }, this));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
{ Processor::scheduler().add_thread(thread);
delete thread;
return ret.release_error();
}
m_thread_is_dead = false; m_thread_is_dead = false;
return {}; return {};
+2 -5
View File
@@ -25,11 +25,8 @@ namespace Kernel
auto* thread = TRY(Thread::create_kernel([](void* loopback_ptr) { auto* thread = TRY(Thread::create_kernel([](void* loopback_ptr) {
static_cast<LoopbackInterface*>(loopback_ptr)->receive_thread(); static_cast<LoopbackInterface*>(loopback_ptr)->receive_thread();
}, loopback_ptr)); }, loopback_ptr));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
{ Processor::scheduler().add_thread(thread);
delete thread;
return ret.release_error();
}
loopback->m_thread_is_dead = false; loopback->m_thread_is_dead = false;
loopback->set_ipv4_address({ 127, 0, 0, 1 }); loopback->set_ipv4_address({ 127, 0, 0, 1 });
+2 -5
View File
@@ -75,11 +75,8 @@ namespace Kernel
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) { auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread(); static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
}, this)); }, this));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
{ Processor::scheduler().add_thread(thread);
delete thread;
return ret.release_error();
}
m_rx_thread_is_dead = false; m_rx_thread_is_dead = false;
return {}; return {};
+1 -1
View File
@@ -45,7 +45,7 @@ namespace Kernel
reinterpret_cast<TCPSocket*>(socket_ptr)->process_task(); reinterpret_cast<TCPSocket*>(socket_ptr)->process_task();
}, socket.ptr() }, socket.ptr()
)); ));
TRY(Processor::scheduler().add_thread(socket->m_thread)); Processor::scheduler().add_thread(socket->m_thread);
// hack to keep socket alive until its process starts // hack to keep socket alive until its process starts
socket->ref(); socket->ref();
return socket; return socket;
+8 -21
View File
@@ -237,9 +237,8 @@ namespace Kernel
#endif #endif
} }
// NOTE: make sure the last two `MUST`s don't fail // NOTE: make sure the last `MUST` doesn't fail
TRY(process->m_threads.reserve(1)); TRY(process->m_threads.reserve(1));
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
{ {
SpinLockGuard _(s_process_lock); SpinLockGuard _(s_process_lock);
@@ -247,7 +246,7 @@ namespace Kernel
} }
MUST(process->m_threads.push_back(thread)); MUST(process->m_threads.push_back(thread));
MUST(Processor::scheduler().add_thread(thread)); Processor::scheduler().add_thread(thread);
process_deleter.disable(); process_deleter.disable();
thread_deleter.disable(); thread_deleter.disable();
@@ -877,9 +876,8 @@ namespace Kernel
Thread* thread = TRY(Thread::current().clone(forked, sp, ip)); Thread* thread = TRY(Thread::current().clone(forked, sp, ip));
BAN::ScopeGuard thread_deleter([thread] { delete thread; }); BAN::ScopeGuard thread_deleter([thread] { delete thread; });
// NOTE: make sure the last two `MUST`s don't fail // NOTE: make sure the last `MUST` doesn't fail
TRY(forked->m_threads.reserve(1)); TRY(forked->m_threads.reserve(1));
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
{ {
SpinLockGuard _(s_process_lock); SpinLockGuard _(s_process_lock);
@@ -905,7 +903,7 @@ namespace Kernel
ASSERT(this == &Process::current()); ASSERT(this == &Process::current());
MUST(forked->m_threads.push_back(thread)); MUST(forked->m_threads.push_back(thread));
MUST(Processor::scheduler().add_thread(thread)); Processor::scheduler().add_thread(thread);
process_deleter.disable(); process_deleter.disable();
thread_deleter.disable(); thread_deleter.disable();
@@ -1072,14 +1070,6 @@ namespace Kernel
#endif #endif
} }
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
// and so that adding the thread to the scheduler cannot fail
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
{
Processor::set_interrupt_state(InterruptState::Enabled);
delete new_thread;
return ret.release_error();
}
RWLockWRGuard wr_guard(m_memory_region_lock); RWLockWRGuard wr_guard(m_memory_region_lock);
@@ -1103,7 +1093,9 @@ namespace Kernel
m_threads.front()->m_process = nullptr; m_threads.front()->m_process = nullptr;
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table)); m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
MUST(Processor::scheduler().add_thread(new_thread)); // NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
Scheduler::bind_thread_to_processor(new_thread, Processor::current_id());
Processor::scheduler().add_thread(new_thread);
m_threads.front() = new_thread; m_threads.front() = new_thread;
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++) for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
@@ -3580,12 +3572,7 @@ namespace Kernel
LockGuard _1(m_process_lock); LockGuard _1(m_process_lock);
TRY(m_threads.push_back(thread)); TRY(m_threads.push_back(thread));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error()) Processor::scheduler().add_thread(thread);
{
m_threads.pop_back();
delete thread;
return ret.release_error();
}
return thread->tid(); return thread->tid();
} }
+68 -84
View File
@@ -33,9 +33,6 @@ namespace Kernel
static SpinLock s_processor_info_time_lock; static SpinLock s_processor_info_time_lock;
static BAN::Array<ProcessorInfo, 0xFF> s_processor_infos; static BAN::Array<ProcessorInfo, 0xFF> s_processor_infos;
static BAN::Atomic<size_t> s_next_processor_index { 0 };
BAN::ErrorOr<Scheduler*> Scheduler::create() BAN::ErrorOr<Scheduler*> Scheduler::create()
{ {
auto* scheduler = new Scheduler(); auto* scheduler = new Scheduler();
@@ -151,7 +148,6 @@ namespace Kernel
if (&PageTable::current() != &PageTable::kernel()) if (&PageTable::current() != &PageTable::kernel())
PageTable::kernel().load(); PageTable::kernel().load();
delete m_current->thread; delete m_current->thread;
delete m_current;
m_thread_count--; m_thread_count--;
break; break;
case Thread::State::Executing: case Thread::State::Executing:
@@ -185,7 +181,6 @@ namespace Kernel
if (&PageTable::current() != &PageTable::kernel()) if (&PageTable::current() != &PageTable::kernel())
PageTable::kernel().load(); PageTable::kernel().load();
delete m_current->thread; delete m_current->thread;
delete m_current;
m_thread_count--; m_thread_count--;
} }
@@ -236,7 +231,7 @@ namespace Kernel
const uint64_t current_ns = SystemTimer::get().ns_since_boot(); const uint64_t current_ns = SystemTimer::get().ns_since_boot();
while (!m_block_list.empty() && current_ns >= m_block_list.front()->wake_time_ns) while (!m_block_list.empty() && current_ns >= m_block_list.front()->wake_time_ns)
unblock_thread(m_block_list.front()); unblock_thread(m_block_list.front()->thread);
} }
void Scheduler::update_wake_up_deadline() void Scheduler::update_wake_up_deadline()
@@ -300,60 +295,6 @@ namespace Kernel
update_wake_up_deadline(); update_wake_up_deadline();
} }
void Scheduler::unblock_thread(SchedulerThreadNode* node)
{
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
if (node->processor_id == Processor::current_id())
{
if (!node->blocked)
return;
ASSERT(node != m_current);
Processor::set_disable_smp_messages(true);
m_block_list.pop(node);
if (auto* blocker = node->blocker.load())
blocker->remove_thread_from_block_queue(node);
node->blocked = false;
m_run_list.push(node);
update_most_loaded_node_list(node, &m_run_list);
Processor::set_disable_smp_messages(false);
}
else
{
Processor::send_smp_message(node->processor_id, {
.type = Processor::SMPMessage::Type::UnblockThread,
.unblock_thread = node
});
}
Processor::set_interrupt_state(state);
}
void Scheduler::add_thread(SchedulerThreadNode* node)
{
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
ASSERT(node->processor_id == Processor::current_id());
if (!node->blocked)
m_run_list.push(node);
else
{
m_block_list.push(node);
if (m_block_list.front() == node)
update_wake_up_deadline();
}
if (auto* thread = node->thread; thread->is_userspace() && thread->has_process())
thread->update_processor_index_address();
m_thread_count++;
Processor::set_interrupt_state(state);
}
ProcessorID Scheduler::find_least_loaded_processor() const ProcessorID Scheduler::find_least_loaded_processor() const
{ {
ProcessorID least_loaded_id = Processor::current_id(); ProcessorID least_loaded_id = Processor::current_id();
@@ -535,7 +476,7 @@ namespace Kernel
thread_info.node->processor_id = least_loaded_id; thread_info.node->processor_id = least_loaded_id;
Processor::send_smp_message(least_loaded_id, { Processor::send_smp_message(least_loaded_id, {
.type = Processor::SMPMessage::Type::NewThread, .type = Processor::SMPMessage::Type::NewThread,
.new_thread = thread_info.node .new_thread = thread_info.node->thread
}); });
thread_info = { thread_info = {
@@ -563,41 +504,52 @@ namespace Kernel
m_last_load_balance_ns += s_load_balance_interval_ns; m_last_load_balance_ns += s_load_balance_interval_ns;
} }
BAN::ErrorOr<void> Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id) void Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id)
{ {
ASSERT(thread->m_scheduler_node == nullptr);
auto* new_node = new SchedulerThreadNode(thread);
if (new_node == nullptr)
return BAN::Error::from_errno(ENOMEM);
ASSERT(processor_id != PROCESSOR_NONE); ASSERT(processor_id != PROCESSOR_NONE);
new_node->processor_id = processor_id; ASSERT(thread->m_scheduler_node.processor_id == PROCESSOR_NONE);
thread->m_scheduler_node = new_node; thread->m_scheduler_node.processor_id = processor_id;
return {};
} }
BAN::ErrorOr<void> Scheduler::add_thread(Thread* thread) void Scheduler::add_thread(Thread* thread)
{ {
if (thread->m_scheduler_node == nullptr) ASSERT(thread);
if (thread->m_scheduler_node.processor_id == PROCESSOR_NONE)
{ {
static BAN::Atomic<size_t> s_next_processor_index { 0 };
const size_t processor_index = s_next_processor_index++ % Processor::count(); const size_t processor_index = s_next_processor_index++ % Processor::count();
const auto processor_id = Processor::id_from_index(processor_index); const auto processor_id = Processor::id_from_index(processor_index);
TRY(bind_thread_to_processor(thread, processor_id)); bind_thread_to_processor(thread, processor_id);
} }
auto* node = thread->m_scheduler_node; if (const auto proc_id = thread->m_scheduler_node.processor_id; proc_id != Processor::current_id())
if (node->processor_id == Processor::current_id()) {
add_thread(node); Processor::send_smp_message(proc_id, {
.type = Processor::SMPMessage::Type::NewThread,
.new_thread = thread
});
return;
}
const auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
if (!thread->m_scheduler_node.blocked)
m_run_list.push(&thread->m_scheduler_node);
else else
{ {
Processor::send_smp_message(node->processor_id, { m_block_list.push(&thread->m_scheduler_node);
.type = Processor::SMPMessage::Type::NewThread, if (m_block_list.front() == &thread->m_scheduler_node)
.new_thread = node update_wake_up_deadline();
});
} }
return {}; if (thread->is_userspace() && thread->has_process())
thread->update_processor_index_address();
m_thread_count++;
Processor::set_interrupt_state(state);
} }
void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex) void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex)
@@ -605,7 +557,7 @@ namespace Kernel
if (SystemTimer::get().ns_since_boot() >= wake_time_ns) if (SystemTimer::get().ns_since_boot() >= wake_time_ns)
return; return;
auto state = Processor::get_interrupt_state(); const auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled); Processor::set_interrupt_state(InterruptState::Disabled);
ASSERT(m_current->processor_id == Processor::current_id()); ASSERT(m_current->processor_id == Processor::current_id());
@@ -639,7 +591,39 @@ namespace Kernel
void Scheduler::unblock_thread(Thread* thread) void Scheduler::unblock_thread(Thread* thread)
{ {
unblock_thread(thread->m_scheduler_node); if (const auto proc_id = thread->m_scheduler_node.processor_id; proc_id != Processor::current_id())
{
Processor::send_smp_message(proc_id, {
.type = Processor::SMPMessage::Type::UnblockThread,
.unblock_thread = thread
});
return;
}
const auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
if (!thread->m_scheduler_node.blocked)
{
Processor::set_interrupt_state(state);
return;
}
ASSERT(&thread->m_scheduler_node != m_current);
Processor::set_disable_smp_messages(true);
m_block_list.pop(&thread->m_scheduler_node);
if (auto* blocker = thread->m_scheduler_node.blocker.load())
blocker->remove_thread_from_block_queue(&thread->m_scheduler_node);
thread->m_scheduler_node.blocked = false;
m_run_list.push(&thread->m_scheduler_node);
update_most_loaded_node_list(&thread->m_scheduler_node, &m_run_list);
Processor::set_disable_smp_messages(false);
Processor::set_interrupt_state(state);
} }
Thread& Scheduler::current_thread() Thread& Scheduler::current_thread()
+1
View File
@@ -240,6 +240,7 @@ namespace Kernel
Thread::Thread(pid_t tid, Process* process) Thread::Thread(pid_t tid, Process* process)
: m_tid(tid), m_process(process) : m_tid(tid), m_process(process)
, m_scheduler_node(this)
{ {
if (!s_default_sse_storage_initialized) if (!s_default_sse_storage_initialized)
initialize_default_sse_storage(); initialize_default_sse_storage();
+1 -1
View File
@@ -37,7 +37,7 @@ namespace Kernel
node->block_chain_prev = nullptr; node->block_chain_prev = nullptr;
node->block_chain_next = nullptr; node->block_chain_next = nullptr;
Processor::scheduler().unblock_thread(node); Processor::scheduler().unblock_thread(node->thread);
node = next; node = next;
} }
+1 -1
View File
@@ -218,7 +218,7 @@ namespace Kernel
} }
m_port_updater = TRY(Thread::create_kernel([](void* data) { reinterpret_cast<USBHubDriver*>(data)->port_updater_task(); }, this)); m_port_updater = TRY(Thread::create_kernel([](void* data) { reinterpret_cast<USBHubDriver*>(data)->port_updater_task(); }, this));
TRY(Processor::scheduler().add_thread(m_port_updater)); Processor::scheduler().add_thread(m_port_updater);
return {}; return {};
} }
+1 -1
View File
@@ -149,7 +149,7 @@ namespace Kernel
continue; continue;
m_port_updater = TRY(Thread::create_kernel([](void* data) { reinterpret_cast<XHCIController*>(data)->port_updater_task(); }, this)); m_port_updater = TRY(Thread::create_kernel([](void* data) { reinterpret_cast<XHCIController*>(data)->port_updater_task(); }, this));
TRY(Processor::scheduler().add_thread(m_port_updater)); Processor::scheduler().add_thread(m_port_updater);
return {}; return {};
} }
+1 -1
View File
@@ -196,7 +196,7 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
MUST(Processor::scheduler().initialize()); MUST(Processor::scheduler().initialize());
auto* init_thread = MUST(Thread::create_kernel(init2, nullptr)); auto* init_thread = MUST(Thread::create_kernel(init2, nullptr));
MUST(Processor::scheduler().add_thread(init_thread)); Processor::scheduler().add_thread(init_thread);
Processor::yield(); Processor::yield();
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();