]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 8 Jul 2004 23:55:54 +0000 (23:55 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 8 Jul 2004 23:55:54 +0000 (23:55 +0000)
2004-07-07  Jakub Jelinek  <jakub@redhat.com>

* sysdeps/pthread/getcpuclockid.c (pthread_getcpuclockid): Allow
using other thread's clock.
* ptclock_gettime.c (__pthread_clock_gettime): Likewise.
* ptclock_settime.c (__pthread_clock_settime): Likewise.
* internals.h (__pthread_clock_gettime, __pthread_clock_settime):
Remove prototypes.
Reported by Bernd Schmidt <bernds@redhat.com>.
* Makefile (librt-tests): Add tst-clock1.
* tst-clock1.c: New test.

* sysdeps/x86_64/Versions: New file.
* sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file.
* sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file.

linuxthreads/ChangeLog
linuxthreads/Makefile
linuxthreads/internals.h
linuxthreads/ptclock_gettime.c
linuxthreads/ptclock_settime.c
linuxthreads/sysdeps/pthread/getcpuclockid.c
linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h [new file with mode: 0644]
linuxthreads/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h [new file with mode: 0644]
linuxthreads/sysdeps/x86_64/Versions [new file with mode: 0644]
linuxthreads/tst-clock1.c [new file with mode: 0644]

index 83f6a8182aa87c0c05501ee3990b18ad67f5212d..ca061a943fe0e08c45fdd5ef1bd6351c3d74a805 100644 (file)
@@ -1,3 +1,19 @@
+2004-07-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/getcpuclockid.c (pthread_getcpuclockid): Allow
+       using other thread's clock.
+       * ptclock_gettime.c (__pthread_clock_gettime): Likewise.
+       * ptclock_settime.c (__pthread_clock_settime): Likewise.
+       * internals.h (__pthread_clock_gettime, __pthread_clock_settime):
+       Remove prototypes.
+       Reported by Bernd Schmidt <bernds@redhat.com>.
+       * Makefile (librt-tests): Add tst-clock1.
+       * tst-clock1.c: New test.
+
+       * sysdeps/x86_64/Versions: New file.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file.
+
 2004-04-16  Andreas Schwab  <schwab@suse.de>
 
        * sysdeps/ia64/tls.h (INIT_SYSINFO): Cast dl_sysinfo to void*.
index 67a6380731dd4ea40ce75d7b34cd06b8a6b4d0a7..2d8a254c401ebaa2b3bce3ca5bcd4983bb75ad0b 100644 (file)
@@ -105,7 +105,7 @@ omit-deps += crti crtn
 CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time)
 endif
 
-librt-tests = ex10 ex11
+librt-tests = ex10 ex11 tst-clock1
 tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \
        tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
        ex17 ex18 tst-cancel tst-context bug-sleep \
index ba6f476b739b5c1cc98048c1efc42ef07308de3f..b35a430c6912169548268087f0ac03d2053604b2 100644 (file)
@@ -405,9 +405,6 @@ extern int __pthread_spin_unlock (pthread_spinlock_t *__lock);
 extern int __pthread_spin_init (pthread_spinlock_t *__lock, int __pshared);
 extern int __pthread_spin_destroy (pthread_spinlock_t *__lock);
 
-extern int __pthread_clock_gettime (hp_timing_t freq, struct timespec *tp);
-extern void __pthread_clock_settime (hp_timing_t offset);
-
 /* Global pointers to old or new suspend functions */
 
 extern void (*__pthread_restart)(pthread_descr);
index 8f17136e5ead1802d5ab68db74e9eede8d971e7a..755f83d10147da6575a38b8c34bb1a9d661b2538 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 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
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <errno.h>
 #include <time.h>
 #include <libc-internal.h>
 #include "internals.h"
+#include "spinlock.h"
 
 
 #if HP_TIMING_AVAIL
 int
-__pthread_clock_gettime (hp_timing_t freq, struct timespec *tp)
+__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
+                        struct timespec *tp)
 {
-  hp_timing_t tsc;
+  hp_timing_t tsc, cpuclock_offset;
   pthread_descr self = thread_self ();
+  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;
+
+  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
+    cpuclock_offset = THREAD_GETMEM (self, p_cpuclock_offset);
+  else
+    {
+      pthread_descr th;
+      pthread_handle handle = thread_handle (thread);
+      __pthread_lock (&handle->h_lock, NULL);
+      th = handle->h_descr;
+      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
+       {
+         __pthread_unlock (&handle->h_lock);
+         __set_errno (EINVAL);
+         return -1;
+       }
+      cpuclock_offset = th->p_cpuclock_offset;
+      __pthread_unlock (&handle->h_lock);
+   }
 
   /* Get the current counter.  */
   HP_TIMING_NOW (tsc);
 
   /* Compute the offset since the start time of the process.  */
-  tsc -= THREAD_GETMEM (self, p_cpuclock_offset);
+  tsc -= cpuclock_offset;
 
   /* Compute the seconds.  */
   tp->tv_sec = tsc / freq;
index e1604759322d23079661193f235ffb20dc8c8da8..a4f218c771787fb29ad15e5de707195e371d0f4b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 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
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <errno.h>
 #include <time.h>
 #include <libc-internal.h>
 #include "internals.h"
+#include "spinlock.h"
 
 
 #if HP_TIMING_AVAIL
-void
-__pthread_clock_settime (hp_timing_t offset)
+int
+__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset)
 {
   pthread_descr self = thread_self ();
+  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;
 
-  /* Compute the offset since the start time of the process.  */
-  THREAD_SETMEM (self, p_cpuclock_offset, offset);
+  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
+    /* Our own clock.  */
+    THREAD_SETMEM (self, p_cpuclock_offset, offset);
+  else
+    {
+      pthread_descr th;
+      pthread_handle handle = thread_handle (thread);
+      __pthread_lock (&handle->h_lock, NULL);
+      th = handle->h_descr;
+      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
+       {
+         __pthread_unlock (&handle->h_lock);
+         __set_errno (EINVAL);
+         return -1;
+       }
+      th->p_cpuclock_offset = offset;
+      __pthread_unlock (&handle->h_lock);
+   }
+
+  return 0;
 }
 #endif
index fff1cb03ec3a08820a03fba0a2c226810fd1928d..032caeb081f05b4138218ddce8aed6dfbf657496 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 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
 #include <errno.h>
 #include <pthread.h>
 #include <sys/time.h>
+#include <time.h>
 #include <internals.h>
 
 int
 pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id)
 {
-  /* We don't allow any process ID but our own.  */
-  if (thread_handle (thread_id)->h_descr != thread_self ())
-    return EPERM;
-
 #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 (2 * PTHREAD_THREADS_MAX
+      >= 1 << (8 * sizeof (*clock_id) - CLOCK_IDFIELD_SIZE))
+    return ERANGE;
+
   /* Store the number.  */
-  *clock_id = CLOCK_THREAD_CPUTIME_ID;
+  *clock_id = CLOCK_THREAD_CPUTIME_ID | (thread_id << CLOCK_IDFIELD_SIZE);
 
   return 0;
 #else
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h
new file mode 100644 (file)
index 0000000..07780df
--- /dev/null
@@ -0,0 +1,144 @@
+/* Define POSIX options for Linux/ia64.
+   Copyright (C) 1996-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.  */
+
+#ifndef        _POSIX_OPT_H
+#define        _POSIX_OPT_H    1
+
+/* Job control is supported.  */
+#define        _POSIX_JOB_CONTROL      1
+
+/* Processes have a saved set-user-ID and a saved set-group-ID.  */
+#define        _POSIX_SAVED_IDS        1
+
+/* Priority scheduling is supported.  */
+#define        _POSIX_PRIORITY_SCHEDULING      200112L
+
+/* Synchronizing file data is supported.  */
+#define        _POSIX_SYNCHRONIZED_IO  200112L
+
+/* The fsync function is present.  */
+#define        _POSIX_FSYNC    200112L
+
+/* Mapping of files to memory is supported.  */
+#define        _POSIX_MAPPED_FILES     200112L
+
+/* Locking of all memory is supported.  */
+#define        _POSIX_MEMLOCK  200112L
+
+/* Locking of ranges of memory is supported.  */
+#define        _POSIX_MEMLOCK_RANGE    200112L
+
+/* Setting of memory protections is supported.  */
+#define        _POSIX_MEMORY_PROTECTION        200112L
+
+/* Only root can change owner of file.  */
+#define        _POSIX_CHOWN_RESTRICTED 1
+
+/* `c_cc' member of 'struct termios' structure can be disabled by
+   using the value _POSIX_VDISABLE.  */
+#define        _POSIX_VDISABLE '\0'
+
+/* Filenames are not silently truncated.  */
+#define        _POSIX_NO_TRUNC 1
+
+/* X/Open realtime support is available.  */
+#define _XOPEN_REALTIME        1
+
+/* X/Open realtime thread support is available.  */
+#define _XOPEN_REALTIME_THREADS        1
+
+/* XPG4.2 shared memory is supported.  */
+#define        _XOPEN_SHM      1
+
+/* Tell we have POSIX threads.  */
+#define _POSIX_THREADS 200112L
+
+/* We have the reentrant functions described in POSIX.  */
+#define _POSIX_REENTRANT_FUNCTIONS      1
+#define _POSIX_THREAD_SAFE_FUNCTIONS   200112L
+
+/* We provide priority scheduling for threads.  */
+#define        _POSIX_THREAD_PRIORITY_SCHEDULING       200112L
+
+/* We support user-defined stack sizes.  */
+#define _POSIX_THREAD_ATTR_STACKSIZE   200112L
+
+/* We support user-defined stacks.  */
+#define _POSIX_THREAD_ATTR_STACKADDR   200112L
+
+/* We support POSIX.1b semaphores, but only the non-shared form for now.  */
+#define _POSIX_SEMAPHORES      200112L
+
+/* Real-time signals are supported.  */
+#define _POSIX_REALTIME_SIGNALS        200112L
+
+/* We support asynchronous I/O.  */
+#define _POSIX_ASYNCHRONOUS_IO 200112L
+#define _POSIX_ASYNC_IO                1
+/* Alternative name for Unix98.  */
+#define _LFS_ASYNCHRONOUS_IO   1
+
+/* The LFS support in asynchronous I/O is also available.  */
+#define _LFS64_ASYNCHRONOUS_IO 1
+
+/* The rest of the LFS is also available.  */
+#define _LFS_LARGEFILE         1
+#define _LFS64_LARGEFILE       1
+#define _LFS64_STDIO           1
+
+/* POSIX shared memory objects are implemented.  */
+#define _POSIX_SHARED_MEMORY_OBJECTS   200112L
+
+/* CPU-time clocks supported.  */
+#define _POSIX_CPUTIME 200112L
+
+/* We support the clock also in threads.  */
+#define _POSIX_THREAD_CPUTIME  200112L
+
+/* GNU libc provides regular expression handling.  */
+#define _POSIX_REGEXP  1
+
+/* Reader/Writer locks are available.  */
+#define _POSIX_READER_WRITER_LOCKS     200112L
+
+/* We have a POSIX shell.  */
+#define _POSIX_SHELL   1
+
+/* We support the Timeouts option.  */
+#define _POSIX_TIMEOUTS        200112L
+
+/* We support spinlocks.  */
+#define _POSIX_SPIN_LOCKS      200112L
+
+/* The `spawn' function family is supported.  */
+#define _POSIX_SPAWN   200112L
+
+/* We have POSIX timers.  */
+#define _POSIX_TIMERS  200112L
+
+/* The barrier functions are available.  */
+#define _POSIX_BARRIERS        200112L
+
+/* POSIX message queues are available.  */
+#define        _POSIX_MESSAGE_PASSING  200112L
+
+/* The monotonic clock might be available.  */
+#define _POSIX_MONOTONIC_CLOCK 0
+
+#endif /* posix_opt.h */
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h
new file mode 100644 (file)
index 0000000..3a5fc7a
--- /dev/null
@@ -0,0 +1,144 @@
+/* Define POSIX options for Linux/x86_64.
+   Copyright (C) 1996-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.  */
+
+#ifndef        _POSIX_OPT_H
+#define        _POSIX_OPT_H    1
+
+/* Job control is supported.  */
+#define        _POSIX_JOB_CONTROL      1
+
+/* Processes have a saved set-user-ID and a saved set-group-ID.  */
+#define        _POSIX_SAVED_IDS        1
+
+/* Priority scheduling is supported.  */
+#define        _POSIX_PRIORITY_SCHEDULING      200112L
+
+/* Synchronizing file data is supported.  */
+#define        _POSIX_SYNCHRONIZED_IO  200112L
+
+/* The fsync function is present.  */
+#define        _POSIX_FSYNC    200112L
+
+/* Mapping of files to memory is supported.  */
+#define        _POSIX_MAPPED_FILES     200112L
+
+/* Locking of all memory is supported.  */
+#define        _POSIX_MEMLOCK  200112L
+
+/* Locking of ranges of memory is supported.  */
+#define        _POSIX_MEMLOCK_RANGE    200112L
+
+/* Setting of memory protections is supported.  */
+#define        _POSIX_MEMORY_PROTECTION        200112L
+
+/* Only root can change owner of file.  */
+#define        _POSIX_CHOWN_RESTRICTED 1
+
+/* `c_cc' member of 'struct termios' structure can be disabled by
+   using the value _POSIX_VDISABLE.  */
+#define        _POSIX_VDISABLE '\0'
+
+/* Filenames are not silently truncated.  */
+#define        _POSIX_NO_TRUNC 1
+
+/* X/Open realtime support is available.  */
+#define _XOPEN_REALTIME        1
+
+/* X/Open realtime thread support is available.  */
+#define _XOPEN_REALTIME_THREADS        1
+
+/* XPG4.2 shared memory is supported.  */
+#define        _XOPEN_SHM      1
+
+/* Tell we have POSIX threads.  */
+#define _POSIX_THREADS 200112L
+
+/* We have the reentrant functions described in POSIX.  */
+#define _POSIX_REENTRANT_FUNCTIONS      1
+#define _POSIX_THREAD_SAFE_FUNCTIONS   200112L
+
+/* We provide priority scheduling for threads.  */
+#define        _POSIX_THREAD_PRIORITY_SCHEDULING       200112L
+
+/* We support user-defined stack sizes.  */
+#define _POSIX_THREAD_ATTR_STACKSIZE   200112L
+
+/* We support user-defined stacks.  */
+#define _POSIX_THREAD_ATTR_STACKADDR   200112L
+
+/* We support POSIX.1b semaphores, but only the non-shared form for now.  */
+#define _POSIX_SEMAPHORES      200112L
+
+/* Real-time signals are supported.  */
+#define _POSIX_REALTIME_SIGNALS        200112L
+
+/* We support asynchronous I/O.  */
+#define _POSIX_ASYNCHRONOUS_IO 200112L
+#define _POSIX_ASYNC_IO                1
+/* Alternative name for Unix98.  */
+#define _LFS_ASYNCHRONOUS_IO   1
+
+/* The LFS support in asynchronous I/O is also available.  */
+#define _LFS64_ASYNCHRONOUS_IO 1
+
+/* The rest of the LFS is also available.  */
+#define _LFS_LARGEFILE         1
+#define _LFS64_LARGEFILE       1
+#define _LFS64_STDIO           1
+
+/* POSIX shared memory objects are implemented.  */
+#define _POSIX_SHARED_MEMORY_OBJECTS   200112L
+
+/* CPU-time clocks supported.  */
+#define _POSIX_CPUTIME 200112L
+
+/* We support the clock also in threads.  */
+#define _POSIX_THREAD_CPUTIME  200112L
+
+/* GNU libc provides regular expression handling.  */
+#define _POSIX_REGEXP  1
+
+/* Reader/Writer locks are available.  */
+#define _POSIX_READER_WRITER_LOCKS     200112L
+
+/* We have a POSIX shell.  */
+#define _POSIX_SHELL   1
+
+/* We support the Timeouts option.  */
+#define _POSIX_TIMEOUTS        200112L
+
+/* We support spinlocks.  */
+#define _POSIX_SPIN_LOCKS      200112L
+
+/* The `spawn' function family is supported.  */
+#define _POSIX_SPAWN   200112L
+
+/* We have POSIX timers.  */
+#define _POSIX_TIMERS  200112L
+
+/* The barrier functions are available.  */
+#define _POSIX_BARRIERS        200112L
+
+/* POSIX message queues are available.  */
+#define        _POSIX_MESSAGE_PASSING  200112L
+
+/* The monotonic clock might be available.  */
+#define _POSIX_MONOTONIC_CLOCK 0
+
+#endif /* posix_opt.h */
diff --git a/linuxthreads/sysdeps/x86_64/Versions b/linuxthreads/sysdeps/x86_64/Versions
new file mode 100644 (file)
index 0000000..32da570
--- /dev/null
@@ -0,0 +1,5 @@
+libpthread {
+  GLIBC_PRIVATE {
+    __pthread_clock_gettime; __pthread_clock_settime;
+  }
+}
diff --git a/linuxthreads/tst-clock1.c b/linuxthreads/tst-clock1.c
new file mode 100644 (file)
index 0000000..54f5041
--- /dev/null
@@ -0,0 +1,194 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#if _POSIX_THREAD_CPUTIME
+static pthread_barrier_t b2;
+static pthread_barrier_t bN;
+
+
+static void *
+tf (void *arg)
+{
+  int e = pthread_barrier_wait (&b2);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&bN);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+#endif
+
+
+int
+do_test (void)
+{
+#if _POSIX_THREAD_CPUTIME
+# define N 10
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0
+      || pthread_barrier_init (&bN, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+  TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+  pthread_t th[N + 1];
+  clockid_t cl[N + 1];
+# ifndef CLOCK_THREAD_CPUTIME_ID
+  if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0)
+    {
+      puts ("own pthread_getcpuclockid failed");
+      return 1;
+    }
+# else
+  cl[0] = CLOCK_THREAD_CPUTIME_ID;
+# endif
+
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int i;
+  int e;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_create (&th[i], &at, tf, NULL) != 0)
+       {
+         puts ("create failed");
+         return 1;
+       }
+
+      e = pthread_barrier_wait (&b2);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait failed");
+         return 1;
+       }
+
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000;
+      TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+      if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0)
+       {
+         puts ("pthread_getcpuclockid failed");
+         return 1;
+       }
+    }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  struct timespec t[N + 1];
+  for (i = 0; i < N + 1; ++i)
+    if (clock_gettime (cl[i], &t[i]) != 0)
+      {
+       printf ("clock_gettime round %d failed\n", i);
+       return 1;
+      }
+
+  for (i = 0; i < N; ++i)
+    {
+      struct timespec diff;
+
+      diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec;
+      diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec;
+      if (diff.tv_nsec < 0)
+       {
+         diff.tv_nsec += 1000000000;
+         --diff.tv_sec;
+       }
+
+      if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000))
+       {
+         printf ("\
+difference between thread %d and %d too small (%ld.%09ld)\n",
+                 i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
+         return 1;
+       }
+
+      printf ("diff %d->%d: %ld.%09ld\n",
+             i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
+    }
+
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  for (i = 0; i < N + 1; ++i)
+    if (clock_settime (cl[i], &ts) != 0)
+      {
+       printf ("clock_settime(%d) round %d failed\n", cl[i], i);
+       return 1;
+      }
+
+  for (i = 0; i < N + 1; ++i)
+    {
+      if (clock_gettime (cl[i], &ts) != 0)
+       {
+         puts ("clock_gettime failed");
+         return 1;
+       }
+
+      if (ts.tv_sec > t[i].tv_sec
+         || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec))
+       {
+         puts ("clock_settime didn't reset clock");
+         return 1;
+       }
+    }
+#endif
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"