diff options
-rw-r--r-- | Kernel/Arch/aarch64/init.cpp | 255 | ||||
-rw-r--r-- | Kernel/Arch/init.cpp | 16 | ||||
-rw-r--r-- | Kernel/Bus/USB/UHCI/UHCIController.cpp | 10 | ||||
-rw-r--r-- | Kernel/FileSystem/Plan9FS/FileSystem.cpp | 5 | ||||
-rw-r--r-- | Kernel/Net/NetworkTask.cpp | 5 | ||||
-rw-r--r-- | Kernel/Process.cpp | 45 | ||||
-rw-r--r-- | Kernel/Process.h | 17 | ||||
-rw-r--r-- | Kernel/Scheduler.cpp | 6 | ||||
-rw-r--r-- | Kernel/Syscalls/fork.cpp | 17 | ||||
-rw-r--r-- | Kernel/Tasks/FinalizerTask.cpp | 6 | ||||
-rw-r--r-- | Kernel/Tasks/SyncTask.cpp | 5 | ||||
-rw-r--r-- | Kernel/WorkQueue.cpp | 8 |
12 files changed, 318 insertions, 77 deletions
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 <thakis@chromium.org> + * Copyright (c) 2021, Marcin Undak <mcinek@gmail.com> + * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> + * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Format.h> +#include <AK/Types.h> + +#include <Kernel/Arch/InterruptManagement.h> +#include <Kernel/Arch/Interrupts.h> +#include <Kernel/Arch/Processor.h> +#include <Kernel/Arch/aarch64/ASM_wrapper.h> +#include <Kernel/Arch/aarch64/BootPPMParser.h> +#include <Kernel/Arch/aarch64/CPU.h> +#include <Kernel/Arch/aarch64/RPi/Framebuffer.h> +#include <Kernel/Arch/aarch64/RPi/Mailbox.h> +#include <Kernel/Arch/aarch64/RPi/UART.h> +#include <Kernel/Arch/aarch64/Registers.h> +#include <Kernel/Arch/aarch64/TrapFrame.h> +#include <Kernel/CommandLine.h> +#include <Kernel/Devices/DeviceManagement.h> +#include <Kernel/FileSystem/VirtualFileSystem.h> +#include <Kernel/Graphics/Console/BootFramebufferConsole.h> +#include <Kernel/KSyms.h> +#include <Kernel/Memory/MemoryManager.h> +#include <Kernel/Panic.h> +#include <Kernel/Scheduler.h> +#include <Kernel/Storage/StorageManagement.h> +#include <Kernel/TTY/VirtualConsole.h> + +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<Graphics::Console*> 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<Graphics::BootFramebufferConsole>(PhysicalAddress((PhysicalPtr)framebuffer.gpu_buffer()), framebuffer.width(), framebuffer.height(), framebuffer.pitch()).value().leak_ref(); + draw_logo(static_cast<Graphics::BootFramebufferConsole*>(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<u8 const*>(&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<Thread> 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> 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<void> UHCIController::spawn_port_process() { - LockRefPtr<Thread> 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<void> UHCIController::spawn_async_poll_process() { - LockRefPtr<Thread> 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<void> 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<NonnullRefPtr<TCPSocket>>* delayed_ack_sockets; void NetworkTask::spawn() { - LockRefPtr<Thread> 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<NonnullRefPtr<Process>> Process::try_create_user_process(LockRefPtr<Thread>& first_thread, StringView path, UserID uid, GroupID gid, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, TTY* tty) +ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView path, UserID uid, GroupID gid, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, TTY* tty) { auto parts = path.split_view('/'); if (arguments.is_empty()) { @@ -218,7 +218,7 @@ ErrorOr<NonnullRefPtr<Process>> Process::try_create_user_process(LockRefPtr<Thre auto path_string = TRY(KString::try_create(path)); auto name = TRY(KString::try_create(parts.last())); - auto process = TRY(Process::try_create(first_thread, move(name), uid, gid, ProcessID(0), false, VirtualFileSystem::the().root_custody(), nullptr, tty)); + auto [process, first_thread] = TRY(Process::create(move(name), uid, gid, ProcessID(0), false, VirtualFileSystem::the().root_custody(), nullptr, tty)); TRY(process->m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> { TRY(fds.try_resize(Process::OpenFileDescriptions::max_open())); @@ -238,11 +238,7 @@ ErrorOr<NonnullRefPtr<Process>> Process::try_create_user_process(LockRefPtr<Thre Thread* new_main_thread = nullptr; InterruptsState previous_interrupts_state = InterruptsState::Enabled; - if (auto result = process->exec(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<NonnullRefPtr<Process>> Process::try_create_user_process(LockRefPtr<Thre new_main_thread->set_state(Thread::State::Runnable); } - return process; + return ProcessAndFirstThread { move(process), move(first_thread) }; } -RefPtr<Process> Process::create_kernel_process(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register) +ErrorOr<Process::ProcessAndFirstThread> Process::create_kernel_process(NonnullOwnPtr<KString> 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<NonnullRefPtr<Process>> Process::try_create(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, Process* fork_parent) +ErrorOr<Process::ProcessAndFirstThread> Process::create(NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, Process* fork_parent) { OwnPtr<Memory::AddressSpace> new_address_space; if (fork_parent) { @@ -303,9 +298,11 @@ ErrorOr<NonnullRefPtr<Process>> Process::try_create(LockRefPtr<Thread>& 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<KString> name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree) @@ -332,7 +329,7 @@ Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credent } } -ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& preallocated_space, LockRefPtr<Thread>& first_thread, Process* fork_parent) +ErrorOr<NonnullLockRefPtr<Thread>> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& preallocated_space, Process* fork_parent) { m_space.with([&](auto& space) { space = move(preallocated_space); @@ -347,7 +344,7 @@ ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& 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<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& 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> process; + NonnullLockRefPtr<Thread> first_thread; + }; + template<typename EntryFunction> - static RefPtr<Process> create_kernel_process(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, EntryFunction entry, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes) + static ErrorOr<ProcessAndFirstThread> create_kernel_process(NonnullOwnPtr<KString> 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<EntryFunction>, entry_func, affinity, do_register); + return create_kernel_process(move(name), &Process::kernel_process_trampoline<EntryFunction>, entry_func, affinity, do_register); } - static RefPtr<Process> create_kernel_process(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes); - static ErrorOr<NonnullRefPtr<Process>> try_create_user_process(LockRefPtr<Thread>& first_thread, StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, TTY*); + static ErrorOr<ProcessAndFirstThread> create_kernel_process(NonnullOwnPtr<KString> name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes); + static ErrorOr<ProcessAndFirstThread> create_user_process(StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, TTY*); static void register_new(Process&); ~Process(); @@ -594,8 +599,8 @@ private: bool remove_thread(Thread&); Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials>, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree); - static ErrorOr<NonnullRefPtr<Process>> try_create(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); - ErrorOr<void> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, LockRefPtr<Thread>& first_thread, Process* fork_parent); + static ErrorOr<ProcessAndFirstThread> create(NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); + ErrorOr<NonnullLockRefPtr<Thread>> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, 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<Thread> 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,20 +18,19 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::proc)); - LockRefPtr<Thread> child_first_thread; + + auto child_name = TRY(name().with([](auto& name) { return name->try_clone(); })); + auto credentials = this->credentials(); + 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); - if (child_first_thread) { - child_first_thread->detach(); - child_first_thread->set_state(Thread::State::Dying); - } + 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)); - // 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<Thread> 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<Thread> 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> 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) |