mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									65438d8a85
								
							
						
					
					
						commit
						a098266ff5
					
				
					 12 changed files with 319 additions and 78 deletions
				
			
		
							
								
								
									
										255
									
								
								Kernel/Arch/aarch64/init.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								Kernel/Arch/aarch64/init.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -281,13 +281,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo con | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     { |     MUST(Process::create_kernel_process(KString::must_create("init_stage2"sv), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No)); | ||||||
|         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
 |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Scheduler::start(); |     Scheduler::start(); | ||||||
|     VERIFY_NOT_REACHED(); |     VERIFY_NOT_REACHED(); | ||||||
|  | @ -415,17 +409,17 @@ void init_stage2(void*) | ||||||
|     // NOTE: Everything marked UNMAP_AFTER_INIT becomes inaccessible after this point.
 |     // NOTE: Everything marked UNMAP_AFTER_INIT becomes inaccessible after this point.
 | ||||||
|     MM.unmap_text_after_init(); |     MM.unmap_text_after_init(); | ||||||
| 
 | 
 | ||||||
|     LockRefPtr<Thread> thread; |  | ||||||
|     auto userspace_init = kernel_command_line().userspace_init(); |     auto userspace_init = kernel_command_line().userspace_init(); | ||||||
|     auto init_args = kernel_command_line().userspace_init_args(); |     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()) |     if (init_or_error.is_error()) | ||||||
|         PANIC("init_stage2: Error spawning init process: {}", init_or_error.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) { |     if (boot_profiling) { | ||||||
|         dbgln("Starting full system boot profiling"); |         dbgln("Starting full system boot profiling"); | ||||||
|  |  | ||||||
|  | @ -585,22 +585,20 @@ size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue) | ||||||
| 
 | 
 | ||||||
| ErrorOr<void> UHCIController::spawn_port_process() | ErrorOr<void> UHCIController::spawn_port_process() | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> usb_hotplug_thread; |     TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Hot Plug Task"sv)), [&] { | ||||||
|     (void)Process::create_kernel_process(usb_hotplug_thread, TRY(KString::try_create("UHCI Hot Plug Task"sv)), [&] { |  | ||||||
|         for (;;) { |         for (;;) { | ||||||
|             if (m_root_hub) |             if (m_root_hub) | ||||||
|                 m_root_hub->check_for_port_updates(); |                 m_root_hub->check_for_port_updates(); | ||||||
| 
 | 
 | ||||||
|             (void)Thread::current()->sleep(Time::from_seconds(1)); |             (void)Thread::current()->sleep(Time::from_seconds(1)); | ||||||
|         } |         } | ||||||
|     }); |     })); | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ErrorOr<void> UHCIController::spawn_async_poll_process() | ErrorOr<void> UHCIController::spawn_async_poll_process() | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> async_poll_thread; |     TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Async Poll Task"sv)), [&] { | ||||||
|     (void)Process::create_kernel_process(async_poll_thread, TRY(KString::try_create("UHCI Async Poll Task"sv)), [&] { |  | ||||||
|         u16 poll_interval_ms = 1024; |         u16 poll_interval_ms = 1024; | ||||||
|         for (;;) { |         for (;;) { | ||||||
|             { |             { | ||||||
|  | @ -620,7 +618,7 @@ ErrorOr<void> UHCIController::spawn_async_poll_process() | ||||||
|             } |             } | ||||||
|             (void)Thread::current()->sleep(Time::from_milliseconds(poll_interval_ms)); |             (void)Thread::current()->sleep(Time::from_milliseconds(poll_interval_ms)); | ||||||
|         } |         } | ||||||
|     }); |     })); | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -353,10 +353,11 @@ void Plan9FS::ensure_thread() | ||||||
|         auto process_name = KString::try_create("Plan9FS"sv); |         auto process_name = KString::try_create("Plan9FS"sv); | ||||||
|         if (process_name.is_error()) |         if (process_name.is_error()) | ||||||
|             TODO(); |             TODO(); | ||||||
|         (void)Process::create_kernel_process(m_thread, process_name.release_value(), [&]() { |         auto [_, thread] = Process::create_kernel_process(process_name.release_value(), [&]() { | ||||||
|             thread_main(); |             thread_main(); | ||||||
|             m_thread_running.store(false, AK::MemoryOrder::memory_order_release); |             m_thread_running.store(false, AK::MemoryOrder::memory_order_release); | ||||||
|         }); |         }).release_value_but_fixme_should_propagate_errors(); | ||||||
|  |         m_thread = move(thread); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -42,12 +42,11 @@ static HashTable<NonnullRefPtr<TCPSocket>>* delayed_ack_sockets; | ||||||
| 
 | 
 | ||||||
| void NetworkTask::spawn() | void NetworkTask::spawn() | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> thread; |  | ||||||
|     auto name = KString::try_create("Network Task"sv); |     auto name = KString::try_create("Network Task"sv); | ||||||
|     if (name.is_error()) |     if (name.is_error()) | ||||||
|         TODO(); |         TODO(); | ||||||
|     (void)Process::create_kernel_process(thread, name.release_value(), NetworkTask_main, nullptr); |     auto [_, first_thread] = MUST(Process::create_kernel_process(name.release_value(), NetworkTask_main, nullptr)); | ||||||
|     network_task = thread; |     network_task = first_thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool NetworkTask::is_current() | bool NetworkTask::is_current() | ||||||
|  |  | ||||||
|  | @ -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('/'); |     auto parts = path.split_view('/'); | ||||||
|     if (arguments.is_empty()) { |     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 path_string = TRY(KString::try_create(path)); | ||||||
|     auto name = TRY(KString::try_create(parts.last())); |     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(process->m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> { | ||||||
|         TRY(fds.try_resize(Process::OpenFileDescriptions::max_open())); |         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; |     Thread* new_main_thread = nullptr; | ||||||
|     InterruptsState previous_interrupts_state = InterruptsState::Enabled; |     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()) { |     TRY(process->exec(move(path_string), move(arguments), move(environment), new_main_thread, previous_interrupts_state)); | ||||||
|         dbgln("Failed to exec {}: {}", path, result.error()); |  | ||||||
|         first_thread = nullptr; |  | ||||||
|         return result.release_error(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     register_new(*process); |     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); |         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); |     auto process_and_first_thread = TRY(Process::create(move(name), UserID(0), GroupID(0), ProcessID(0), true)); | ||||||
|     if (process_or_error.is_error()) |     auto& process = *process_and_first_thread.process; | ||||||
|         return {}; |     auto& thread = *process_and_first_thread.first_thread; | ||||||
|     auto process = process_or_error.release_value(); |  | ||||||
| 
 | 
 | ||||||
|     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) |     if (do_register == RegisterProcess::Yes) | ||||||
|         register_new(*process); |         register_new(process); | ||||||
| 
 | 
 | ||||||
|     SpinlockLocker lock(g_scheduler_lock); |     SpinlockLocker lock(g_scheduler_lock); | ||||||
|     first_thread->set_affinity(affinity); |     thread.set_affinity(affinity); | ||||||
|     first_thread->set_state(Thread::State::Runnable); |     thread.set_state(Thread::State::Runnable); | ||||||
|     return process; |     return process_and_first_thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Process::protect_data() | 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; |     OwnPtr<Memory::AddressSpace> new_address_space; | ||||||
|     if (fork_parent) { |     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 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 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 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)))); |     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)); |     auto first_thread = TRY(process->attach_resources(new_address_space.release_nonnull(), fork_parent)); | ||||||
|     return process; | 
 | ||||||
|  |     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) | 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) { |     m_space.with([&](auto& space) { | ||||||
|         space = move(preallocated_space); |         space = move(preallocated_space); | ||||||
|  | @ -347,7 +344,7 @@ ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& pr | ||||||
|         return Thread::try_create(*this); |         return Thread::try_create(*this); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     first_thread = TRY(create_first_thread()); |     auto first_thread = TRY(create_first_thread()); | ||||||
| 
 | 
 | ||||||
|     if (!fork_parent) { |     if (!fork_parent) { | ||||||
|         // FIXME: Figure out if this is really necessary.
 |         // FIXME: Figure out if this is really necessary.
 | ||||||
|  | @ -359,7 +356,7 @@ ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& pr | ||||||
|     if (fork_parent) |     if (fork_parent) | ||||||
|         m_signal_action_data = fork_parent->m_signal_action_data; |         m_signal_action_data = fork_parent->m_signal_action_data; | ||||||
| 
 | 
 | ||||||
|     return {}; |     return first_thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Process::~Process() | Process::~Process() | ||||||
|  |  | ||||||
|  | @ -185,15 +185,20 @@ public: | ||||||
|         Yes |         Yes | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     struct ProcessAndFirstThread { | ||||||
|  |         NonnullRefPtr<Process> process; | ||||||
|  |         NonnullLockRefPtr<Thread> first_thread; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     template<typename EntryFunction> |     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)); |         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<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<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_user_process(StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, TTY*); | ||||||
|     static void register_new(Process&); |     static void register_new(Process&); | ||||||
| 
 | 
 | ||||||
|     ~Process(); |     ~Process(); | ||||||
|  | @ -594,8 +599,8 @@ private: | ||||||
|     bool remove_thread(Thread&); |     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); |     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); |     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<void> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, LockRefPtr<Thread>& first_thread, Process* fork_parent); |     ErrorOr<NonnullLockRefPtr<Thread>> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, Process* fork_parent); | ||||||
|     static ProcessID allocate_pid(); |     static ProcessID allocate_pid(); | ||||||
| 
 | 
 | ||||||
|     void kill_threads_except_self(); |     void kill_threads_except_self(); | ||||||
|  |  | ||||||
|  | @ -366,13 +366,11 @@ UNMAP_AFTER_INIT void Scheduler::initialize() | ||||||
|     VERIFY(Processor::is_initialized()); // sanity check
 |     VERIFY(Processor::is_initialized()); // sanity check
 | ||||||
|     VERIFY(TimeManagement::is_initialized()); |     VERIFY(TimeManagement::is_initialized()); | ||||||
| 
 | 
 | ||||||
|     LockRefPtr<Thread> idle_thread; |  | ||||||
|     g_finalizer_wait_queue = new WaitQueue; |     g_finalizer_wait_queue = new WaitQueue; | ||||||
| 
 | 
 | ||||||
|     g_finalizer_has_work.store(false, AK::MemoryOrder::memory_order_release); |     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(); |     auto [colonel_process, idle_thread] = MUST(Process::create_kernel_process(KString::must_create("colonel"sv), idle_loop, nullptr, 1, Process::RegisterProcess::No)); | ||||||
|     VERIFY(s_colonel_process); |     s_colonel_process = &colonel_process.leak_ref(); | ||||||
|     VERIFY(idle_thread); |  | ||||||
|     idle_thread->set_priority(THREAD_PRIORITY_MIN); |     idle_thread->set_priority(THREAD_PRIORITY_MIN); | ||||||
|     idle_thread->set_name(KString::must_create("Idle Task #0"sv)); |     idle_thread->set_name(KString::must_create("Idle Task #0"sv)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,19 +18,18 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs) | ||||||
| { | { | ||||||
|     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); |     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); | ||||||
|     TRY(require_promise(Pledge::proc)); |     TRY(require_promise(Pledge::proc)); | ||||||
|     LockRefPtr<Thread> 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 child_name = TRY(name().with([](auto& name) { return name->try_clone(); })); | ||||||
|     auto credentials = this->credentials(); |     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().
 |     // NOTE: All user processes have a leaked ref on them. It's balanced by Thread::WaitBlockerSet::finalize().
 | ||||||
|     child->ref(); |     child->ref(); | ||||||
|  |  | ||||||
|  | @ -28,10 +28,8 @@ static void finalizer_task(void*) | ||||||
| 
 | 
 | ||||||
| UNMAP_AFTER_INIT void FinalizerTask::spawn() | UNMAP_AFTER_INIT void FinalizerTask::spawn() | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> finalizer_thread; |     auto [_, finalizer_thread] = MUST(Process::create_kernel_process(KString::must_create(finalizer_task_name), finalizer_task, nullptr)); | ||||||
|     auto finalizer_process = Process::create_kernel_process(finalizer_thread, KString::must_create(finalizer_task_name), finalizer_task, nullptr); |     g_finalizer = move(finalizer_thread); | ||||||
|     VERIFY(finalizer_process); |  | ||||||
|     g_finalizer = finalizer_thread; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,14 +14,13 @@ namespace Kernel { | ||||||
| 
 | 
 | ||||||
| UNMAP_AFTER_INIT void SyncTask::spawn() | UNMAP_AFTER_INIT void SyncTask::spawn() | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> syncd_thread; |     MUST(Process::create_kernel_process(KString::must_create("VFS Sync Task"sv), [] { | ||||||
|     (void)Process::create_kernel_process(syncd_thread, KString::must_create("VFS Sync Task"sv), [] { |  | ||||||
|         dbgln("VFS SyncTask is running"); |         dbgln("VFS SyncTask is running"); | ||||||
|         for (;;) { |         for (;;) { | ||||||
|             VirtualFileSystem::sync(); |             VirtualFileSystem::sync(); | ||||||
|             (void)Thread::current()->sleep(Time::from_seconds(1)); |             (void)Thread::current()->sleep(Time::from_seconds(1)); | ||||||
|         } |         } | ||||||
|     }); |     })); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,11 +24,10 @@ UNMAP_AFTER_INIT void WorkQueue::initialize() | ||||||
| 
 | 
 | ||||||
| UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name) | UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name) | ||||||
| { | { | ||||||
|     LockRefPtr<Thread> thread; |  | ||||||
|     auto name_kstring = KString::try_create(name); |     auto name_kstring = KString::try_create(name); | ||||||
|     if (name_kstring.is_error()) |     if (name_kstring.is_error()) | ||||||
|         TODO(); |         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) | #if ARCH(AARCH64) | ||||||
|         // FIXME: This function expects to be executed with interrupts disabled, however on
 |         // 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.
 |         //        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({}); |             [[maybe_unused]] auto result = m_wait_queue.wait_on({}); | ||||||
|         } |         } | ||||||
|     }); |     }).release_value_but_fixme_should_propagate_errors(); | ||||||
|     // If we can't create the thread we're in trouble...
 |     m_thread = move(thread); | ||||||
|     m_thread = thread.release_nonnull(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WorkQueue::do_queue(WorkItem& item) | void WorkQueue::do_queue(WorkItem& item) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling