1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:48:11 +00:00

Kernel: Don't allocate memory for names of processes and threads

Instead, use the FixedCharBuffer class to ensure we always use a static
buffer storage for these names. This ensures that if a Process or a
Thread were created, there's a guarantee that setting a new name will
never fail, as only copying of strings should be done to that static
storage.

The limits which are set are 32 characters for processes' names and 64
characters for thread names - this is because threads' names could be
more verbose than processes' names.
This commit is contained in:
Liav A 2023-07-17 18:34:19 +03:00 committed by Andrew Kaster
parent 0d30f558f4
commit 3fd4997fc2
22 changed files with 102 additions and 110 deletions

View file

@ -920,7 +920,7 @@ void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
if (Kernel::Thread::current()) { if (Kernel::Thread::current()) {
auto& thread = *Kernel::Thread::current(); auto& thread = *Kernel::Thread::current();
thread.process().name().with([&](auto& process_name) { thread.process().name().with([&](auto& process_name) {
builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id(), process_name->view(), thread.pid().value(), thread.tid().value()); builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id(), process_name.representable_view(), thread.pid().value(), thread.tid().value());
}); });
} else { } else {
builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id()); builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id());
@ -974,7 +974,7 @@ void vdmesgln(StringView fmtstr, TypeErasedFormatParams& params)
if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) { if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
auto& thread = *Kernel::Thread::current(); auto& thread = *Kernel::Thread::current();
thread.process().name().with([&](auto& process_name) { thread.process().name().with([&](auto& process_name) {
builder.appendff("{}.{:03} \033[34;1m[{}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, process_name->view(), thread.pid().value(), thread.tid().value()); builder.appendff("{}.{:03} \033[34;1m[{}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, process_name.representable_view(), thread.pid().value(), thread.tid().value());
}); });
} else { } else {
builder.appendff("{}.{:03} \033[34;1m[Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000); builder.appendff("{}.{:03} \033[34;1m[Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000);
@ -1001,7 +1001,7 @@ void v_critical_dmesgln(StringView fmtstr, TypeErasedFormatParams& params)
if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) { if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
auto& thread = *Kernel::Thread::current(); auto& thread = *Kernel::Thread::current();
thread.process().name().with([&](auto& process_name) { thread.process().name().with([&](auto& process_name) {
builder.appendff("[{}({}:{})]: ", process_name->view(), thread.pid().value(), thread.tid().value()); builder.appendff("[{}({}:{})]: ", process_name.representable_view(), thread.pid().value(), thread.tid().value());
}); });
} else { } else {
builder.appendff("[Kernel]: "); builder.appendff("[Kernel]: ");

View file

@ -298,7 +298,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)); MUST(Process::create_kernel_process("init_stage2"sv, init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No));
Scheduler::start(); Scheduler::start();
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();

View file

@ -585,7 +585,7 @@ size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue)
ErrorOr<void> UHCIController::spawn_port_process() ErrorOr<void> UHCIController::spawn_port_process()
{ {
TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Hot Plug Task"sv)), [&] { TRY(Process::create_kernel_process("UHCI Hot Plug Task"sv, [&] {
while (!Process::current().is_dying()) { while (!Process::current().is_dying()) {
if (m_root_hub) if (m_root_hub)
m_root_hub->check_for_port_updates(); m_root_hub->check_for_port_updates();
@ -600,7 +600,7 @@ ErrorOr<void> UHCIController::spawn_port_process()
ErrorOr<void> UHCIController::spawn_async_poll_process() ErrorOr<void> UHCIController::spawn_async_poll_process()
{ {
TRY(Process::create_kernel_process(TRY(KString::try_create("UHCI Async Poll Task"sv)), [&] { TRY(Process::create_kernel_process("UHCI Async Poll Task"sv, [&] {
u16 poll_interval_ms = 1024; u16 poll_interval_ms = 1024;
while (!Process::current().is_dying()) { while (!Process::current().is_dying()) {
{ {

View file

@ -350,10 +350,7 @@ void Plan9FS::ensure_thread()
{ {
SpinlockLocker lock(m_thread_lock); SpinlockLocker lock(m_thread_lock);
if (!m_thread_running.exchange(true, AK::MemoryOrder::memory_order_acq_rel)) { if (!m_thread_running.exchange(true, AK::MemoryOrder::memory_order_acq_rel)) {
auto process_name = KString::try_create("Plan9FS"sv); auto [_, thread] = Process::create_kernel_process("Plan9FS"sv, [&]() {
if (process_name.is_error())
TODO();
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);
Process::current().sys$exit(0); Process::current().sys$exit(0);

View file

@ -81,7 +81,7 @@ ErrorOr<void> SysFSOverallProcesses::try_generate(KBufferBuilder& builder)
} else { } else {
TRY(process_object.add("tty"sv, "")); TRY(process_object.add("tty"sv, ""));
} }
TRY(process.name().with([&](auto& process_name) { return process_object.add("name"sv, process_name->view()); })); TRY(process.name().with([&](auto& process_name) { return process_object.add("name"sv, process_name.representable_view()); }));
TRY(process_object.add("executable"sv, process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv)); TRY(process_object.add("executable"sv, process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv));
TRY(process_object.add("creation_time"sv, process.creation_time().nanoseconds_since_epoch())); TRY(process_object.add("creation_time"sv, process.creation_time().nanoseconds_since_epoch()));
@ -121,7 +121,7 @@ ErrorOr<void> SysFSOverallProcesses::try_generate(KBufferBuilder& builder)
TRY(thread_object.add("lock_count"sv, thread.lock_count())); TRY(thread_object.add("lock_count"sv, thread.lock_count()));
#endif #endif
TRY(thread_object.add("tid"sv, thread.tid().value())); TRY(thread_object.add("tid"sv, thread.tid().value()));
TRY(thread.name().with([&](auto& thread_name) { return thread_object.add("name"sv, thread_name->view()); })); TRY(thread.name().with([&](auto& thread_name) { return thread_object.add("name"sv, thread_name.representable_view()); }));
TRY(thread_object.add("times_scheduled"sv, thread.times_scheduled())); TRY(thread_object.add("times_scheduled"sv, thread.times_scheduled()));
TRY(thread_object.add("time_user"sv, thread.time_in_user())); TRY(thread_object.add("time_user"sv, thread.time_in_user()));
TRY(thread_object.add("time_kernel"sv, thread.time_in_kernel())); TRY(thread_object.add("time_kernel"sv, thread.time_in_kernel()));

View file

@ -904,7 +904,7 @@ ErrorOr<CommittedPhysicalPageSet> MemoryManager::commit_physical_pages(size_t pa
}); });
process.name().with([&](auto& process_name) { process.name().with([&](auto& process_name) {
dbgln("{}({}) resident:{}, shared:{}, virtual:{}", dbgln("{}({}) resident:{}, shared:{}, virtual:{}",
process_name->view(), process_name.representable_view(),
process.pid(), process.pid(),
amount_resident / PAGE_SIZE, amount_resident / PAGE_SIZE,
amount_shared / PAGE_SIZE, amount_shared / PAGE_SIZE,

View file

@ -42,10 +42,7 @@ static HashTable<NonnullRefPtr<TCPSocket>>* delayed_ack_sockets;
void NetworkTask::spawn() void NetworkTask::spawn()
{ {
auto name = KString::try_create("Network Task"sv); auto [_, first_thread] = MUST(Process::create_kernel_process("Network Task"sv, NetworkTask_main, nullptr));
if (name.is_error())
TODO();
auto [_, first_thread] = MUST(Process::create_kernel_process(name.release_value(), NetworkTask_main, nullptr));
network_task = first_thread; network_task = first_thread;
} }

View file

@ -480,9 +480,6 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
auto last_part = path->view().find_last_split_view('/'); auto last_part = path->view().find_last_split_view('/');
auto new_process_name = TRY(KString::try_create(last_part));
auto new_main_thread_name = TRY(new_process_name->try_clone());
auto allocated_space = TRY(Memory::AddressSpace::try_create(*this, nullptr)); auto allocated_space = TRY(Memory::AddressSpace::try_create(*this, nullptr));
OwnPtr<Memory::AddressSpace> old_space; OwnPtr<Memory::AddressSpace> old_space;
auto old_master_tls_region = m_master_tls_region; auto old_master_tls_region = m_master_tls_region;
@ -659,8 +656,9 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
// and we don't want to deal with faults after this point. // and we don't want to deal with faults after this point.
auto new_userspace_sp = TRY(make_userspace_context_for_main_thread(new_main_thread->regs(), *load_result.stack_region.unsafe_ptr(), m_arguments, m_environment, move(auxv))); auto new_userspace_sp = TRY(make_userspace_context_for_main_thread(new_main_thread->regs(), *load_result.stack_region.unsafe_ptr(), m_arguments, m_environment, move(auxv)));
set_name(move(new_process_name)); // NOTE: The Process and its first thread share the same name.
new_main_thread->set_name(move(new_main_thread_name)); set_name(last_part);
new_main_thread->set_name(last_part);
if (wait_for_tracer_at_next_execve()) { if (wait_for_tracer_at_next_execve()) {
// Make sure we release the ptrace lock here or the tracer will block forever. // Make sure we release the ptrace lock here or the tracer will block forever.

View file

@ -20,9 +20,8 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::proc)); TRY(require_promise(Pledge::proc));
auto child_name = TRY(name().with([](auto& name) { return name->try_clone(); }));
auto credentials = this->credentials(); 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(), tty(), this)); auto child_and_first_thread = TRY(Process::create_with_forked_name(credentials->uid(), credentials->gid(), pid(), m_is_kernel_process, current_directory(), executable(), tty(), this));
auto& child = child_and_first_thread.process; auto& child = child_and_first_thread.process;
auto& child_first_thread = child_and_first_thread.first_thread; auto& child_first_thread = child_and_first_thread.first_thread;

View file

@ -22,7 +22,7 @@ ErrorOr<void> Process::do_kill(Process& process, int signal)
return EPERM; return EPERM;
if (process.is_kernel_process()) { if (process.is_kernel_process()) {
process.name().with([&](auto& process_name) { process.name().with([&](auto& process_name) {
dbgln("Attempted to send signal {} to kernel process {} ({})", signal, process_name->view(), process.pid()); dbgln("Attempted to send signal {} to kernel process {} ({})", signal, process_name.representable_view(), process.pid());
}); });
return EPERM; return EPERM;
} }

View file

@ -55,14 +55,13 @@ ErrorOr<FlatPtr> Process::sys$prctl(int option, FlatPtr arg1, FlatPtr arg2)
int user_buffer_size = static_cast<int>(arg2); int user_buffer_size = static_cast<int>(arg2);
if (user_buffer_size < 0) if (user_buffer_size < 0)
return EINVAL; return EINVAL;
if (user_buffer_size > 256)
return ENAMETOOLONG;
size_t buffer_size = static_cast<size_t>(user_buffer_size); size_t buffer_size = static_cast<size_t>(user_buffer_size);
auto name = TRY(try_copy_kstring_from_user(buffer, buffer_size)); Process::Name process_name {};
TRY(try_copy_name_from_user_into_fixed_string_buffer<32>(buffer, process_name, buffer_size));
// NOTE: Reject empty and whitespace-only names, as they only confuse users. // NOTE: Reject empty and whitespace-only names, as they only confuse users.
if (name->view().is_whitespace()) if (process_name.representable_view().is_whitespace())
return EINVAL; return EINVAL;
set_name(move(name)); set_name(process_name.representable_view());
return 0; return 0;
} }
case PR_GET_PROCESS_NAME: { case PR_GET_PROCESS_NAME: {
@ -73,9 +72,10 @@ ErrorOr<FlatPtr> Process::sys$prctl(int option, FlatPtr arg1, FlatPtr arg2)
return EINVAL; return EINVAL;
size_t buffer_size = static_cast<size_t>(arg2); size_t buffer_size = static_cast<size_t>(arg2);
TRY(m_name.with([&buffer, buffer_size](auto& name) -> ErrorOr<void> { TRY(m_name.with([&buffer, buffer_size](auto& name) -> ErrorOr<void> {
if (name->length() + 1 > buffer_size) auto view = name.representable_view();
if (view.length() + 1 > buffer_size)
return ENAMETOOLONG; return ENAMETOOLONG;
return copy_to_user(buffer, name->characters(), name->length() + 1); return copy_to_user(buffer, view.characters_without_null_termination(), view.length() + 1);
})); }));
return 0; return 0;
} }

View file

@ -48,9 +48,9 @@ ErrorOr<FlatPtr> Process::sys$create_thread(void* (*entry)(void*), Userspace<Sys
// We know this thread is not the main_thread, // We know this thread is not the main_thread,
// So give it a unique name until the user calls $set_thread_name on it // So give it a unique name until the user calls $set_thread_name on it
auto new_thread_name = TRY(name().with([&](auto& process_name) { auto new_thread_name = TRY(name().with([&](auto& process_name) {
return KString::formatted("{} [{}]", process_name->view(), thread->tid().value()); return KString::formatted("{} [{}]", process_name.representable_view(), thread->tid().value());
})); }));
thread->set_name(move(new_thread_name)); thread->set_name(new_thread_name->view());
if (!is_thread_joinable) if (!is_thread_joinable)
thread->detach(); thread->detach();
@ -194,17 +194,14 @@ ErrorOr<FlatPtr> Process::sys$set_thread_name(pid_t tid, Userspace<char const*>
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
auto name = TRY(try_copy_kstring_from_user(user_name, user_name_length)); Thread::Name thread_name {};
TRY(try_copy_name_from_user_into_fixed_string_buffer<64>(user_name, thread_name, user_name_length));
const size_t max_thread_name_size = 64;
if (name->length() > max_thread_name_size)
return ENAMETOOLONG;
auto thread = Thread::from_tid(tid); auto thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid()) if (!thread || thread->pid() != pid())
return ESRCH; return ESRCH;
thread->set_name(move(name)); thread->set_name(thread_name.representable_view());
return 0; return 0;
} }
@ -220,16 +217,12 @@ ErrorOr<FlatPtr> Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer
return ESRCH; return ESRCH;
TRY(thread->name().with([&](auto& thread_name) -> ErrorOr<void> { TRY(thread->name().with([&](auto& thread_name) -> ErrorOr<void> {
if (thread_name->view().is_null()) { VERIFY(!thread_name.representable_view().is_null());
char null_terminator = '\0'; auto thread_name_view = thread_name.representable_view();
TRY(copy_to_user(buffer, &null_terminator, sizeof(null_terminator))); if (thread_name_view.length() + 1 > buffer_size)
return {};
}
if (thread_name->length() + 1 > buffer_size)
return ENAMETOOLONG; return ENAMETOOLONG;
return copy_to_user(buffer, thread_name->characters(), thread_name->length() + 1); return copy_to_user(buffer, thread_name_view.characters_without_null_termination(), thread_name_view.length() + 1);
})); }));
return 0; return 0;

View file

@ -30,7 +30,7 @@ static void finalizer_task(void*)
UNMAP_AFTER_INIT void FinalizerTask::spawn() UNMAP_AFTER_INIT void FinalizerTask::spawn()
{ {
auto [_, finalizer_thread] = MUST(Process::create_kernel_process(KString::must_create(finalizer_task_name), finalizer_task, nullptr)); auto [_, finalizer_thread] = MUST(Process::create_kernel_process(finalizer_task_name, finalizer_task, nullptr));
g_finalizer = move(finalizer_thread); g_finalizer = move(finalizer_thread);
} }

View file

@ -340,7 +340,7 @@ ErrorOr<void> PerformanceEventBuffer::add_process(Process const& process, Proces
executable = TRY(process.executable()->try_serialize_absolute_path()); executable = TRY(process.executable()->try_serialize_absolute_path());
} else { } else {
executable = TRY(process.name().with([&](auto& process_name) { executable = TRY(process.name().with([&](auto& process_name) {
return KString::formatted("<{}>", process_name->view()); return KString::formatted("<{}>", process_name.representable_view());
})); }));
} }

View file

@ -26,8 +26,6 @@
namespace Kernel { namespace Kernel {
static constexpr StringView power_state_switch_task_name_view = "Power State Switch Task"sv;
Thread* g_power_state_switch_task; Thread* g_power_state_switch_task;
bool g_in_system_shutdown { false }; bool g_in_system_shutdown { false };
@ -53,12 +51,9 @@ void PowerStateSwitchTask::power_state_switch_task(void* raw_entry_data)
void PowerStateSwitchTask::spawn(PowerStateCommand command) void PowerStateSwitchTask::spawn(PowerStateCommand command)
{ {
// FIXME: If we switch power states during memory pressure, don't let the system crash just because of our task name.
NonnullOwnPtr<KString> power_state_switch_task_name = MUST(KString::try_create(power_state_switch_task_name_view));
VERIFY(g_power_state_switch_task == nullptr); VERIFY(g_power_state_switch_task == nullptr);
auto [_, power_state_switch_task_thread] = MUST(Process::create_kernel_process( auto [_, power_state_switch_task_thread] = MUST(Process::create_kernel_process(
move(power_state_switch_task_name), power_state_switch_task, bit_cast<void*>(command))); "Power State Switch Task"sv, power_state_switch_task, bit_cast<void*>(command)));
g_power_state_switch_task = move(power_state_switch_task_thread); g_power_state_switch_task = move(power_state_switch_task_thread);
} }
@ -189,7 +184,7 @@ ErrorOr<void> PowerStateSwitchTask::kill_processes(ProcessKind kind, ProcessID f
if (process.pid() != Process::current().pid() && !process.is_dead() && process.pid() != finalizer_pid && process.is_kernel_process() == kill_kernel_processes) { if (process.pid() != Process::current().pid() && !process.is_dead() && process.pid() != finalizer_pid && process.is_kernel_process() == kill_kernel_processes) {
dbgln("Process {:2} kernel={} dead={} dying={} ({})", dbgln("Process {:2} kernel={} dead={} dying={} ({})",
process.pid(), process.is_kernel_process(), process.is_dead(), process.is_dying(), process.pid(), process.is_kernel_process(), process.is_dead(), process.is_dying(),
process.name().with([](auto& name) { return name->view(); })); process.name().with([](auto& name) { return name.representable_view(); }));
} }
}); });
} }

View file

@ -219,8 +219,7 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView
} }
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 [process, first_thread] = TRY(Process::create(parts.last(), 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()));
@ -255,9 +254,9 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView
return ProcessAndFirstThread { move(process), move(first_thread) }; return ProcessAndFirstThread { move(process), move(first_thread) };
} }
ErrorOr<Process::ProcessAndFirstThread> Process::create_kernel_process(NonnullOwnPtr<KString> name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register) ErrorOr<Process::ProcessAndFirstThread> Process::create_kernel_process(StringView name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register)
{ {
auto process_and_first_thread = TRY(Process::create(move(name), UserID(0), GroupID(0), ProcessID(0), true)); auto process_and_first_thread = TRY(Process::create(name, UserID(0), GroupID(0), ProcessID(0), true));
auto& process = *process_and_first_thread.process; auto& process = *process_and_first_thread.process;
auto& thread = *process_and_first_thread.first_thread; auto& thread = *process_and_first_thread.first_thread;
@ -286,13 +285,22 @@ void Process::unprotect_data()
}); });
} }
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, RefPtr<TTY> tty, Process* fork_parent) ErrorOr<Process::ProcessAndFirstThread> Process::create_with_forked_name(UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
{
Process::Name name {};
Process::current().name().with([&name](auto& process_name) {
name.store_characters(process_name.representable_view());
});
return TRY(Process::create(name.representable_view(), uid, gid, ppid, is_kernel_process, current_directory, executable, tty, fork_parent));
}
ErrorOr<Process::ProcessAndFirstThread> Process::create(StringView name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
{ {
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), kgettimeofday()))); auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(name, move(credentials), ppid, is_kernel_process, move(current_directory), move(executable), tty, move(unveil_tree), move(exec_unveil_tree), kgettimeofday())));
OwnPtr<Memory::AddressSpace> new_address_space; OwnPtr<Memory::AddressSpace> new_address_space;
if (fork_parent) { if (fork_parent) {
@ -309,9 +317,8 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create(NonnullOwnPtr<KString> n
return ProcessAndFirstThread { move(process), move(first_thread) }; 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, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time) Process::Process(StringView name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time)
: m_name(move(name)) : m_is_kernel_process(is_kernel_process)
, m_is_kernel_process(is_kernel_process)
, m_executable(move(executable)) , m_executable(move(executable))
, m_current_directory(move(current_directory)) , m_current_directory(move(current_directory))
, m_creation_time(creation_time) , m_creation_time(creation_time)
@ -319,6 +326,7 @@ Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credent
, m_exec_unveil_data(move(exec_unveil_tree)) , m_exec_unveil_data(move(exec_unveil_tree))
, m_wait_blocker_set(*this) , m_wait_blocker_set(*this)
{ {
set_name(name);
// Ensure that we protect the process data when exiting the constructor. // Ensure that we protect the process data when exiting the constructor.
with_mutable_protected_data([&](auto& protected_data) { with_mutable_protected_data([&](auto& protected_data) {
protected_data.pid = allocate_pid(); protected_data.pid = allocate_pid();
@ -329,7 +337,7 @@ Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credent
if constexpr (PROCESS_DEBUG) { if constexpr (PROCESS_DEBUG) {
this->name().with([&](auto& process_name) { this->name().with([&](auto& process_name) {
dbgln("Created new process {}({})", process_name->view(), this->pid().value()); dbgln("Created new process {}({})", process_name.representable_view(), this->pid().value());
}); });
} }
} }
@ -701,7 +709,7 @@ ErrorOr<void> Process::dump_core()
return {}; return {};
} }
auto coredump_path = TRY(name().with([&](auto& process_name) { auto coredump_path = TRY(name().with([&](auto& process_name) {
return KString::formatted("{}/{}_{}_{}", coredump_directory_path->view(), process_name->view(), pid().value(), kgettimeofday().seconds_since_epoch()); return KString::formatted("{}/{}_{}_{}", coredump_directory_path->view(), process_name.representable_view(), pid().value(), kgettimeofday().seconds_since_epoch());
})); }));
auto coredump = TRY(Coredump::try_create(*this, coredump_path->view())); auto coredump = TRY(Coredump::try_create(*this, coredump_path->view()));
return coredump->write(); return coredump->write();
@ -715,7 +723,7 @@ ErrorOr<void> Process::dump_perfcore()
// Try to generate a filename which isn't already used. // Try to generate a filename which isn't already used.
auto base_filename = TRY(name().with([&](auto& process_name) { auto base_filename = TRY(name().with([&](auto& process_name) {
return KString::formatted("{}_{}", process_name->view(), pid().value()); return KString::formatted("{}_{}", process_name.representable_view(), pid().value());
})); }));
auto perfcore_filename = TRY(KString::formatted("{}.profile", base_filename)); auto perfcore_filename = TRY(KString::formatted("{}.profile", base_filename));
RefPtr<OpenFileDescription> description; RefPtr<OpenFileDescription> description;
@ -757,7 +765,7 @@ void Process::finalize()
if (veil_state() == VeilState::Dropped) { if (veil_state() == VeilState::Dropped) {
name().with([&](auto& process_name) { name().with([&](auto& process_name) {
dbgln("\x1b[01;31mProcess '{}' exited with the veil left open\x1b[0m", process_name->view()); dbgln("\x1b[01;31mProcess '{}' exited with the veil left open\x1b[0m", process_name.representable_view());
}); });
} }
@ -888,7 +896,7 @@ void Process::die()
if constexpr (PROCESS_DEBUG) { if constexpr (PROCESS_DEBUG) {
process.name().with([&](auto& process_name) { process.name().with([&](auto& process_name) {
name().with([&](auto& name) { name().with([&](auto& name) {
dbgln("Process {} ({}) is attached by {} ({}) which will exit", process_name->view(), process.pid(), name->view(), pid()); dbgln("Process {} ({}) is attached by {} ({}) which will exit", process_name.representable_view(), process.pid(), name.representable_view(), pid());
}); });
}); });
} }
@ -896,7 +904,7 @@ void Process::die()
auto err = process.send_signal(SIGSTOP, this); auto err = process.send_signal(SIGSTOP, this);
if (err.is_error()) { if (err.is_error()) {
process.name().with([&](auto& process_name) { process.name().with([&](auto& process_name) {
dbgln("Failed to send the SIGSTOP signal to {} ({})", process_name->view(), process.pid()); dbgln("Failed to send the SIGSTOP signal to {} ({})", process_name.representable_view(), process.pid());
}); });
} }
} }
@ -943,14 +951,14 @@ ErrorOr<void> Process::send_signal(u8 signal, Process* sender)
return ESRCH; return ESRCH;
} }
ErrorOr<NonnullRefPtr<Thread>> Process::create_kernel_thread(void (*entry)(void*), void* entry_data, u32 priority, NonnullOwnPtr<KString> name, u32 affinity, bool joinable) ErrorOr<NonnullRefPtr<Thread>> Process::create_kernel_thread(void (*entry)(void*), void* entry_data, u32 priority, StringView name, u32 affinity, bool joinable)
{ {
VERIFY((priority >= THREAD_PRIORITY_MIN) && (priority <= THREAD_PRIORITY_MAX)); VERIFY((priority >= THREAD_PRIORITY_MIN) && (priority <= THREAD_PRIORITY_MAX));
// FIXME: Do something with guard pages? // FIXME: Do something with guard pages?
auto thread = TRY(Thread::create(*this)); auto thread = TRY(Thread::create(*this));
thread->set_name(move(name)); thread->set_name(name);
thread->set_affinity(affinity); thread->set_affinity(affinity);
thread->set_priority(priority); thread->set_priority(priority);
if (!joinable) if (!joinable)
@ -1138,15 +1146,15 @@ ErrorOr<NonnullRefPtr<Custody>> Process::custody_for_dirfd(int dirfd)
return *description->custody(); return *description->custody();
} }
SpinlockProtected<NonnullOwnPtr<KString>, LockRank::None> const& Process::name() const SpinlockProtected<Process::Name, LockRank::None> const& Process::name() const
{ {
return m_name; return m_name;
} }
void Process::set_name(NonnullOwnPtr<KString> name) void Process::set_name(StringView name)
{ {
m_name.with([&](auto& this_name) { m_name.with([name](auto& process_name) {
this_name = move(name); process_name.store_characters(name);
}); });
} }

View file

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <AK/Concepts.h> #include <AK/Concepts.h>
#include <AK/FixedStringBuffer.h>
#include <AK/HashMap.h> #include <AK/HashMap.h>
#include <AK/IntrusiveList.h> #include <AK/IntrusiveList.h>
#include <AK/IntrusiveListRelaxedConst.h> #include <AK/IntrusiveListRelaxedConst.h>
@ -193,13 +194,13 @@ public:
}; };
template<typename EntryFunction> template<typename EntryFunction>
static ErrorOr<ProcessAndFirstThread> create_kernel_process(NonnullOwnPtr<KString> name, EntryFunction entry, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes) static ErrorOr<ProcessAndFirstThread> create_kernel_process(StringView 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(move(name), &Process::kernel_process_trampoline<EntryFunction>, entry_func, affinity, do_register); return create_kernel_process(name, &Process::kernel_process_trampoline<EntryFunction>, entry_func, affinity, do_register);
} }
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_kernel_process(StringView 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, RefPtr<TTY>); static ErrorOr<ProcessAndFirstThread> create_user_process(StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, RefPtr<TTY>);
static void register_new(Process&); static void register_new(Process&);
@ -207,7 +208,7 @@ public:
virtual void remove_from_secondary_lists(); virtual void remove_from_secondary_lists();
ErrorOr<NonnullRefPtr<Thread>> create_kernel_thread(void (*entry)(void*), void* entry_data, u32 priority, NonnullOwnPtr<KString> name, u32 affinity = THREAD_AFFINITY_DEFAULT, bool joinable = true); ErrorOr<NonnullRefPtr<Thread>> create_kernel_thread(void (*entry)(void*), void* entry_data, u32 priority, StringView name, u32 affinity = THREAD_AFFINITY_DEFAULT, bool joinable = true);
bool is_profiling() const { return m_profiling; } bool is_profiling() const { return m_profiling; }
void set_profiling(bool profiling) { m_profiling = profiling; } void set_profiling(bool profiling) { m_profiling = profiling; }
@ -228,8 +229,9 @@ public:
static RefPtr<Process> from_pid_ignoring_jails(ProcessID); static RefPtr<Process> from_pid_ignoring_jails(ProcessID);
static SessionID get_sid_from_pgid(ProcessGroupID pgid); static SessionID get_sid_from_pgid(ProcessGroupID pgid);
SpinlockProtected<NonnullOwnPtr<KString>, LockRank::None> const& name() const; using Name = FixedStringBuffer<32>;
void set_name(NonnullOwnPtr<KString>); SpinlockProtected<Name, LockRank::None> const& name() const;
void set_name(StringView);
ProcessID pid() const ProcessID pid() const
{ {
@ -612,8 +614,9 @@ private:
bool add_thread(Thread&); bool add_thread(Thread&);
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, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time); Process(StringView name, NonnullRefPtr<Credentials>, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time);
static ErrorOr<ProcessAndFirstThread> create(NonnullOwnPtr<KString> name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr); static ErrorOr<ProcessAndFirstThread> create_with_forked_name(UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
static ErrorOr<ProcessAndFirstThread> create(StringView name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
ErrorOr<NonnullRefPtr<Thread>> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, Process* fork_parent); ErrorOr<NonnullRefPtr<Thread>> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, Process* fork_parent);
static ProcessID allocate_pid(); static ProcessID allocate_pid();
@ -684,7 +687,7 @@ private:
return nullptr; return nullptr;
} }
SpinlockProtected<NonnullOwnPtr<KString>, LockRank::None> m_name; SpinlockProtected<Name, LockRank::None> m_name;
SpinlockProtected<OwnPtr<Memory::AddressSpace>, LockRank::None> m_space; SpinlockProtected<OwnPtr<Memory::AddressSpace>, LockRank::None> m_space;
@ -1046,7 +1049,7 @@ struct AK::Formatter<Kernel::Process> : AK::Formatter<FormatString> {
ErrorOr<void> format(FormatBuilder& builder, Kernel::Process const& value) ErrorOr<void> format(FormatBuilder& builder, Kernel::Process const& value)
{ {
return value.name().with([&](auto& process_name) { return value.name().with([&](auto& process_name) {
return AK::Formatter<FormatString>::format(builder, "{}({})"sv, process_name->view(), value.pid().value()); return AK::Formatter<FormatString>::format(builder, "{}({})"sv, process_name.representable_view(), value.pid().value());
}); });
} }
}; };

View file

@ -372,10 +372,10 @@ UNMAP_AFTER_INIT void Scheduler::initialize()
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);
auto [colonel_process, idle_thread] = MUST(Process::create_kernel_process(KString::must_create("colonel"sv), idle_loop, nullptr, 1, Process::RegisterProcess::No)); auto [colonel_process, idle_thread] = MUST(Process::create_kernel_process("colonel"sv, idle_loop, nullptr, 1, Process::RegisterProcess::No));
s_colonel_process = &colonel_process.leak_ref(); s_colonel_process = &colonel_process.leak_ref();
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("Idle Task #0"sv);
set_idle_thread(idle_thread); set_idle_thread(idle_thread);
} }
@ -394,7 +394,7 @@ UNMAP_AFTER_INIT Thread* Scheduler::create_ap_idle_thread(u32 cpu)
VERIFY(Processor::is_bootstrap_processor()); VERIFY(Processor::is_bootstrap_processor());
VERIFY(s_colonel_process); VERIFY(s_colonel_process);
Thread* idle_thread = MUST(s_colonel_process->create_kernel_thread(idle_loop, nullptr, THREAD_PRIORITY_MIN, MUST(KString::formatted("idle thread #{}", cpu)), 1 << cpu, false)); Thread* idle_thread = MUST(s_colonel_process->create_kernel_thread(idle_loop, nullptr, THREAD_PRIORITY_MIN, MUST(KString::formatted("idle thread #{}", cpu))->view(), 1 << cpu, false));
VERIFY(idle_thread); VERIFY(idle_thread);
return idle_thread; return idle_thread;
} }

View file

@ -14,7 +14,7 @@ namespace Kernel {
UNMAP_AFTER_INIT void SyncTask::spawn() UNMAP_AFTER_INIT void SyncTask::spawn()
{ {
MUST(Process::create_kernel_process(KString::must_create("VFS Sync Task"sv), [] { MUST(Process::create_kernel_process("VFS Sync Task"sv, [] {
dbgln("VFS SyncTask is running"); dbgln("VFS SyncTask is running");
while (!Process::current().is_dying()) { while (!Process::current().is_dying()) {
VirtualFileSystem::sync(); VirtualFileSystem::sync();

View file

@ -47,16 +47,18 @@ ErrorOr<NonnullRefPtr<Thread>> Thread::create(NonnullRefPtr<Process> process)
auto block_timer = TRY(try_make_ref_counted<Timer>()); auto block_timer = TRY(try_make_ref_counted<Timer>());
auto name = TRY(process->name().with([](auto& name) { return name->try_clone(); })); return adopt_nonnull_ref_or_enomem(new (nothrow) Thread(move(process), move(kernel_stack_region), move(block_timer)));
return adopt_nonnull_ref_or_enomem(new (nothrow) Thread(move(process), move(kernel_stack_region), move(block_timer), move(name)));
} }
Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Memory::Region> kernel_stack_region, NonnullRefPtr<Timer> block_timer, NonnullOwnPtr<KString> name) Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Memory::Region> kernel_stack_region, NonnullRefPtr<Timer> block_timer)
: m_process(move(process)) : m_process(move(process))
, m_kernel_stack_region(move(kernel_stack_region)) , m_kernel_stack_region(move(kernel_stack_region))
, m_name(move(name))
, m_block_timer(move(block_timer)) , m_block_timer(move(block_timer))
{ {
m_process->name().with([this](auto& process_name) {
set_name(process_name.representable_view());
});
bool is_first_thread = m_process->add_thread(*this); bool is_first_thread = m_process->add_thread(*this);
if (is_first_thread) { if (is_first_thread) {
// First thread gets TID == PID // First thread gets TID == PID
@ -74,7 +76,7 @@ Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Memory::Region> ker
if constexpr (THREAD_DEBUG) { if constexpr (THREAD_DEBUG) {
m_process->name().with([&](auto& process_name) { m_process->name().with([&](auto& process_name) {
dbgln("Created new thread {}({}:{})", process_name->view(), m_process->pid().value(), m_tid.value()); dbgln("Created new thread {}({}:{})", process_name.representable_view(), m_process->pid().value(), m_tid.value());
}); });
} }
@ -1465,10 +1467,10 @@ void Thread::track_lock_release(LockRank rank)
m_lock_rank_mask ^= rank; m_lock_rank_mask ^= rank;
} }
void Thread::set_name(NonnullOwnPtr<KString> name) void Thread::set_name(StringView name)
{ {
m_name.with([&](auto& this_name) { m_name.with([name](auto& thread_name) {
this_name = move(name); thread_name.store_characters(name);
}); });
} }
@ -1476,9 +1478,9 @@ void Thread::set_name(NonnullOwnPtr<KString> name)
ErrorOr<void> AK::Formatter<Kernel::Thread>::format(FormatBuilder& builder, Kernel::Thread const& value) ErrorOr<void> AK::Formatter<Kernel::Thread>::format(FormatBuilder& builder, Kernel::Thread const& value)
{ {
return value.process().name().with([&](auto& process_name) { return value.process().name().with([&](auto& thread_name) {
return AK::Formatter<FormatString>::format( return AK::Formatter<FormatString>::format(
builder, builder,
"{}({}:{})"sv, process_name->view(), value.pid().value(), value.tid().value()); "{}({}:{})"sv, thread_name.representable_view(), value.pid().value(), value.tid().value());
}); });
} }

View file

@ -9,6 +9,7 @@
#include <AK/Concepts.h> #include <AK/Concepts.h>
#include <AK/EnumBits.h> #include <AK/EnumBits.h>
#include <AK/Error.h> #include <AK/Error.h>
#include <AK/FixedStringBuffer.h>
#include <AK/IntrusiveList.h> #include <AK/IntrusiveList.h>
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
@ -94,11 +95,13 @@ public:
Process& process() { return m_process; } Process& process() { return m_process; }
Process const& process() const { return m_process; } Process const& process() const { return m_process; }
SpinlockProtected<NonnullOwnPtr<KString>, LockRank::None> const& name() const using Name = FixedStringBuffer<64>;
SpinlockProtected<Name, LockRank::None> const& name() const
{ {
return m_name; return m_name;
} }
void set_name(NonnullOwnPtr<KString> name);
void set_name(StringView);
void finalize(); void finalize();
@ -1083,7 +1086,7 @@ public:
#endif #endif
private: private:
Thread(NonnullRefPtr<Process>, NonnullOwnPtr<Memory::Region>, NonnullRefPtr<Timer>, NonnullOwnPtr<KString>); Thread(NonnullRefPtr<Process>, NonnullOwnPtr<Memory::Region>, NonnullRefPtr<Timer>);
BlockResult block_impl(BlockTimeout const&, Blocker&); BlockResult block_impl(BlockTimeout const&, Blocker&);
@ -1221,7 +1224,7 @@ private:
FPUState m_fpu_state {}; FPUState m_fpu_state {};
State m_state { Thread::State::Invalid }; State m_state { Thread::State::Invalid };
SpinlockProtected<NonnullOwnPtr<KString>, LockRank::None> m_name; SpinlockProtected<Name, LockRank::None> m_name;
u32 m_priority { THREAD_PRIORITY_NORMAL }; u32 m_priority { THREAD_PRIORITY_NORMAL };
State m_stop_state { Thread::State::Invalid }; State m_stop_state { Thread::State::Invalid };

View file

@ -24,10 +24,7 @@ UNMAP_AFTER_INIT void WorkQueue::initialize()
UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name) UNMAP_AFTER_INIT WorkQueue::WorkQueue(StringView name)
{ {
auto name_kstring = KString::try_create(name); auto [_, thread] = Process::create_kernel_process(name, [this] {
if (name_kstring.is_error())
TODO();
auto [_, thread] = Process::create_kernel_process(name_kstring.release_value(), [this] {
while (!Process::current().is_dying()) { while (!Process::current().is_dying()) {
WorkItem* item; WorkItem* item;
bool have_more; bool have_more;