about summary refs log tree commit diff
path: root/nptl/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c111
-rw-r--r--nptl/sysdeps/unix/sysv/linux/timer_create.c13
2 files changed, 121 insertions, 3 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
new file mode 100644
index 0000000000..088b3392bc
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
@@ -0,0 +1,111 @@
+/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t.  Linux version
+   Copyright (C) 2000,2001,2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+#include <sys/time.h>
+#include <tls.h>
+#include "kernel-features.h"
+#include "kernel-posix-cpu-timers.h"
+
+
+#if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+int __libc_missing_posix_cpu_timers attribute_hidden;
+#endif
+#if !(__ASSUME_POSIX_TIMERS > 0)
+int __libc_missing_posix_timers attribute_hidden;
+#endif
+
+int
+pthread_getcpuclockid (threadid, clockid)
+     pthread_t threadid;
+     clockid_t *clockid;
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+#ifdef __NR_clock_getres
+  /* The clockid_t value is a simple computation from the TID.
+     But we do a clock_getres call to validate it if we aren't
+     yet sure we have the kernel support.  */
+
+  const clockid_t tidclock = MAKE_THREAD_CPUCLOCK (pd->tid, CPUCLOCK_SCHED);
+
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+#  if !(__ASSUME_POSIX_TIMERS > 0)
+  if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers)
+    __libc_missing_posix_cpu_timers = 1;
+#  endif
+  if (!__libc_missing_posix_cpu_timers)
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      int r = INTERNAL_SYSCALL (clock_getres, err, 2, tidclock, NULL);
+      if (!INTERNAL_SYSCALL_ERROR_P (r, err))
+# endif
+	{
+	  *clockid = tidclock;
+	  return 0;
+	}
+
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+#  if !(__ASSUME_POSIX_TIMERS > 0)
+      if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS)
+	{
+	  /* The kernel doesn't support these calls at all.  */
+	  __libc_missing_posix_timers = 1;
+	  __libc_missing_posix_cpu_timers = 1;
+	}
+      else
+#  endif
+	if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL)
+	  {
+	    /* The kernel doesn't support these clocks at all.  */
+	    __libc_missing_posix_cpu_timers = 1;
+	  }
+      else
+	return INTERNAL_SYSCALL_ERRNO (r, err);
+    }
+# endif
+#endif
+
+#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
+     problematic if the thread ID is too large.  But 29 bits should be
+     fine.
+
+     If some day more clock IDs are needed the ID part can be
+     enlarged.  The IDs are entirely internal.  */
+  if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE))
+    return ERANGE;
+
+  /* Store the number.  */
+  *clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE);
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/timer_create.c b/nptl/sysdeps/unix/sysv/linux/timer_create.c
index ca6ff6c7ef..5e99513950 100644
--- a/nptl/sysdeps/unix/sysv/linux/timer_create.c
+++ b/nptl/sysdeps/unix/sysv/linux/timer_create.c
@@ -28,6 +28,7 @@
 #include <internaltypes.h>
 #include <nptl/pthreadP.h>
 #include "kernel-posix-timers.h"
+#include "kernel-posix-cpu-timers.h"
 
 
 #ifdef __NR_timer_create
@@ -58,6 +59,12 @@ timer_create (clock_id, evp, timerid)
   if  (__no_posix_timers >= 0)
 # endif
     {
+      clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
+				   ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
+				   : clock_id == CLOCK_THREAD_CPUTIME_ID
+				   ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
+				   : clock_id);
+
       /* If the user wants notification via a thread we need to handle
 	 this special.  */
       if (evp == NULL
@@ -88,7 +95,7 @@ timer_create (clock_id, evp, timerid)
 	    }
 
 	  kernel_timer_t ktimerid;
-	  int retval = INLINE_SYSCALL (timer_create, 3, clock_id, evp,
+	  int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
 				       &ktimerid);
 
 # ifndef __ASSUME_POSIX_TIMERS
@@ -196,8 +203,8 @@ timer_create (clock_id, evp, timerid)
 	      /* Create the timer.  */
 	      INTERNAL_SYSCALL_DECL (err);
 	      int res;
-	      res = INTERNAL_SYSCALL (timer_create, err, 3, clock_id, &sev,
-				      &newp->ktimerid);
+	      res = INTERNAL_SYSCALL (timer_create, err, 3,
+				      syscall_clockid, &sev, &newp->ktimerid);
 	      if (! INTERNAL_SYSCALL_ERROR_P (res, err))
 		{
 		  *timerid = (timer_t) newp;