From a098266ff5086e52b1af2e11fd1835f4c22a746d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 2 Apr 2023 19:25:36 +0200 Subject: [PATCH] Kernel: Simplify Process factory functions - Instead of taking the first new thread as an out-parameter, we now bundle the process and its first thread in a struct and use that as the return value. - Make all Process factory functions return ErrorOr. Use this to convert some places to more TRY(). - Drop the "try_" prefix on Process factory functions. --- Kernel/Arch/aarch64/init.cpp | 255 +++++++++++++++++++++++ Kernel/Arch/init.cpp | 16 +- Kernel/Bus/USB/UHCI/UHCIController.cpp | 10 +- Kernel/FileSystem/Plan9FS/FileSystem.cpp | 5 +- Kernel/Net/NetworkTask.cpp | 5 +- Kernel/Process.cpp | 45 ++-- Kernel/Process.h | 17 +- Kernel/Scheduler.cpp | 6 +- Kernel/Syscalls/fork.cpp | 19 +- Kernel/Tasks/FinalizerTask.cpp | 6 +- Kernel/Tasks/SyncTask.cpp | 5 +- Kernel/WorkQueue.cpp | 8 +- 12 files changed, 319 insertions(+), 78 deletions(-) create mode 100644 Kernel/Arch/aarch64/init.cpp diff --git a/Kernel/Arch/aarch64/init.cpp b/Kernel/Arch/aarch64/init.cpp new file mode 100644 index 0000000000..612d1e4117 --- /dev/null +++ b/Kernel/Arch/aarch64/init.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021, Nico Weber + * Copyright (c) 2021, Marcin Undak + * Copyright (c) 2021, Jesse Buhagiar + * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Filiph Sandström + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef void (*ctor_func_t)(); +extern ctor_func_t start_heap_ctors[]; +extern ctor_func_t end_heap_ctors[]; +extern ctor_func_t start_ctors[]; +extern ctor_func_t end_ctors[]; + +// FIXME: Share this with the Intel Prekernel. +extern uintptr_t __stack_chk_guard; +uintptr_t __stack_chk_guard; + +READONLY_AFTER_INIT bool g_in_early_boot; + +namespace Kernel { + +static void draw_logo(u8* framebuffer_data); +static u32 query_firmware_version(); + +extern "C" [[noreturn]] void halt(); +extern "C" [[noreturn]] void init(); + +ALWAYS_INLINE static Processor& bootstrap_processor() +{ + alignas(Processor) static u8 bootstrap_processor_storage[sizeof(Processor)]; + return (Processor&)bootstrap_processor_storage; +} + +Atomic g_boot_console; + +VirtualConsole* tty0; +ProcessID g_init_pid { 0 }; + +static void init_stage2(void*); +void init_stage2(void*) +{ + Process::register_new(Process::current()); + + auto firmware_version = query_firmware_version(); + dmesgln("Firmware version: {}", firmware_version); + + VirtualFileSystem::initialize(); + + StorageManagement::the().initialize(kernel_command_line().root_device(), kernel_command_line().is_force_pio(), kernel_command_line().is_nvme_polling_enabled()); + if (VirtualFileSystem::the().mount_root(StorageManagement::the().root_filesystem()).is_error()) { + PANIC("VirtualFileSystem::mount_root failed"); + } + + // Switch out of early boot mode. + g_in_early_boot = false; + + auto userspace_init = kernel_command_line().userspace_init(); + auto init_args = kernel_command_line().userspace_init_args(); + + auto init_or_error = Process::create_user_process(userspace_init, UserID(0), GroupID(0), move(init_args), {}, tty0); + if (init_or_error.is_error()) + PANIC("init_stage2: Error spawning init process: {}", init_or_error.error()); + + auto [init_process, init_thread] = init_or_error.release_value(); + g_init_pid = init_process->pid(); + + init_thread->set_priority(THREAD_PRIORITY_HIGH); + + Process::current().sys$exit(0); + VERIFY_NOT_REACHED(); +} + +extern "C" [[noreturn]] void init() +{ + g_in_early_boot = true; + + // FIXME: Don't hardcode this + multiboot_memory_map_t mmap[] = { + { sizeof(struct multiboot_mmap_entry) - sizeof(u32), + (u64)0x0, + (u64)0x3F000000, + MULTIBOOT_MEMORY_AVAILABLE } + }; + + multiboot_memory_map = mmap; + multiboot_memory_map_count = 1; + + dbgln("Welcome to Serenity OS!"); + dbgln("Imagine this being your ideal operating system."); + dbgln("Observed deviations from that ideal are shortcomings of your imagination."); + dbgln(); + + CommandLine::early_initialize(""); + + new (&bootstrap_processor()) Processor(); + bootstrap_processor().install(0); + + // We call the constructors of kmalloc.cpp separately, because other constructors in the Kernel + // might rely on being able to call new/kmalloc in the constructor. We do have to run the + // kmalloc constructors, because kmalloc_init relies on that. + for (ctor_func_t* ctor = start_heap_ctors; ctor < end_heap_ctors; ctor++) + (*ctor)(); + kmalloc_init(); + + bootstrap_processor().initialize(); + + load_kernel_symbol_table(); + + CommandLine::initialize(); + + dmesgln("Starting SerenityOS..."); + + Memory::MemoryManager::initialize(0); + DeviceManagement::initialize(); + SysFSComponentRegistry::initialize(); + DeviceManagement::the().attach_null_device(*NullDevice::must_initialize()); + + // Invoke all static global constructors in the kernel. + // Note that we want to do this as early as possible. + for (ctor_func_t* ctor = start_ctors; ctor < end_ctors; ctor++) + (*ctor)(); + + auto& framebuffer = RPi::Framebuffer::the(); + if (framebuffer.initialized()) { + g_boot_console = &try_make_lock_ref_counted(PhysicalAddress((PhysicalPtr)framebuffer.gpu_buffer()), framebuffer.width(), framebuffer.height(), framebuffer.pitch()).value().leak_ref(); + draw_logo(static_cast(g_boot_console.load())->unsafe_framebuffer_data()); + } + + initialize_interrupts(); + InterruptManagement::initialize(); + Processor::enable_interrupts(); + + // Note: We have to disable interrupts otherwise Scheduler::timer_tick might be called before the scheduler is started. + Processor::disable_interrupts(); + TimeManagement::initialize(0); + + Process::initialize(); + Scheduler::initialize(); + + MUST(Process::create_kernel_process(KString::must_create("init_stage2"sv), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No)); + + Scheduler::start(); + + VERIFY_NOT_REACHED(); +} + +class QueryFirmwareVersionMboxMessage : RPi::Mailbox::Message { +public: + u32 version; + + QueryFirmwareVersionMboxMessage() + : RPi::Mailbox::Message(0x0000'0001, 4) + { + version = 0; + } +}; + +static u32 query_firmware_version() +{ + struct __attribute__((aligned(16))) { + RPi::Mailbox::MessageHeader header; + QueryFirmwareVersionMboxMessage query_firmware_version; + RPi::Mailbox::MessageTail tail; + } message_queue; + + if (!RPi::Mailbox::the().send_queue(&message_queue, sizeof(message_queue))) { + return 0xffff'ffff; + } + + return message_queue.query_firmware_version.version; +} + +extern "C" const u32 serenity_boot_logo_start; +extern "C" const u32 serenity_boot_logo_size; + +static void draw_logo(u8* framebuffer_data) +{ + BootPPMParser logo_parser(reinterpret_cast(&serenity_boot_logo_start), serenity_boot_logo_size); + if (!logo_parser.parse()) { + dbgln("Failed to parse boot logo."); + return; + } + + dbgln("Boot logo size: {} ({} x {})", serenity_boot_logo_size, logo_parser.image.width, logo_parser.image.height); + + auto& framebuffer = RPi::Framebuffer::the(); + auto fb_ptr = framebuffer_data; + auto image_left = (framebuffer.width() - logo_parser.image.width) / 2; + auto image_right = image_left + logo_parser.image.width; + auto image_top = (framebuffer.height() - logo_parser.image.height) / 2; + auto image_bottom = image_top + logo_parser.image.height; + auto logo_pixels = logo_parser.image.pixel_data; + + for (u32 y = 0; y < framebuffer.height(); y++) { + for (u32 x = 0; x < framebuffer.width(); x++) { + if (x >= image_left && x < image_right && y >= image_top && y < image_bottom) { + switch (framebuffer.pixel_order()) { + case RPi::Framebuffer::PixelOrder::RGB: + fb_ptr[0] = logo_pixels[0]; + fb_ptr[1] = logo_pixels[1]; + fb_ptr[2] = logo_pixels[2]; + break; + case RPi::Framebuffer::PixelOrder::BGR: + fb_ptr[0] = logo_pixels[2]; + fb_ptr[1] = logo_pixels[1]; + fb_ptr[2] = logo_pixels[0]; + break; + default: + dbgln("Unsupported pixel format"); + VERIFY_NOT_REACHED(); + } + + logo_pixels += 3; + } else { + fb_ptr[0] = 0xBD; + fb_ptr[1] = 0xBD; + fb_ptr[2] = 0xBD; + } + + fb_ptr[3] = 0xFF; + fb_ptr += 4; + } + fb_ptr += framebuffer.pitch() - framebuffer.width() * 4; + } +} + +} diff --git a/Kernel/Arch/init.cpp b/Kernel/Arch/init.cpp index 4eb0b02048..01e01069d5 100644 --- a/Kernel/Arch/init.cpp +++ b/Kernel/Arch/init.cpp @@ -281,13 +281,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo con } #endif - { - LockRefPtr init_stage2_thread; - (void)Process::create_kernel_process(init_stage2_thread, KString::must_create("init_stage2"sv), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No); - // We need to make sure we drop the reference for init_stage2_thread - // before calling into Scheduler::start, otherwise we will have a - // dangling Thread that never gets cleaned up - } + MUST(Process::create_kernel_process(KString::must_create("init_stage2"sv), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No)); Scheduler::start(); VERIFY_NOT_REACHED(); @@ -415,17 +409,17 @@ void init_stage2(void*) // NOTE: Everything marked UNMAP_AFTER_INIT becomes inaccessible after this point. MM.unmap_text_after_init(); - LockRefPtr thread; auto userspace_init = kernel_command_line().userspace_init(); auto init_args = kernel_command_line().userspace_init_args(); - auto init_or_error = Process::try_create_user_process(thread, userspace_init, UserID(0), GroupID(0), move(init_args), {}, tty0); + auto init_or_error = Process::create_user_process(userspace_init, UserID(0), GroupID(0), move(init_args), {}, tty0); if (init_or_error.is_error()) PANIC("init_stage2: Error spawning init process: {}", init_or_error.error()); - g_init_pid = init_or_error.value()->pid(); + auto [init_process, init_thread] = init_or_error.release_value(); - thread->set_priority(THREAD_PRIORITY_HIGH); + g_init_pid = init_process->pid(); + init_thread->set_priority(THREAD_PRIORITY_HIGH); if (boot_profiling) { dbgln("Starting full system boot profiling"); diff --git a/Kernel/Bus/USB/UHCI/UHCIController.cpp b/Kernel/Bus/USB/UHCI/UHCIController.cpp index c058f8fb4c..a2411ee526 100644 --- a/Kernel/Bus/USB/UHCI/UHCIController.cpp +++ b/Kernel/Bus/USB/UHCI/UHCIController.cpp @@ -585,22 +585,20 @@ size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue) ErrorOr UHCIController::spawn_port_process() { - LockRefPtr usb_hotplug_thread; - (void)Process::create_kernel_process(usb_hotplug_thread, TRY(KString::try_create("UHCI Hot Plug Task"sv)), [&] { + TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Hot Plug Task"sv)), [&] { for (;;) { if (m_root_hub) m_root_hub->check_for_port_updates(); (void)Thread::current()->sleep(Time::from_seconds(1)); } - }); + })); return {}; } ErrorOr UHCIController::spawn_async_poll_process() { - LockRefPtr async_poll_thread; - (void)Process::create_kernel_process(async_poll_thread, TRY(KString::try_create("UHCI Async Poll Task"sv)), [&] { + TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Async Poll Task"sv)), [&] { u16 poll_interval_ms = 1024; for (;;) { { @@ -620,7 +618,7 @@ ErrorOr UHCIController::spawn_async_poll_process() } (void)Thread::current()->sleep(Time::from_milliseconds(poll_interval_ms)); } - }); + })); return {}; } diff --git a/Kernel/FileSystem/Plan9FS/FileSystem.cpp b/Kernel/FileSystem/Plan9FS/FileSystem.cpp index d2f0b32245..6c6f038cd9 100644 --- a/Kernel/FileSystem/Plan9FS/FileSystem.cpp +++ b/Kernel/FileSystem/Plan9FS/FileSystem.cpp @@ -353,10 +353,11 @@ void Plan9FS::ensure_thread() auto process_name = KString::try_create("Plan9FS"sv); if (process_name.is_error()) TODO(); - (void)Process::create_kernel_process(m_thread, process_name.release_value(), [&]() { + auto [_, thread] = Process::create_kernel_process(process_name.release_value(), [&]() { thread_main(); m_thread_running.store(false, AK::MemoryOrder::memory_order_release); - }); + }).release_value_but_fixme_should_propagate_errors(); + m_thread = move(thread); } } diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp index cb7586b7a5..b5de06dda8 100644 --- a/Kernel/Net/NetworkTask.cpp +++ b/Kernel/Net/NetworkTask.cpp @@ -42,12 +42,11 @@ static HashTable>* delayed_ack_sockets; void NetworkTask::spawn() { - LockRefPtr thread; auto name = KString::try_create("Network Task"sv); if (name.is_error()) TODO(); - (void)Process::create_kernel_process(thread, name.release_value(), NetworkTask_main, nullptr); - network_task = thread; + auto [_, first_thread] = MUST(Process::create_kernel_process(name.release_value(), NetworkTask_main, nullptr)); + network_task = first_thread; } bool NetworkTask::is_current() diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index eeeb052e38..0a3f35c738 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -208,7 +208,7 @@ void Process::register_new(Process& process) }); } -ErrorOr> Process::try_create_user_process(LockRefPtr& first_thread, StringView path, UserID uid, GroupID gid, Vector> arguments, Vector> environment, TTY* tty) +ErrorOr Process::create_user_process(StringView path, UserID uid, GroupID gid, Vector> arguments, Vector> environment, TTY* tty) { auto parts = path.split_view('/'); if (arguments.is_empty()) { @@ -218,7 +218,7 @@ ErrorOr> Process::try_create_user_process(LockRefPtrm_fds.with_exclusive([&](auto& fds) -> ErrorOr { TRY(fds.try_resize(Process::OpenFileDescriptions::max_open())); @@ -238,11 +238,7 @@ ErrorOr> Process::try_create_user_process(LockRefPtrexec(move(path_string), move(arguments), move(environment), new_main_thread, previous_interrupts_state); result.is_error()) { - dbgln("Failed to exec {}: {}", path, result.error()); - first_thread = nullptr; - return result.release_error(); - } + TRY(process->exec(move(path_string), move(arguments), move(environment), new_main_thread, previous_interrupts_state)); register_new(*process); @@ -254,25 +250,24 @@ ErrorOr> Process::try_create_user_process(LockRefPtrset_state(Thread::State::Runnable); } - return process; + return ProcessAndFirstThread { move(process), move(first_thread) }; } -RefPtr Process::create_kernel_process(LockRefPtr& first_thread, NonnullOwnPtr name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register) +ErrorOr Process::create_kernel_process(NonnullOwnPtr name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register) { - auto process_or_error = Process::try_create(first_thread, move(name), UserID(0), GroupID(0), ProcessID(0), true); - if (process_or_error.is_error()) - return {}; - auto process = process_or_error.release_value(); + auto process_and_first_thread = TRY(Process::create(move(name), UserID(0), GroupID(0), ProcessID(0), true)); + auto& process = *process_and_first_thread.process; + auto& thread = *process_and_first_thread.first_thread; - first_thread->regs().set_entry_function((FlatPtr)entry, (FlatPtr)entry_data); + thread.regs().set_entry_function((FlatPtr)entry, (FlatPtr)entry_data); if (do_register == RegisterProcess::Yes) - register_new(*process); + register_new(process); SpinlockLocker lock(g_scheduler_lock); - first_thread->set_affinity(affinity); - first_thread->set_state(Thread::State::Runnable); - return process; + thread.set_affinity(affinity); + thread.set_state(Thread::State::Runnable); + return process_and_first_thread; } void Process::protect_data() @@ -289,7 +284,7 @@ void Process::unprotect_data() }); } -ErrorOr> Process::try_create(LockRefPtr& first_thread, NonnullOwnPtr name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr current_directory, RefPtr executable, TTY* tty, Process* fork_parent) +ErrorOr Process::create(NonnullOwnPtr name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr current_directory, RefPtr executable, TTY* tty, Process* fork_parent) { OwnPtr new_address_space; if (fork_parent) { @@ -303,9 +298,11 @@ ErrorOr> Process::try_create(LockRefPtr& first_th auto unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) }; auto exec_unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) }; auto credentials = TRY(Credentials::create(uid, gid, uid, gid, uid, gid, {}, fork_parent ? fork_parent->sid() : 0, fork_parent ? fork_parent->pgid() : 0)); + auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(move(name), move(credentials), ppid, is_kernel_process, move(current_directory), move(executable), tty, move(unveil_tree), move(exec_unveil_tree)))); - TRY(process->attach_resources(new_address_space.release_nonnull(), first_thread, fork_parent)); - return process; + auto first_thread = TRY(process->attach_resources(new_address_space.release_nonnull(), fork_parent)); + + return ProcessAndFirstThread { move(process), move(first_thread) }; } Process::Process(NonnullOwnPtr name, NonnullRefPtr credentials, ProcessID ppid, bool is_kernel_process, RefPtr current_directory, RefPtr executable, TTY* tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree) @@ -332,7 +329,7 @@ Process::Process(NonnullOwnPtr name, NonnullRefPtr credent } } -ErrorOr Process::attach_resources(NonnullOwnPtr&& preallocated_space, LockRefPtr& first_thread, Process* fork_parent) +ErrorOr> Process::attach_resources(NonnullOwnPtr&& preallocated_space, Process* fork_parent) { m_space.with([&](auto& space) { space = move(preallocated_space); @@ -347,7 +344,7 @@ ErrorOr Process::attach_resources(NonnullOwnPtr&& pr return Thread::try_create(*this); }; - first_thread = TRY(create_first_thread()); + auto first_thread = TRY(create_first_thread()); if (!fork_parent) { // FIXME: Figure out if this is really necessary. @@ -359,7 +356,7 @@ ErrorOr Process::attach_resources(NonnullOwnPtr&& pr if (fork_parent) m_signal_action_data = fork_parent->m_signal_action_data; - return {}; + return first_thread; } Process::~Process() diff --git a/Kernel/Process.h b/Kernel/Process.h index e1b5220fcb..ccf5684169 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -185,15 +185,20 @@ public: Yes }; + struct ProcessAndFirstThread { + NonnullRefPtr process; + NonnullLockRefPtr first_thread; + }; + template - static RefPtr create_kernel_process(LockRefPtr& first_thread, NonnullOwnPtr name, EntryFunction entry, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes) + static ErrorOr create_kernel_process(NonnullOwnPtr name, EntryFunction entry, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes) { auto* entry_func = new EntryFunction(move(entry)); - return create_kernel_process(first_thread, move(name), &Process::kernel_process_trampoline, entry_func, affinity, do_register); + return create_kernel_process(move(name), &Process::kernel_process_trampoline, entry_func, affinity, do_register); } - static RefPtr create_kernel_process(LockRefPtr& first_thread, NonnullOwnPtr name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes); - static ErrorOr> try_create_user_process(LockRefPtr& first_thread, StringView path, UserID, GroupID, Vector> arguments, Vector> environment, TTY*); + static ErrorOr create_kernel_process(NonnullOwnPtr name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes); + static ErrorOr create_user_process(StringView path, UserID, GroupID, Vector> arguments, Vector> environment, TTY*); static void register_new(Process&); ~Process(); @@ -594,8 +599,8 @@ private: bool remove_thread(Thread&); Process(NonnullOwnPtr name, NonnullRefPtr, ProcessID ppid, bool is_kernel_process, RefPtr current_directory, RefPtr executable, TTY* tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree); - static ErrorOr> try_create(LockRefPtr& first_thread, NonnullOwnPtr name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr current_directory = nullptr, RefPtr executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); - ErrorOr attach_resources(NonnullOwnPtr&&, LockRefPtr& first_thread, Process* fork_parent); + static ErrorOr create(NonnullOwnPtr name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr current_directory = nullptr, RefPtr executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); + ErrorOr> attach_resources(NonnullOwnPtr&&, Process* fork_parent); static ProcessID allocate_pid(); void kill_threads_except_self(); diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 789b43da54..0905171364 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -366,13 +366,11 @@ UNMAP_AFTER_INIT void Scheduler::initialize() VERIFY(Processor::is_initialized()); // sanity check VERIFY(TimeManagement::is_initialized()); - LockRefPtr idle_thread; g_finalizer_wait_queue = new WaitQueue; g_finalizer_has_work.store(false, AK::MemoryOrder::memory_order_release); - s_colonel_process = Process::create_kernel_process(idle_thread, KString::must_create("colonel"sv), idle_loop, nullptr, 1, Process::RegisterProcess::No).leak_ref(); - VERIFY(s_colonel_process); - VERIFY(idle_thread); + auto [colonel_process, idle_thread] = MUST(Process::create_kernel_process(KString::must_create("colonel"sv), idle_loop, nullptr, 1, Process::RegisterProcess::No)); + s_colonel_process = &colonel_process.leak_ref(); idle_thread->set_priority(THREAD_PRIORITY_MIN); idle_thread->set_name(KString::must_create("Idle Task #0"sv)); diff --git a/Kernel/Syscalls/fork.cpp b/Kernel/Syscalls/fork.cpp index 6aee2d40bb..cf1ee14fdf 100644 --- a/Kernel/Syscalls/fork.cpp +++ b/Kernel/Syscalls/fork.cpp @@ -18,19 +18,18 @@ ErrorOr Process::sys$fork(RegisterState& regs) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::proc)); - LockRefPtr child_first_thread; - - ArmedScopeGuard thread_finalizer_guard = [&child_first_thread]() { - SpinlockLocker lock(g_scheduler_lock); - if (child_first_thread) { - child_first_thread->detach(); - child_first_thread->set_state(Thread::State::Dying); - } - }; auto child_name = TRY(name().with([](auto& name) { return name->try_clone(); })); auto credentials = this->credentials(); - auto child = TRY(Process::try_create(child_first_thread, move(child_name), credentials->uid(), credentials->gid(), pid(), m_is_kernel_process, current_directory(), executable(), m_tty, this)); + auto child_and_first_thread = TRY(Process::create(move(child_name), credentials->uid(), credentials->gid(), pid(), m_is_kernel_process, current_directory(), executable(), m_tty, this)); + auto& child = child_and_first_thread.process; + auto& child_first_thread = child_and_first_thread.first_thread; + + ArmedScopeGuard thread_finalizer_guard = [&child_first_thread]() { + SpinlockLocker lock(g_scheduler_lock); + child_first_thread->detach(); + child_first_thread->set_state(Thread::State::Dying); + }; // NOTE: All user processes have a leaked ref on them. It's balanced by Thread::WaitBlockerSet::finalize(). child->ref(); diff --git a/Kernel/Tasks/FinalizerTask.cpp b/Kernel/Tasks/FinalizerTask.cpp index eaf219cbff..b16450fbb0 100644 --- a/Kernel/Tasks/FinalizerTask.cpp +++ b/Kernel/Tasks/FinalizerTask.cpp @@ -28,10 +28,8 @@ static void finalizer_task(void*) UNMAP_AFTER_INIT void FinalizerTask::spawn() { - LockRefPtr finalizer_thread; - auto finalizer_process = Process::create_kernel_process(finalizer_thread, KString::must_create(finalizer_task_name), finalizer_task, nullptr); - VERIFY(finalizer_process); - g_finalizer = finalizer_thread; + auto [_, finalizer_thread] = MUST(Process::create_kernel_process(KString::must_create(finalizer_task_name), finalizer_task, nullptr)); + g_finalizer = move(finalizer_thread); } } diff --git a/Kernel/Tasks/SyncTask.cpp b/Kernel/Tasks/SyncTask.cpp index cd2354dcbd..973cbe5786 100644 --- a/Kernel/Tasks/SyncTask.cpp +++ b/Kernel/Tasks/SyncTask.cpp @@ -14,14 +14,13 @@ namespace Kernel { UNMAP_AFTER_INIT void SyncTask::spawn() { - LockRefPtr syncd_thread; - (void)Process::create_kernel_process(syncd_thread, KString::must_create("VFS Sync Task"sv), [] { + MUST(Process::create_kernel_process(KString::must_create("VFS Sync Task"sv), [] { dbgln("VFS SyncTask is running"); for (;;) { VirtualFileSystem::sync(); (void)Thread::current()->sleep(Time::from_seconds(1)); } - }); + })); } } diff --git a/Kernel/WorkQueue.cpp b/Kernel/WorkQueue.cpp index 53c5524b41..dc99835c89 100644 --- a/Kernel/WorkQueue.cpp +++ b/Kernel/WorkQueue.cpp @@ -24,11 +24,10 @@ UNMAP_AFTER_INIT void WorkQueue::initialize() UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name) { - LockRefPtr thread; auto name_kstring = KString::try_create(name); if (name_kstring.is_error()) TODO(); - (void)Process::create_kernel_process(thread, name_kstring.release_value(), [this] { + auto [_, thread] = Process::create_kernel_process(name_kstring.release_value(), [this] { #if ARCH(AARCH64) // FIXME: This function expects to be executed with interrupts disabled, however on // aarch64 we spawn (kernel) threads with interrupts enabled, so we need to disable them. @@ -52,9 +51,8 @@ UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name) } [[maybe_unused]] auto result = m_wait_queue.wait_on({}); } - }); - // If we can't create the thread we're in trouble... - m_thread = thread.release_nonnull(); + }).release_value_but_fixme_should_propagate_errors(); + m_thread = move(thread); } void WorkQueue::do_queue(WorkItem& item)