mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 17:53:37 +08:00
* rt/tst-cpuclock1.c: New file.
* rt/tst-cpuclock2.c: New file. * rt/tst-cputimer1.c: New file. * rt/tst-cputimer2.c: New file. * rt/tst-cputimer3.c: New file. * rt/Makefile (tests): Add them. * sysdeps/unix/sysv/linux/kernel-posix-cpu-timers.h: New file. * sysdeps/unix/sysv/linux/clock_getcpuclockid.c: New file. * sysdeps/unix/sysv/linux/ia64/clock_getcpuclockid.c (HAS_CPUCLOCK): New macro. (clock_getcpuclockid): Function removed. #include the new linux file to define it instead. * sysdeps/unix/clock_gettime.c [HP_TIMING_AVAIL] (hp_timing_gettime): New function, broken out of ... (clock_gettime) [HP_TIMING_AVAIL]: ... here. Call it. (realtime_gettime): New function, broken out of ... (clock_gettime) [! HANDLED_REALTIME]: ... here. Call it. (clock_gettime) [SYSDEP_GETTIME_CPU]: Use new macro in default case. * sysdeps/unix/sysv/linux/clock_gettime.c (SYSCALL_GETTIME): New macro. (SYSDEP_GETTIME_CPUTIME): New macro. (SYSDEP_GETTIME): Use both. [! __ASSUME_POSIX_TIMERS] (maybe_syscall_gettime): New function, broken out of ... (SYSDEP_GETTIME): ... here. Use it. [__NR_clock_gettime] (HANDLED_CPUTIME): Define it. (SYSDEP_GETTIME_CPUTIME): New macro. Handle CPU timers by trying kernel support and falling back to hp-timing code. * sysdeps/posix/clock_getres.c [HP_TIMING_AVAIL] (hp_timing_getres): New function, broken out of ... (clock_getres) [HP_TIMING_AVAIL]: ... here. Call it. (realtime_getres): New function, broken out of ... (clock_getres) [! HANDLED_REALTIME]: ... here. Call it. (clock_getres) [SYSDEP_GETRES_CPU]: Use new macro in default case. * sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES): New macro. (SYSDEP_GETRES_CPUTIME): New macro. (SYSDEP_GETRES): Use both. [! __ASSUME_POSIX_TIMERS] (maybe_syscall_getres): New function, broken out of ... (SYSDEP_GETRES): ... here. Use it. [__NR_clock_getres] (HANDLED_CPUTIME): Define it. (SYSDEP_GETRES_CPUTIME): New macro. Handle CPU timers by trying kernel support and falling back to hp-timing code. * sysdeps/unix/sysv/linux/clock_nanosleep.c: Handle CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially, translating to the kernel clockid_t for our own process/thread clock.
This commit is contained in:
parent
2f4f3bd4a9
commit
84060bad82
49
ChangeLog
49
ChangeLog
@ -1,3 +1,52 @@
|
||||
2005-04-27 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* rt/tst-cpuclock1.c: New file.
|
||||
* rt/tst-cpuclock2.c: New file.
|
||||
* rt/tst-cputimer1.c: New file.
|
||||
* rt/tst-cputimer2.c: New file.
|
||||
* rt/tst-cputimer3.c: New file.
|
||||
* rt/Makefile (tests): Add them.
|
||||
|
||||
* sysdeps/unix/sysv/linux/kernel-posix-cpu-timers.h: New file.
|
||||
* sysdeps/unix/sysv/linux/clock_getcpuclockid.c: New file.
|
||||
* sysdeps/unix/sysv/linux/ia64/clock_getcpuclockid.c
|
||||
(HAS_CPUCLOCK): New macro.
|
||||
(clock_getcpuclockid): Function removed.
|
||||
#include the new linux file to define it instead.
|
||||
* sysdeps/unix/clock_gettime.c [HP_TIMING_AVAIL] (hp_timing_gettime):
|
||||
New function, broken out of ...
|
||||
(clock_gettime) [HP_TIMING_AVAIL]: ... here. Call it.
|
||||
(realtime_gettime): New function, broken out of ...
|
||||
(clock_gettime) [! HANDLED_REALTIME]: ... here. Call it.
|
||||
(clock_gettime) [SYSDEP_GETTIME_CPU]: Use new macro in default case.
|
||||
* sysdeps/unix/sysv/linux/clock_gettime.c (SYSCALL_GETTIME): New macro.
|
||||
(SYSDEP_GETTIME_CPUTIME): New macro.
|
||||
(SYSDEP_GETTIME): Use both.
|
||||
[! __ASSUME_POSIX_TIMERS] (maybe_syscall_gettime): New function, broken
|
||||
out of ...
|
||||
(SYSDEP_GETTIME): ... here. Use it.
|
||||
[__NR_clock_gettime] (HANDLED_CPUTIME): Define it.
|
||||
(SYSDEP_GETTIME_CPUTIME): New macro. Handle CPU timers by trying
|
||||
kernel support and falling back to hp-timing code.
|
||||
* sysdeps/posix/clock_getres.c
|
||||
[HP_TIMING_AVAIL] (hp_timing_getres): New function, broken out of ...
|
||||
(clock_getres) [HP_TIMING_AVAIL]: ... here. Call it.
|
||||
(realtime_getres): New function, broken out of ...
|
||||
(clock_getres) [! HANDLED_REALTIME]: ... here. Call it.
|
||||
(clock_getres) [SYSDEP_GETRES_CPU]: Use new macro in default case.
|
||||
* sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES): New macro.
|
||||
(SYSDEP_GETRES_CPUTIME): New macro.
|
||||
(SYSDEP_GETRES): Use both.
|
||||
[! __ASSUME_POSIX_TIMERS] (maybe_syscall_getres): New function, broken
|
||||
out of ...
|
||||
(SYSDEP_GETRES): ... here. Use it.
|
||||
[__NR_clock_getres] (HANDLED_CPUTIME): Define it.
|
||||
(SYSDEP_GETRES_CPUTIME): New macro. Handle CPU timers by trying
|
||||
kernel support and falling back to hp-timing code.
|
||||
* sysdeps/unix/sysv/linux/clock_nanosleep.c: Handle
|
||||
CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially,
|
||||
translating to the kernel clockid_t for our own process/thread clock.
|
||||
|
||||
2005-04-27 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* stdlib/test-canon.c: Make doesExist a directory and add more tests
|
||||
|
@ -1,3 +1,8 @@
|
||||
2005-04-27 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* sysdeps/pthread/getcpuclockid.c (pthread_getcpuclockid)
|
||||
[__NR_clock_getres]: Use kernel-supplied CPU clocks if available.
|
||||
|
||||
2005-03-31 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Use
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
|
||||
/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version
|
||||
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
|
||||
@ -21,10 +22,76 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <internals.h>
|
||||
#include "kernel-features.h"
|
||||
#include "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 (pthread_t thread_id, clockid_t *clock_id)
|
||||
{
|
||||
#ifdef __NR_clock_getres
|
||||
pthread_handle handle = thread_handle(thread_id);
|
||||
int pid;
|
||||
|
||||
__pthread_lock (&handle->h_lock, NULL);
|
||||
if (nonexisting_handle (handle, thread_id))
|
||||
{
|
||||
__pthread_unlock (&handle->h_lock);
|
||||
return ESRCH;
|
||||
}
|
||||
pid = handle->h_descr->p_pid;
|
||||
__pthread_unlock (&handle->h_lock);
|
||||
|
||||
/* The clockid_t value is a simple computation from the PID.
|
||||
But we do a clock_getres call to validate it if we aren't
|
||||
yet sure we have the kernel support. */
|
||||
|
||||
const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, 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_cpu_posix_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
|
||||
{
|
||||
*clock_id = pidclock;
|
||||
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
|
||||
|
@ -1,3 +1,11 @@
|
||||
2005-04-27 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/timer_create.c (timer_create): Handle
|
||||
CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially,
|
||||
translating to the kernel clockid_t for our own process/thread clock.
|
||||
|
||||
* sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: New file.
|
||||
|
||||
2005-04-15 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* old_pthread_cond_init.c: Include <errno.h>.
|
||||
|
111
nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
Normal file
111
nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
Normal file
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -45,7 +45,9 @@ tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \
|
||||
tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \
|
||||
tst-aio7 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
|
||||
tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
|
||||
tst-timer3 tst-timer4 tst-timer5
|
||||
tst-timer3 tst-timer4 tst-timer5 \
|
||||
tst-cpuclock1 tst-cpuclock2 \
|
||||
tst-cputimer1 tst-cputimer2 tst-cputimer3
|
||||
|
||||
extra-libs := librt
|
||||
extra-libs-others := $(extra-libs)
|
||||
|
307
rt/tst-cpuclock1.c
Normal file
307
rt/tst-cpuclock1.c
Normal file
@ -0,0 +1,307 @@
|
||||
/* Test program for process CPU clocks.
|
||||
Copyright (C) 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; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* This function is intended to rack up both user and system time. */
|
||||
static void
|
||||
chew_cpu (void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
static volatile char buf[4096];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xaa;
|
||||
int nullfd = open ("/dev/null", O_WRONLY);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xbb;
|
||||
write (nullfd, (char *) buf, sizeof buf);
|
||||
close (nullfd);
|
||||
if (getppid () == 1)
|
||||
_exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
clockid_t cl;
|
||||
int e;
|
||||
pid_t dead_child, child;
|
||||
|
||||
/* Fork a child and let it die, to give us a PID known not be valid
|
||||
(assuming PIDs don't wrap around during the test). */
|
||||
{
|
||||
dead_child = fork ();
|
||||
if (dead_child == 0)
|
||||
_exit (0);
|
||||
if (dead_child < 0)
|
||||
{
|
||||
perror ("fork");
|
||||
return 1;
|
||||
}
|
||||
int x;
|
||||
if (wait (&x) != dead_child)
|
||||
{
|
||||
perror ("wait");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX says we should get ESRCH for this. */
|
||||
e = clock_getcpuclockid (dead_child, &cl);
|
||||
if (e != ENOSYS && e != ESRCH && e != EPERM)
|
||||
{
|
||||
printf ("clock_getcpuclockid on dead PID %d => %s\n",
|
||||
dead_child, strerror (e));
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Now give us a live child eating up CPU time. */
|
||||
child = fork ();
|
||||
if (child == 0)
|
||||
{
|
||||
chew_cpu ();
|
||||
_exit (1);
|
||||
}
|
||||
if (child < 0)
|
||||
{
|
||||
perror ("fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = clock_getcpuclockid (child, &cl);
|
||||
if (e == EPERM)
|
||||
{
|
||||
puts ("clock_getcpuclockid does not support other processes");
|
||||
goto done;
|
||||
}
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("clock_getcpuclockid on live PID %d => %s\n",
|
||||
child, strerror (e));
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
const clockid_t child_clock = cl;
|
||||
struct timespec res;
|
||||
if (clock_getres (child_clock, &res) < 0)
|
||||
{
|
||||
printf ("clock_getres on live PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
printf ("live PID %d clock %lx resolution %lu.%.9lu\n",
|
||||
child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec);
|
||||
|
||||
struct timespec before, after;
|
||||
if (clock_gettime (child_clock, &before) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
printf ("live PID %d before sleep => %lu.%.9lu\n",
|
||||
child, before.tv_sec, before.tv_nsec);
|
||||
|
||||
struct timespec sleeptime = { .tv_nsec = 500000000 };
|
||||
nanosleep (&sleeptime, NULL);
|
||||
|
||||
if (clock_gettime (child_clock, &after) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
printf ("live PID %d after sleep => %lu.%.9lu\n",
|
||||
child, after.tv_sec, after.tv_nsec);
|
||||
|
||||
struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec,
|
||||
.tv_nsec = after.tv_nsec - before.tv_nsec };
|
||||
if (diff.tv_nsec < 0)
|
||||
{
|
||||
--diff.tv_sec;
|
||||
diff.tv_nsec += 1000000000;
|
||||
}
|
||||
if (diff.tv_sec != 0
|
||||
|| diff.tv_nsec > 600000000
|
||||
|| diff.tv_nsec < 100000000)
|
||||
{
|
||||
printf ("before - after %lu.%.9lu outside reasonable range\n",
|
||||
diff.tv_sec, diff.tv_nsec);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
sleeptime.tv_nsec = 100000000;
|
||||
e = clock_nanosleep (child_clock, 0, &sleeptime, NULL);
|
||||
if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
|
||||
{
|
||||
printf ("clock_nanosleep not supported for other process clock: %s\n",
|
||||
strerror (e));
|
||||
}
|
||||
else if (e != 0)
|
||||
{
|
||||
printf ("clock_nanosleep on other process clock: %s\n", strerror (e));
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec afterns;
|
||||
if (clock_gettime (child_clock, &afterns) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec,
|
||||
.tv_nsec = afterns.tv_nsec - after.tv_nsec };
|
||||
if (d.tv_nsec < 0)
|
||||
{
|
||||
--d.tv_sec;
|
||||
d.tv_nsec += 1000000000;
|
||||
}
|
||||
if (d.tv_sec > 0
|
||||
|| d.tv_nsec < sleeptime.tv_nsec
|
||||
|| d.tv_nsec > sleeptime.tv_nsec * 2)
|
||||
{
|
||||
printf ("nanosleep time %lu.%.9lu outside reasonable range\n",
|
||||
d.tv_sec, d.tv_nsec);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kill (child, SIGKILL) != 0)
|
||||
{
|
||||
perror ("kill");
|
||||
result = 2;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Wait long enough to let the child finish dying. */
|
||||
|
||||
sleeptime.tv_nsec = 200000000;
|
||||
nanosleep (&sleeptime, NULL);
|
||||
|
||||
struct timespec dead;
|
||||
if (clock_gettime (child_clock, &dead) < 0)
|
||||
{
|
||||
printf ("clock_gettime on dead PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
printf ("dead PID %d => %lu.%.9lu\n",
|
||||
child, dead.tv_sec, dead.tv_nsec);
|
||||
|
||||
diff.tv_sec = dead.tv_sec - after.tv_sec;
|
||||
diff.tv_nsec = dead.tv_nsec - after.tv_nsec;
|
||||
if (diff.tv_nsec < 0)
|
||||
{
|
||||
--diff.tv_sec;
|
||||
diff.tv_nsec += 1000000000;
|
||||
}
|
||||
if (diff.tv_sec != 0 || diff.tv_nsec > 200000000)
|
||||
{
|
||||
printf ("dead - after %lu.%.9lu outside reasonable range\n",
|
||||
diff.tv_sec, diff.tv_nsec);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Now reap the child and verify that its clock is no longer valid. */
|
||||
{
|
||||
int x;
|
||||
if (waitpid (child, &x, 0) != child)
|
||||
{
|
||||
perror ("waitpid");
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (clock_gettime (child_clock, &dead) == 0)
|
||||
{
|
||||
printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n",
|
||||
child, (unsigned long int) child_clock,
|
||||
dead.tv_sec, dead.tv_nsec);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != EINVAL)
|
||||
result = 1;
|
||||
printf ("clock_gettime on reaped PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
}
|
||||
|
||||
if (clock_getres (child_clock, &dead) == 0)
|
||||
{
|
||||
printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n",
|
||||
child, (unsigned long int) child_clock,
|
||||
dead.tv_sec, dead.tv_nsec);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != EINVAL)
|
||||
result = 1;
|
||||
printf ("clock_getres on reaped PID %d clock %lx => %s\n",
|
||||
child, (unsigned long int) child_clock, strerror (errno));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
done:
|
||||
{
|
||||
if (kill (child, SIGKILL) != 0 && errno != ESRCH)
|
||||
{
|
||||
perror ("kill");
|
||||
return 2;
|
||||
}
|
||||
int x;
|
||||
if (waitpid (child, &x, 0) != child && errno != ECHILD)
|
||||
{
|
||||
perror ("waitpid");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#define TIMEOUT 5
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
332
rt/tst-cpuclock2.c
Normal file
332
rt/tst-cpuclock2.c
Normal file
@ -0,0 +1,332 @@
|
||||
/* Test program for process and thread CPU clocks.
|
||||
Copyright (C) 2005 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; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#if (_POSIX_THREADS - 0) <= 0
|
||||
|
||||
# define TEST_FUNCTION 0
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_barrier_t barrier;
|
||||
|
||||
/* This function is intended to rack up both user and system time. */
|
||||
static void *
|
||||
chew_cpu (void *arg)
|
||||
{
|
||||
pthread_barrier_wait (&barrier);
|
||||
|
||||
while (1)
|
||||
{
|
||||
static volatile char buf[4096];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xaa;
|
||||
int nullfd = open ("/dev/null", O_WRONLY);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xbb;
|
||||
write (nullfd, (char *) buf, sizeof buf);
|
||||
close (nullfd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned long long int
|
||||
tsdiff (const struct timespec *before, const struct timespec *after)
|
||||
{
|
||||
struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
|
||||
.tv_nsec = after->tv_nsec - before->tv_nsec };
|
||||
while (diff.tv_nsec < 0)
|
||||
{
|
||||
--diff.tv_sec;
|
||||
diff.tv_nsec += 1000000000;
|
||||
}
|
||||
return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
|
||||
}
|
||||
|
||||
static unsigned long long int
|
||||
test_nanosleep (clockid_t clock, const char *which,
|
||||
const struct timespec *before, int *bad)
|
||||
{
|
||||
const struct timespec sleeptime = { .tv_nsec = 100000000 };
|
||||
int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
|
||||
if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
|
||||
{
|
||||
printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
|
||||
which, strerror (e));
|
||||
return 0;
|
||||
}
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
|
||||
*bad = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct timespec after;
|
||||
if (clock_gettime (clock, &after) < 0)
|
||||
{
|
||||
printf ("clock_gettime on %s CPU clock %lx => %s\n",
|
||||
which, (unsigned long int) clock, strerror (errno));
|
||||
*bad = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long int diff = tsdiff (before, &after);
|
||||
if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
|
||||
{
|
||||
printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
|
||||
which, diff);
|
||||
*bad = 1;
|
||||
return diff;
|
||||
}
|
||||
|
||||
struct timespec sleeptimeabs = sleeptime;
|
||||
sleeptimeabs.tv_sec += after.tv_sec;
|
||||
sleeptimeabs.tv_nsec += after.tv_nsec;
|
||||
while (sleeptimeabs.tv_nsec > 1000000000)
|
||||
{
|
||||
++sleeptimeabs.tv_sec;
|
||||
sleeptimeabs.tv_nsec -= 1000000000;
|
||||
}
|
||||
e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
|
||||
which, strerror (e));
|
||||
*bad = 1;
|
||||
return diff;
|
||||
}
|
||||
|
||||
struct timespec afterabs;
|
||||
if (clock_gettime (clock, &afterabs) < 0)
|
||||
{
|
||||
printf ("clock_gettime on %s CPU clock %lx => %s\n",
|
||||
which, (unsigned long int) clock, strerror (errno));
|
||||
*bad = 1;
|
||||
return diff;
|
||||
}
|
||||
|
||||
unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
|
||||
if (sleepdiff > sleeptime.tv_nsec)
|
||||
{
|
||||
printf ("\
|
||||
absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
|
||||
which, sleepdiff);
|
||||
*bad = 1;
|
||||
}
|
||||
|
||||
unsigned long long int diffabs = tsdiff (&after, &afterabs);
|
||||
if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
|
||||
{
|
||||
printf ("\
|
||||
absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
|
||||
which, diffabs);
|
||||
*bad = 1;
|
||||
}
|
||||
|
||||
return diff + diffabs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
clockid_t process_clock, th_clock, my_thread_clock;
|
||||
int e;
|
||||
pthread_t th;
|
||||
|
||||
e = clock_getcpuclockid (0, &process_clock);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("clock_getcpuclockid on self => %s\n", strerror (e));
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is a kludge. This test fails if the semantics of thread and
|
||||
process clocks are wrong. The old code using hp-timing without kernel
|
||||
support has bogus semantics if there are context switches. We don't
|
||||
fail to report failure when the proper functionality is not available
|
||||
in the kernel. It so happens that Linux kernels without correct CPU
|
||||
clock support also lack CPU timer support, so we use use that to guess
|
||||
that we are using the bogus code and not test it. */
|
||||
timer_t t;
|
||||
if (timer_create (my_thread_clock, NULL, &t) != 0)
|
||||
{
|
||||
printf ("timer_create: %m\n");
|
||||
puts ("No support for CPU clocks with good semantics, skipping test");
|
||||
return 0;
|
||||
}
|
||||
timer_delete (t);
|
||||
|
||||
|
||||
pthread_barrier_init (&barrier, NULL, 2);
|
||||
|
||||
e = pthread_create (&th, NULL, chew_cpu, NULL);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("pthread_create: %s\n", strerror (e));
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = pthread_getcpuclockid (th, &th_clock);
|
||||
if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
|
||||
{
|
||||
puts ("pthread_getcpuclockid does not support other threads");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pthread_barrier_wait (&barrier);
|
||||
|
||||
struct timespec res;
|
||||
if (clock_getres (th_clock, &res) < 0)
|
||||
{
|
||||
printf ("clock_getres on thread clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
result = 1;
|
||||
return 1;
|
||||
}
|
||||
printf ("live thread clock %lx resolution %lu.%.9lu\n",
|
||||
(unsigned long int) th_clock, res.tv_sec, res.tv_nsec);
|
||||
|
||||
struct timespec process_before, process_after;
|
||||
if (clock_gettime (process_clock, &process_before) < 0)
|
||||
{
|
||||
printf ("clock_gettime on process clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct timespec before, after;
|
||||
if (clock_gettime (th_clock, &before) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live thread clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
printf ("live thread before sleep => %lu.%.9lu\n",
|
||||
before.tv_sec, before.tv_nsec);
|
||||
|
||||
struct timespec me_before, me_after;
|
||||
if (clock_gettime (my_thread_clock, &me_before) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live thread clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
printf ("self thread before sleep => %lu.%.9lu\n",
|
||||
me_before.tv_sec, me_before.tv_nsec);
|
||||
|
||||
struct timespec sleeptime = { .tv_nsec = 500000000 };
|
||||
nanosleep (&sleeptime, NULL);
|
||||
|
||||
if (clock_gettime (th_clock, &after) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live thread clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
printf ("live thread after sleep => %lu.%.9lu\n",
|
||||
after.tv_sec, after.tv_nsec);
|
||||
|
||||
if (clock_gettime (process_clock, &process_after) < 0)
|
||||
{
|
||||
printf ("clock_gettime on process clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (clock_gettime (my_thread_clock, &me_after) < 0)
|
||||
{
|
||||
printf ("clock_gettime on live thread clock %lx => %s\n",
|
||||
(unsigned long int) th_clock, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
printf ("self thread after sleep => %lu.%.9lu\n",
|
||||
me_after.tv_sec, me_after.tv_nsec);
|
||||
|
||||
unsigned long long int th_diff = tsdiff (&before, &after);
|
||||
unsigned long long int pdiff = tsdiff (&process_before, &process_after);
|
||||
unsigned long long int my_diff = tsdiff (&me_before, &me_after);
|
||||
|
||||
if (th_diff < 100000000 || th_diff > 600000000)
|
||||
{
|
||||
printf ("thread before - after %llu outside reasonable range\n",
|
||||
th_diff);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (my_diff > 100000000)
|
||||
{
|
||||
printf ("self thread before - after %llu outside reasonable range\n",
|
||||
my_diff);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (pdiff < th_diff)
|
||||
{
|
||||
printf ("process before - after %llu outside reasonable range (%llu)\n",
|
||||
pdiff, th_diff);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
process_after.tv_nsec += test_nanosleep (th_clock, "thread",
|
||||
&after, &result);
|
||||
process_after.tv_nsec += test_nanosleep (process_clock, "process",
|
||||
&process_after, &result);
|
||||
test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
|
||||
"PROCESS_CPUTIME_ID", &process_after, &result);
|
||||
|
||||
pthread_cancel (th);
|
||||
|
||||
e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
|
||||
if (e != EINVAL)
|
||||
{
|
||||
printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
|
||||
strerror (e));
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
# define TIMEOUT 8
|
||||
# define TEST_FUNCTION do_test ()
|
||||
#endif
|
||||
|
||||
#include "../test-skeleton.c"
|
68
rt/tst-cputimer1.c
Normal file
68
rt/tst-cputimer1.c
Normal file
@ -0,0 +1,68 @@
|
||||
/* Tests for POSIX timer implementation using process CPU clock. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#if _POSIX_THREADS && defined _POSIX_CPUTIME
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID
|
||||
#define TEST_CLOCK_MISSING(clock) \
|
||||
(setup_test () ? "process CPU clock timer support" : NULL)
|
||||
|
||||
/* This function is intended to rack up both user and system time. */
|
||||
static void *
|
||||
chew_cpu (void *arg)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
static volatile char buf[4096];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xaa;
|
||||
int nullfd = open ("/dev/null", O_WRONLY);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xbb;
|
||||
write (nullfd, (char *) buf, sizeof buf);
|
||||
close (nullfd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_test (void)
|
||||
{
|
||||
/* Test timers on our own process CPU clock by having a worker thread
|
||||
eating CPU. First make sure we can make such timers at all. */
|
||||
|
||||
timer_t t;
|
||||
if (timer_create (TEST_CLOCK, NULL, &t) != 0)
|
||||
{
|
||||
printf ("timer_create: %m\n");
|
||||
return 1;
|
||||
}
|
||||
timer_delete (t);
|
||||
|
||||
pthread_t th;
|
||||
int e = pthread_create (&th, NULL, chew_cpu, NULL);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("pthread_create: %s\n", strerror (e));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
# define TEST_CLOCK_MISSING(clock) "process clocks"
|
||||
#endif
|
||||
|
||||
#include "tst-timer4.c"
|
83
rt/tst-cputimer2.c
Normal file
83
rt/tst-cputimer2.c
Normal file
@ -0,0 +1,83 @@
|
||||
/* Tests for POSIX timer implementation using thread CPU clock. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#if _POSIX_THREADS && defined _POSIX_CPUTIME
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static clockid_t worker_thread_clock;
|
||||
|
||||
#define TEST_CLOCK worker_thread_clock
|
||||
#define TEST_CLOCK_MISSING(clock) \
|
||||
(setup_test () ? "thread CPU clock timer support" : NULL)
|
||||
|
||||
/* This function is intended to rack up both user and system time. */
|
||||
static void *
|
||||
chew_cpu (void *arg)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
static volatile char buf[4096];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xaa;
|
||||
int nullfd = open ("/dev/null", O_WRONLY);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xbb;
|
||||
write (nullfd, (char *) buf, sizeof buf);
|
||||
close (nullfd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_test (void)
|
||||
{
|
||||
/* Test timers on a thread CPU clock by having a worker thread eating
|
||||
CPU. First make sure we can make such timers at all. */
|
||||
|
||||
pthread_t th;
|
||||
int e = pthread_create (&th, NULL, chew_cpu, NULL);
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("pthread_create: %s\n", strerror (e));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
e = pthread_getcpuclockid (th, &worker_thread_clock);
|
||||
if (e == EPERM || e == ENOENT || e == ENOTSUP)
|
||||
{
|
||||
puts ("pthread_getcpuclockid does not support other threads");
|
||||
return 1;
|
||||
}
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("pthread_getcpuclockid: %s\n", strerror (e));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
timer_t t;
|
||||
if (timer_create (TEST_CLOCK, NULL, &t) != 0)
|
||||
{
|
||||
printf ("timer_create: %m\n");
|
||||
return 1;
|
||||
}
|
||||
timer_delete (t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
# define TEST_CLOCK_MISSING(clock) "process clocks"
|
||||
#endif
|
||||
|
||||
#include "tst-timer4.c"
|
130
rt/tst-cputimer3.c
Normal file
130
rt/tst-cputimer3.c
Normal file
@ -0,0 +1,130 @@
|
||||
/* Tests for POSIX timer implementation using another process's CPU clock. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#if _POSIX_THREADS && defined _POSIX_CPUTIME
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static clockid_t child_clock;
|
||||
|
||||
#define TEST_CLOCK child_clock
|
||||
#define TEST_CLOCK_MISSING(clock) \
|
||||
(setup_test () ? "other-process CPU clock timer support" : NULL)
|
||||
|
||||
/* This function is intended to rack up both user and system time. */
|
||||
static void
|
||||
chew_cpu (void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
static volatile char buf[4096];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xaa;
|
||||
int nullfd = open ("/dev/null", O_WRONLY);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
for (size_t j = 0; j < sizeof buf; ++j)
|
||||
buf[j] = 0xbb;
|
||||
write (nullfd, (char *) buf, sizeof buf);
|
||||
close (nullfd);
|
||||
if (getppid () == 1)
|
||||
_exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
static pid_t child;
|
||||
static void
|
||||
cleanup_child (void)
|
||||
{
|
||||
if (child <= 0)
|
||||
return;
|
||||
if (kill (child, SIGKILL) < 0 && errno != ESRCH)
|
||||
printf ("cannot kill child %d: %m\n", child);
|
||||
else
|
||||
{
|
||||
int status;
|
||||
errno = 0;
|
||||
if (waitpid (child, &status, 0) != child)
|
||||
printf ("waitpid %d: %m\n", child);
|
||||
}
|
||||
}
|
||||
#define CLEANUP_HANDLER cleanup_child ()
|
||||
|
||||
static int
|
||||
setup_test (void)
|
||||
{
|
||||
/* Test timers on a process CPU clock by having a child process eating
|
||||
CPU. First make sure we can make such timers at all. */
|
||||
|
||||
int pipefd[2];
|
||||
if (pipe (pipefd) < 0)
|
||||
{
|
||||
printf ("pipe: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
child = fork ();
|
||||
|
||||
if (child == 0)
|
||||
{
|
||||
char c;
|
||||
close (pipefd[1]);
|
||||
if (read (pipefd[0], &c, 1) == 1)
|
||||
chew_cpu ();
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
if (child < 0)
|
||||
{
|
||||
printf ("fork: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
atexit (&cleanup_child);
|
||||
|
||||
close (pipefd[0]);
|
||||
|
||||
int e = clock_getcpuclockid (child, &child_clock);
|
||||
if (e == EPERM)
|
||||
{
|
||||
puts ("clock_getcpuclockid does not support other processes");
|
||||
return 1;
|
||||
}
|
||||
if (e != 0)
|
||||
{
|
||||
printf ("clock_getcpuclockid: %s\n", strerror (e));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
timer_t t;
|
||||
if (timer_create (TEST_CLOCK, NULL, &t) != 0)
|
||||
{
|
||||
printf ("timer_create: %m\n");
|
||||
return 1;
|
||||
}
|
||||
timer_delete (t);
|
||||
|
||||
/* Get the child started chewing. */
|
||||
if (write (pipefd[1], "x", 1) != 1)
|
||||
{
|
||||
printf ("write to pipe: %m\n");
|
||||
return 1;
|
||||
}
|
||||
close (pipefd[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
# define TEST_CLOCK_MISSING(clock) "process clocks"
|
||||
#endif
|
||||
|
||||
#include "tst-timer4.c"
|
Loading…
Reference in New Issue
Block a user