Current uClibc-ng version incorrectly calculates clockid
in pthread_getcpuclockid (at least for modern kernels). The simplest test
program
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int main()
{
clockid_t clk;
struct timespec ts;
const int err = pthread_getcpuclockid(pthread_self(), &clk);
if (err != 0) {
errno = err;
perror("pthread_getcpuclockid");
return EXIT_FAILURE;
}
if (clock_gettime(clk, &ts) == -1) {
perror("clock_gettime");
return EXIT_FAILURE;
}
printf("Thread time is %lu.%06lu.\n",
ts.tv_sec,
ts.tv_nsec / 1000);
return EXIT_SUCCESS;
}
fails with
clock_gettime: Invalid argument
Tested on Linux 3.4 / MIPS built with GCC 5.4.0.
Other implementations, for example musl, use a simple calculation
https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_getcpuclockid.c
Looks strange, but the official glibc repository
https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=nptl/pthread_getcpuclockid.c;hb=HEAD
has the same implementation as in uClibc-ng.
This fork
https://github.com/lattera/glibc/blob/master/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
use more accurate approach relying on __NR_clock_getres (defined in the
kernel since 2.6.24) with MAKE_THREAD_CPUCLOCK macro copied from the kernel
(
http://lxr.free-electrons.com/source/include/linux/posix-timers.h?v=2.6.24#L34,
Linux
4.10 has the same one).
I propose an intermediate solution: use MAKE_THREAD_CPUCLOCK like
computation of clockid when __NR_clock_getres defined and do a fallback to
an older implementation when not.
From caebc4ced19c46725109d607c47a355d66da3097 Mon Sep 17 00:00:00 2001
From: Sergey Korolev <[email protected]>
Date: Tue, 25 Apr 2017 02:14:59 +0300
Subject: [PATCH] pthread_getcpuclockid.c: fix clockid calculation
According to newer linux kernel sources (since 2.6.24)
MAKE_THREAD_CPUCLOCK macro should be used to get clockid.
The fix use MAKE_THREAD_CPUCLOCK-like computation when
__NR_clock_getres defined and do a fallback to an older
implementation when not.
---
.../nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
index ca3570f..0fe6a35 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
@@ -20,6 +20,8 @@
#include <sys/time.h>
#include <tls.h>
+#define CPUCLOCK_PERTHREAD_MASK 4
+#define CPUCLOCK_SCHED 2
int
pthread_getcpuclockid (
@@ -33,7 +35,13 @@ pthread_getcpuclockid (
/* Not a valid thread handle. */
return ESRCH;
-#ifdef CLOCK_THREAD_CPUTIME_ID
+#ifdef __NR_clock_getres
+ *clockid = ((~(clockid_t) (pd->tid)) << CLOCK_IDFIELD_SIZE)
+ | CPUCLOCK_SCHED | CPUCLOCK_PERTHREAD_MASK;
+
+ return 0;
+#else
+# ifdef CLOCK_THREAD_CPUTIME_ID
/* We need to store the thread ID in the CLOCKID variable together
with a number identifying the clock. We reserve the low 3 bits
for the clock ID and the rest for the thread ID. This is
@@ -49,8 +57,9 @@ pthread_getcpuclockid (
*clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE);
return 0;
-#else
+# else
/* We don't have a timer for that. */
return ENOENT;
+# endif
#endif
}
--
2.7.4
_______________________________________________
devel mailing list
[email protected]
https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel