Make clock API POSIX-compliant and implement clock IDs - #538
adamgreloch wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for process and thread CPU-time clocks, implementing POSIX-compliant APIs such as pthread_getcpuclockid, clock_getcpuclockid, and clock_getres, while expanding clock_gettime and clock_nanosleep capabilities. It also refactors internal priority and tick interval handling, and updates the times system call implementation. Feedback on these changes highlights critical safety and portability improvements: first, pthread_getcpuclockid should verify thread existence via the thread list to prevent segmentation faults on invalid thread IDs; second, clock_nanosleep must validate that the req timespec pointer is non-NULL before dereferencing; and third, the CPU clock macros in common/cpuclock.h should cast the clock ID to an unsigned type to avoid implementation-defined behavior during right-shift operations.
Unit Test Results13 884 tests +154 13 024 ✅ +153 1h 6m 27s ⏱️ + 9m 55s For more details on these failures, see this check. Results for commit ef2d465. ± Comparison against base commit 9bffcee. ♻️ This comment has been updated with latest results. |
c0e836d to
cea7694
Compare
| @@ -564,15 +564,29 @@ int nanosleep(const struct timespec *req, struct timespec *rem) | |||
| /* clock_nanosleep() shall return **positive** errors codes directly, without setting errno */ | |||
| int clock_nanosleep(clockid_t clock, int flags, const struct timespec *req, struct timespec *rem) | |||
There was a problem hiding this comment.
Function parameter names are different than in POSIX
There was a problem hiding this comment.
I see that there are multiple functions with argument naming deviating from POSIX spec. Will do this in a separate PR in one sweep.
| #include <sys/time.h> | ||
| #include <sys/types.h> | ||
| #include <sys/times.h> | ||
| #include <time.h> |
There was a problem hiding this comment.
Any reason not to sort these alphabetically?
Applies in other places too
There was a problem hiding this comment.
maybe let's do it for the whole libphoenix in one sweep in a separate PR
| us = __getSystickInterval(); | ||
| } | ||
| else if (clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_MONOTONIC_RAW) { | ||
| us = 1; |
There was a problem hiding this comment.
Well, the actual resolution for CLOCK_REALTIME depends on the per-platform hardware clock used by the kernel. Usually this is a typical 32,768 kHz calibrated built-in RTC, so the resolution would be ~30 us. This aligns with clock_settime() POSIX behavior, which truncates the actually set time to match the resolution (e.g. a write and read from HW RTC registers will yield a truncated value).
I think platform-dependent parameters should at least be defined by kernel per-arch headers. Maybe it should also be a part of sysctl-like mechanism to query/set the kernel tick frequency and other runtime parameters.
Or maybe this can't be done due to compatibility concerns?
(Of course we could enhance the realtime clock by complementing it with a high-resolution clock in short timeframes, but I'm almost positive this is only in a sphere of dreams, so your 1 us seems not to come from that.)
There was a problem hiding this comment.
True, but userspace doesn't need to know the real resolution. It must be the smallest increment by which the clock can change, so 1 us is fine for ~30 us clocks.
I agree that, long term, it would be nice to have this sorted out precisely, but from the POSIX perspective it's not required. I'd prefer to exploit this fact, since currently we don't have the API to pass the true resolution to the userspace.
| clock_t clock(void) | ||
| { | ||
| return (clock_t)-1; | ||
| time_t res = cpuclockGet(0, 0); |
There was a problem hiding this comment.
Is this value normalized so that it can be used with CLOCKS_PER_SEC? Note that the (legacy) functions clock() and times() operate on different clocks - clock() returns the number of ticks which must be divided by CLOCKS_PER_SEC to get the time and times() returns other, "virtual" number of ticks which must be divided by the value of sysconf(_SC_CLK_TCK). to get the time.
Why "virtual" and not real ticks? If we decide that system tick interval can be changed at runtime, then the output of times() would not be comparable with other invocations' output and, more importantly, sysconf(_SC_CLK_TCK) would need to be a dynamic variable. So, times() can be implemented in the same way as clock(), just with a (possibly) different "clocks per sec" constant.
Let's treat clock() and times() as legacy functions mainly used by ports, so that their behavior does not affect how we account time in the kernel.
There was a problem hiding this comment.
If you ask whether it is POSIX compliant, it is. Kernel provides microseconds, clock() is supposed to return a value sanely divisible by CLOCKS_PER_SEC which could very well be called MS_PER_SEC, since it is specified to be equal 1000000.
Let's treat clock() and times() as legacy functions mainly used by ports, so that their behavior does not affect how we account time in the kernel.
Agreed.
cea7694 to
9b8b952
Compare
nsleep is a native syscall, so it should operate on PH_CLOCK_* definitions. TASK: RTOS-1472
Breaking change: depends on newly added sys_cpuTime syscall and PH_CLK_TCK definition. TASK: RTOS-1472
TASK: RTOS-1472
TASK: RTOS-1472
9b8b952 to
ef2d465
Compare
TASK: RTOS-1472
Fixes: phoenix-rtos/phoenix-rtos-project#1685
Description
Motivation and Context
Types of changes
How Has This Been Tested?
Checklist:
Special treatment
!proc: track thread/process sys/user time, add sys_cpuclockGet and sys_times syscalls phoenix-rtos-kernel#847