diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 3c509b6c..630790be 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -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 m_spinlock_count { 0 }; BAN::Atomic m_mutex_count { 0 }; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 6af4755f..ee144515 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2373,10 +2373,8 @@ namespace Kernel BAN::ErrorOr Process::sys_clock_gettime(clockid_t clock_id, timespec* tp) { - { - LockGuard _(m_process_lock); - TRY(validate_pointer_access(tp, sizeof(timespec), true)); - } + 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(cpu_time_ns / 1'000'000'000), + .tv_nsec = static_cast(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(cpu_time_ns / 1'000'000'000), + .tv_nsec = static_cast(cpu_time_ns % 1'000'000'000), + }; + break; + } default: dwarnln("TODO: clock_gettime({})", clock_id); return BAN::Error::from_errno(ENOTSUP); } + return 0; } diff --git a/kernel/kernel/Processor.cpp b/kernel/kernel/Processor.cpp index 3b8c64b7..5ed0171a 100644 --- a/kernel/kernel/Processor.cpp +++ b/kernel/kernel/Processor.cpp @@ -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); } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 7c8f4dcc..49b0e71b 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -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(); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 7d9bf7b1..edee0b22 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -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::pthread_create(entry_t entry, void* arg) { auto* thread = TRY(create_userspace(m_process, m_process->page_table()));