Kernel: Implement CLOCK_{PROCESS,THREAD}_CPUTIME_ID

This commit is contained in:
Bananymous 2025-06-26 13:38:50 +03:00
parent 4fa40de557
commit 83c0ef3514
5 changed files with 63 additions and 4 deletions

View File

@ -103,6 +103,10 @@ namespace Kernel
bool is_userspace() const { return m_is_userspace; }
uint64_t cpu_time_ns() const;
void set_cpu_time_start();
void set_cpu_time_stop();
void set_tls(vaddr_t tls) { m_tls = tls; }
vaddr_t get_tls() const { return m_tls; }
@ -155,6 +159,10 @@ namespace Kernel
SpinLock m_signal_lock;
static_assert(_SIGMAX < 64);
mutable SpinLock m_cpu_time_lock;
uint64_t m_cpu_time_ns { 0 };
uint64_t m_cpu_time_start_ns { UINT64_MAX };
BAN::Atomic<uint32_t> m_spinlock_count { 0 };
BAN::Atomic<uint32_t> m_mutex_count { 0 };

View File

@ -2372,11 +2372,9 @@ namespace Kernel
}
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp)
{
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(tp, sizeof(timespec), true));
}
switch (clock_id)
{
@ -2386,10 +2384,31 @@ namespace Kernel
case CLOCK_REALTIME:
*tp = SystemTimer::get().real_time();
break;
case CLOCK_PROCESS_CPUTIME_ID:
{
uint64_t cpu_time_ns { 0 };
for (auto* thread : m_threads)
cpu_time_ns += thread->cpu_time_ns();
*tp = {
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
};
break;
}
case CLOCK_THREAD_CPUTIME_ID:
{
const auto cpu_time_ns = Thread::current().cpu_time_ns();
*tp = {
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
};
break;
}
default:
dwarnln("TODO: clock_gettime({})", clock_id);
return BAN::Error::from_errno(ENOTSUP);
}
return 0;
}

View File

@ -382,6 +382,9 @@ namespace Kernel
}
}
if (!scheduler().is_idle())
Thread::current().set_cpu_time_stop();
#if ARCH(x86_64)
asm volatile(
"movq %%rsp, %%rcx;"
@ -412,6 +415,9 @@ namespace Kernel
processor_info.m_start_ns = SystemTimer::get().ns_since_boot();
if (!scheduler().is_idle())
Thread::current().set_cpu_time_start();
Processor::set_interrupt_state(state);
}

View File

@ -275,7 +275,10 @@ namespace Kernel
page_table.load();
if (thread->state() == Thread::State::NotStarted)
{
thread->m_state = Thread::State::Executing;
thread->set_cpu_time_start();
}
Processor::gdt().set_tss_stack(thread->kernel_stack_top());
Processor::load_tls();

View File

@ -166,6 +166,29 @@ namespace Kernel
}
}
uint64_t Thread::cpu_time_ns() const
{
SpinLockGuard _(m_cpu_time_lock);
if (m_cpu_time_start_ns == UINT64_MAX)
return m_cpu_time_ns;
return m_cpu_time_ns + (SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns);
}
void Thread::set_cpu_time_start()
{
SpinLockGuard _(m_cpu_time_lock);
ASSERT(m_cpu_time_start_ns == UINT64_MAX);
m_cpu_time_start_ns = SystemTimer::get().ns_since_boot();
}
void Thread::set_cpu_time_stop()
{
SpinLockGuard _(m_cpu_time_lock);
ASSERT(m_cpu_time_start_ns != UINT64_MAX);
m_cpu_time_ns += SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns;
m_cpu_time_start_ns = UINT64_MAX;
}
BAN::ErrorOr<Thread*> Thread::pthread_create(entry_t entry, void* arg)
{
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));