lkml.org 
[lkml]   [2004]   [Nov]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subjectposix timer test program / glibc patch to make glibc posix compliant
    Recently patches went into the Linux kernel to correctly implement the
    posix clocks CLOCK_THREAD_CPUTIME_ID and CLOCK_PROCESS_CPUTIME_ID as well
    as the ability to determine the process and thread clocks of other
    processes. The following program is able to exercise the posix
    timer subsystem in various ways and also able to check for posix
    compliance by detecting system libraries that violate the posix
    specification by providing real time instead of cpu time (such as glibc).

    Three appendixes follow:
    1. A description of the clocktest program and how to use it.
    2. the source code of the program
    3. A glibc patch to fix these issues and provide access to the Linux
    thread and process clocks.

    Feedback appreciated.

    -----------------------------------------------------------------------------
    clocktest - A test program for posix clock interfaces

    clocktest is a test program for clock access via the POSIX clock and timer
    interface as defined in the POSIX standard and the Single Unix Specification
    (on the web http://www.unix.org). clocktest allows to perform the following
    tests on a Unix system:

    - Discovery of available clocks
    - Display of current clock values and clock precision
    - Test if process clocks are supported
    - Verification of process clock operation
    - Test if thread clocks are supported
    - Verification of thread clock operation
    - Test timed generation of periodic and single shot signals
    - Access to arbitrary nonstandard clocks (such as CLOCK_SGI_CYCLE)
    - Test may be run directly through the kernel system call interface
    or via function calls through the system library
    - Verification of POSIX compliant behavior of system library for
    CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID (a known
    glibc deficiency)

    Usage
    -----

    clocktest <option1> <option2> ... <test>

    Available tests are

    --scan Perform a scan for available clocks. Test availability of process
    and thread clocks. Verify POSIX compliant behavior of CLOCK_*_CPUTIME_ID
    clocks if glibc interface is in use.

    --timer Perform a periodic timer test. By default the test is run on
    CLOCK_REALTIME with a period of 1234567ns and a count of 5 signals

    --show Show clock value and precision

    --clock-status Clock status summary for standard clocks (also default if no
    test specified)

    --process-clocks Tests the ability to retrieve process and thread clocks of
    other processes

    --single-thread Verify thread/process clock operation in a single process

    --multi-thread Verify thread/process clock operations using threads

    Available options are:

    --kernel Use kernel interface for clock tests [default]
    --glibc Use glibc library for clock tests
    --clock=N Use the named or numbered clock for the test
    --interval=N Use the specified interval for the timer test
    --count=N Specify the number of interations for a periodic timer test.
    Specify count=1 for single shot mode
    --busywait Busywait instead of giving up the time slice. This increases
    the reaction time of the process receiving the signal.


    Typical uses:

    clocktest Show default clocks and their resolutions

    clocktest --clock=SGI_CYCLE --timer
    Test intervals generated by SGI SHub RTC interrupts

    clocktest --glibc --scan
    Detect glibc limitations

    clocktest --kernel --scan
    Show kernel time capabilities


    ----------------------------------------------------------------------

    /*********************************************************************
    Program to exercise the posix time subsystem of Linux

    Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved

    Christoph Lameter <christoph@lameter.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    ********************************************************************/

    #define POSIX_SOURCE 1
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <time.h>
    #include <errno.h>
    #include <asm/unistd.h>
    #include <pthread.h>
    #include <strings.h>
    #include <sys/time.h>
    #include <getopt.h>

    #define VERSION "0.2"

    /* Default program options */
    int verbose = 0;
    int clockid = CLOCK_REALTIME;
    int interval = 1234567;
    int count = 5;
    int use_glibc = 0;
    int busywait = 0;

    #define PID_MAX_LIMIT (sizeof(long) > 4 ? 4*1024*1024 : 0x8000)

    /* We need to be able to redirect these calls to bypass glibc since
    * there are old version of glibc around that do not support all these calls.
    */

    int t_clock_getres(int clk_id, struct timespec *res) {
    if (use_glibc)
    return clock_getres(clk_id,res);
    else
    return syscall(__NR_clock_getres, clk_id, res);
    }

    int t_clock_gettime(int clk_id, struct timespec *tp) {
    if (use_glibc)
    return clock_gettime(clk_id, tp);
    else
    return syscall(__NR_clock_gettime, clk_id, tp);
    }

    int t_clock_settime(int clk_id, struct timespec *tp) {
    if (use_glibc)
    return clock_settime(clk_id, tp);
    else
    return syscall(__NR_clock_settime, clk_id, tp);
    }

    int t_clock_getcpuclockid(int pid, int *clock) {
    if (use_glibc)
    return clock_getcpuclockid(pid,clock);

    *clock = ((pid == 0) ? CLOCK_PROCESS_CPUTIME_ID : -pid);
    return 0;
    }

    int t_timer_create(int clockid, struct sigevent *evp,
    timer_t *t) {

    if (use_glibc)
    return timer_create(clockid, evp, t);
    else
    return syscall(__NR_timer_create, clockid, evp, t);
    }

    int t_timer_gettime(timer_t t,struct itimerspec *value) {
    if (use_glibc)
    return timer_gettime(t,value);
    else
    return syscall(__NR_clock_gettime, t, value);
    }

    int t_timer_settime(timer_t t,int flags,
    const struct itimerspec *value, struct itimerspec *ovalue) {
    if (use_glibc)
    return timer_settime(t, flags, value, ovalue);
    else
    return syscall(__NR_timer_settime, t, flags, value, ovalue);
    }

    int t_timer_delete(timer_t t) {
    if (use_glibc)
    return timer_delete(t);
    else
    return syscall(__NR_timer_delete, t);
    }

    int t_timer_getoverrun(timer_t t) {
    if (use_glibc)
    return timer_getoverrun(t);
    else
    return syscall(__NR_timer_getoverrun, t);
    }

    char *clockstr [] = {
    /* 0-3 Standard POSIX Clocks */
    "REALTIME","MONOTONIC","PROCESS_CPUTIME_ID","THREAD_CPUTIME_ID",
    /* 4-5 Unused clocks mentioned in linux 2.6.9 source code */
    "REALTIME_HR","MONOTONIC_HR",
    /* 6-9 spacer */
    "6","7","8","9",
    /* 10- Driver specific clocks */
    "SGI_CYCLE",
    NULL
    };

    int clockstr_to_id(char *s) {
    char **p;

    if (isdigit(*s)) return atoi(s);
    if (strncmp(s,"CLOCK_",6) ==0) s+=6;

    for(p= clockstr;*p;*p++) if (strcasecmp(s,*p)==0) return p-clockstr;
    return -1;
    }

    char *clockid_to_str(int n) {
    static char buffer[40];

    if (n<0) {
    n = -n;
    if (n < (8 << 20))
    sprintf(buffer, "CLOCK_PROCESS(%d)", n);
    else {
    n -= (8 << 20);
    sprintf(buffer, "CLOCK_THREAD(%d)", n);
    }
    } else
    if (n < sizeof(clockstr) / sizeof(char *))
    sprintf(buffer, "CLOCK_%s", clockstr[n]);
    else
    sprintf(buffer, "CLOCK(%d)", n);
    out:
    return buffer;
    }

    unsigned long long time_diff(const struct timespec *t1, const struct timespec *t2) {
    return t2->tv_nsec - t1->tv_nsec + (t2->tv_sec - t1->tv_sec) * 1000000000LL;
    }

    void pr(int clock)
    {
    struct timespec tv = {1,2};
    struct timespec res = {3,4};
    int rc;

    rc=t_clock_getres(clock,&res);
    if (rc) {
    printf("getres return code on %s=%d errno=%d\n",clockid_to_str(clock),rc,errno);
    }
    rc=t_clock_gettime(clock,&tv);
    if (rc) {
    printf("gettime return code on %s=%d errno=%d\n",clockid_to_str(clock),rc, errno);
    }
    else
    printf("%25s=% 11ld.%09ld resolution=% 2ld.%09ld\n",clockid_to_str(clock),tv.tv_sec,tv.tv_nsec,res.tv_sec,res.tv_nsec);
    }

    void fourclocks(void) {
    int i;

    for(i=0; i<4; i++) pr(i);
    }


    int y;

    void kx(long long x) {
    y=x;
    };

    void single_thread(void) {
    int i;

    /* Waste some time */
    printf("\nSingle Thread Testing\n--------------------\n");
    fourclocks();
    printf("10,000,000 divisions ...\n");
    for(i=1;i<10000000;i++) kx(1000000000000LL/i);
    fourclocks();
    }

    struct timespec zero;

    pthread_t thread[10];

    struct tinfo {
    int i;
    struct timespec ttime,ptime;
    } tinf[10];

    void *thread_function(void *x) {
    struct tinfo *t=x;
    int i;

    for(i=1;i< t->i;i++) kx(1000000000000LL/i);
    t_clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t->ttime);
    t_clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t->ptime);
    return NULL;
    }

    void multi_thread(void) {
    int i;
    int initpclock;
    int selftclock;

    /* Waste some more time in threads */
    printf("\nMulti Thread Testing\n----------------------\n");
    fourclocks();
    printf("Starting Thread:");
    for(i=0;i<10;i++) {
    tinf[i].i=i*1000000;
    if (pthread_create(&thread[i], NULL, thread_function, tinf+i))
    perror("thread");
    else
    printf(" %d",i);
    }
    printf("\n Joining Thread:");
    for(i=0;i<10;i++)
    if (pthread_join( thread[i], NULL))
    perror("join");
    else
    printf(" %d",i);
    printf("\n");
    for(i=0;i<10;i++) {
    printf("%d Cycles=%7d Thread=% 3ld.%09ldns Process=% 3ld.%09ldns\n",i,tinf[i].i,tinf[i].ttime.tv_sec,tinf[i].ttime.tv_nsec,tinf[i].ptime.tv_sec,tinf[i].ptime.tv_nsec);
    }
    if (t_clock_getcpuclockid(1,&initpclock))
    printf("clock_getcpuclockid failed\n");
    if (pthread_getcpuclockid(pthread_self(),&selftclock))
    printf("pthread_getcpuclockid failed\n");
    pr(initpclock);
    pr(selftclock);
    printf("process clock of init (1) = %d. My own threadclock =%d\n",initpclock,selftclock);
    fourclocks();
    }

    static volatile sig_atomic_t timer_tick = 0;
    #define MAX_STEPS 1000

    struct timespec ev[MAX_STEPS];
    int overruns[MAX_STEPS];
    int soverruns[MAX_STEPS];

    int g_nsteps;
    timer_t timer_id;

    void sigalarm(int signo, siginfo_t *si, void *x)
    {
    soverruns[timer_tick] = si->si_overrun;
    overruns[timer_tick] = t_timer_getoverrun(timer_id);
    t_clock_gettime(CLOCK_REALTIME,ev + timer_tick++ );

    if (timer_tick == g_nsteps) {
    struct itimerspec ts;

    /* Disarm timer */
    ts.it_interval = zero;
    ts.it_value = zero;
    t_timer_settime(timer_id, 0, &ts, NULL);
    }
    printf(".");
    // fflush(stdout);
    }


    int timer_test(int clockid, int nanosec, int nsteps) {
    struct itimerspec ts;
    struct sigevent se;
    struct sigaction act;
    struct timespec time0,time1;
    int i;
    int signum = SIGRTMAX;
    int status;

    if (nsteps > MAX_STEPS) {
    printf("Maximum number of steps is %d\n",MAX_STEPS);
    exit(1);
    }

    g_nsteps = nsteps;

    timer_tick = 0;
    /* Set up signal handler: */
    sigfillset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_sigaction = sigalarm;
    sigaction(signum, &act, NULL);

    /* Set up timer: */
    memset(&se, 0, sizeof(se));
    se.sigev_notify = SIGEV_SIGNAL;
    se.sigev_signo = signum;
    se.sigev_value.sival_int = 0;
    status = t_timer_create(clockid, &se, &timer_id);
    if (status < 0) {
    perror("timer_create");
    return -1;
    }
    /* Start timer: */
    ts.it_interval.tv_sec = nanosec / 1000000000;
    ts.it_interval.tv_nsec = (nanosec % 1000000000);
    ts.it_value = ts.it_interval;
    /* Tick */
    t_clock_gettime(CLOCK_REALTIME,&time0);
    printf("Receiving signals: ");
    // fflush(stdout);
    status = t_timer_settime(timer_id, 0, &ts, NULL);
    if (status < 0) {
    perror("timer_settime");
    t_timer_delete(timer_id);
    return -1;
    }

    /* Loop: */
    if (busywait) {
    while (timer_tick < nsteps) ;
    } else {
    while (timer_tick < nsteps)
    sched_yield();
    }
    /* Tock */
    ts.it_interval = zero;
    ts.it_value = zero;
    t_timer_settime(timer_id, 0, &ts, NULL);
    t_clock_gettime(CLOCK_REALTIME, &time1);
    // printf("\nOverruns: %d\n", t_timer_getoverrun(timer_id));
    t_timer_delete(timer_id);
    printf("\nTotal time=%luns\n", time1.tv_nsec - time0.tv_nsec + (time1.tv_sec - time0.tv_sec)*1000000000LL);

    printf("Events (%d in an interval of %dns)\n",nsteps, nanosec);
    for(i=0; i < nsteps; i++) {
    long ns = ev[i].tv_nsec - time0.tv_nsec + (ev[i].tv_sec - time0.tv_sec)*1000000000LL;
    printf("Signal #%d received in %luns. Overruns=%d/%d Target was=%ld Diff=%d\n",i+1,ns,overruns[i],soverruns[i],(i+1)*interval,ns-(i+1)*interval);
    }

    return 0;
    }

    void standard_timer_test(void) {
    printf("\nTest %s signal scheduling:\n"
    "----------------------------------------------\n",clockid_to_str(clockid));
    timer_test(clockid,interval,count);
    }

    void other_processes_clocks_test(void) {
    int i;

    printf("\nTest other processes clocks:\n------------------------------\n");
    for(i=1 ; i< 100; i+=10) {
    printf("Process %d:\n",i);
    pr(-i);
    pr(-i - PID_MAX_LIMIT);
    }
    printf("\n");
    }

    void clock_scan(void) {
    int i;
    int n = 0;
    struct timespec t;
    int status;

    printf("Scan for available clocks:\n");
    printf("--------------------------\n");

    if (use_glibc) {
    /* Test for broken posix behavior */
    struct timespec t;

    printf("Using glibc function calls for posix time\n");
    if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t)==0) {
    struct timespec t2;

    sleep(1);
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t2);
    if (time_diff(&t,&t2) >100000000LL)
    printf("\nPOSIX violation: real time returns instead of cpu time for CLOCK_*_CPUTIME_ID!\n\n");
    }
    }

    if ((status = t_clock_gettime(-1, &t)) == 0)
    printf("Process clocks available.\n");
    else if (verbose)
    printf("Process Clock Error = %d %d\n", status, errno);
    if ((status = t_clock_gettime(-PID_MAX_LIMIT -1, &t)) == 0)
    printf("Thread clocks available.\n");
    else if (verbose)
    printf("Thread Clock Error = %d %d\n", status, errno);

    printf("\n");
    for(i=0; i < 100; i++) {
    status = t_clock_gettime(i, &t);

    if (verbose && status)
    printf("Status for %s = %d %d\n", clockid_to_str(i), status, errno);

    if (!status) {
    printf("%s\n",clockid_to_str(i));
    n++;
    }
    }
    printf("\n%d clocks found.\n",n);

    }

    int test_single_thread, test_multi_thread, test_other_process_clocks, test_timer,
    test_clock_status, do_scan, showclock;

    static struct option ct_options[] = {
    { "single-thread", 0, &test_single_thread, 1 },
    { "multi-thread", 0, &test_multi_thread, 1 },
    { "process-clocks", 0, &test_other_process_clocks, 1 },
    { "timer", 0, &test_timer, 1 },
    { "clock-status", 0, &test_clock_status, 1 },
    { "scan", 0, &do_scan, 1 },
    { "show", 0, NULL, 's' },
    { "glibc", 0, NULL, 'g' },
    { "kernel", 0, NULL, 'k' },
    { "clock", 1, NULL, 'c' },
    { "interval", 1, NULL, 'i' },
    { "count", 1, NULL, 'n' },
    { "verbose", 0, NULL, 'v' },
    { "help", 0, NULL, 'h' },
    { "version", 0, NULL, 'V' },
    { "busywait", 0, NULL, 'b' },
    { 0, 0, NULL, 0}
    };

    void usage(char *cmd) {
    printf("clocktest comes with ABSOLUTELY NO WARRANTY. This is free software which may\n"
    "be redistributed under the terms of the GNU General Public License. See the\n"
    "sourcecode for details. Written by Christoph Lameter <christoph@lameter.com>\n\n"
    );
    printf("Copyright (C) 2004 Silicon Graphics Inc (http://www.sgi.com).\n\n");

    printf("usage: %s [OPTIONS]... \n", cmd);

    printf( "-h, --help\t\tdisplay this help and exit\n"
    "-V, --version\t\toutput version information and exit\n"
    "--single-thread\t\ttest process/thread clocks for single thread\n"
    "--multi-thread\t\ttest process/thread clocks for multi threads\n"
    "--process-clocks\ttest process clocks for other processes\n"
    "--timer\t\t\tdo a posix interval timer test\n"
    "--scan\t\t\tscan for available clocks\n"
    "--clock-status\t\tdisplay clock status (default)\n"
    "-s,--show\t\tShow single clock status\n"
    "-c,--clock=N\t\tUse specified clockid instead of CLOCK_REALTIME\n"
    "-g,--glibc\t\tUse glibc functions for testing\n"
    "-k,--kernel\t\tUse system calls bypassing glibc (default)\n"
    "-i,--interval=ns\tUse the specified interval instead of 1234567ns\n"
    "-n,--count=N\t\tRepeat timer signal N times instead of 5 times\n"
    "-b,--busywait\t\tUse a busy loop for waiting instead of suspending the process\n"
    );
    }

    int main(int argc, char *argv[])
    {
    char c;

    while ((c=getopt_long(argc, argv, "bkgvsVhc:i:n:", ct_options, 0)) != -1) switch (c) {
    case 0 : break;

    case 'b' : busywait = 1;
    break;

    case 'c' : clockid = clockstr_to_id(optarg);
    if (clockid <0) {
    fprintf(stderr,"Unknown clock:%s\n",optarg);
    exit(2);
    }
    break;

    case 'i' : interval = atoi(optarg);
    break;

    case 'n' : count = atoi(optarg);
    break;

    case 'v' : verbose++;
    break;

    case 'g' : use_glibc = 1;
    break;

    case 'k' : use_glibc = 0;
    break;

    case 's' :
    showclock = 1;
    break;
    case 'V' :
    printf("clock_test version " VERSION "Christoph Lameter\n");
    exit(0);

    case 'h' :
    usage(argv[0]);
    exit(0);

    default:
    fprintf(stderr, "Unknown command %c\n",c);
    usage(argv[0]);
    exit(1);
    }

    if (showclock) pr(clockid); else
    if (do_scan) clock_scan(); else
    if (test_single_thread) single_thread(); else
    if (test_multi_thread) multi_thread(); else
    if (test_other_process_clocks) other_processes_clocks_test(); else
    if (test_timer) standard_timer_test(); else
    {
    struct timespec tv;

    gettimeofday((struct timeval *)&tv, NULL);
    tv.tv_nsec = tv.tv_nsec*1000;
    printf("Current values of POSIX clocks:"
    "\n-------------------------------\n");
    fourclocks();

    printf(" Gettimeofday() =% 11ld.%09ld\n",tv.tv_sec,tv.tv_nsec);
    }
    return 0;
    }
    ------------------------------------------------------------------------

    Index: libc/nptl/sysdeps/pthread/pthread_getcpuclockid.c
    ===================================================================
    --- libc.orig/nptl/sysdeps/pthread/pthread_getcpuclockid.c 2004-10-26 10:34:39.130349968 -0700
    +++ libc/nptl/sysdeps/pthread/pthread_getcpuclockid.c 2004-11-18 16:15:47.959666831 -0800
    @@ -20,7 +20,7 @@
    #include <pthreadP.h>
    #include <sys/time.h>
    #include <tls.h>
    -
    +#include <linux/threads.h>

    int
    pthread_getcpuclockid (threadid, clockid)
    @@ -35,19 +35,8 @@
    return ESRCH;

    #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);
    + *clockid = - (pd->tid + PID_MAX_LIMIT);

    return 0;
    #else
    Index: libc/sysdeps/unix/sysv/linux/clock_getres.c
    ===================================================================
    --- libc.orig/sysdeps/unix/sysv/linux/clock_getres.c 2004-10-26 10:34:42.523834080 -0700
    +++ libc/sysdeps/unix/sysv/linux/clock_getres.c 2004-11-18 16:15:47.973665948 -0800
    @@ -20,24 +20,17 @@

    #include "kernel-features.h"

    -
    #ifdef __ASSUME_POSIX_TIMERS
    -/* This means the REALTIME and MONOTONIC clock are definitely
    - supported in the kernel. */
    -# define SYSDEP_GETRES \
    - case CLOCK_REALTIME: \
    - case CLOCK_MONOTONIC: \
    - retval = INLINE_SYSCALL (clock_getres, 2, clock_id, res); \
    - break
    +/* we have to rely on the kernel */
    +#define SYSDEP_DEFAULT_GETRES retval = INLINE_SYSCALL(clock_getres, err, 2, clock_id, res)
    +
    #elif defined __NR_clock_getres
    /* Is the syscall known to exist? */
    extern int __libc_missing_posix_timers attribute_hidden;

    /* The REALTIME and MONOTONIC clock might be available. Try the
    syscall first. */
    -# define SYSDEP_GETRES \
    - case CLOCK_REALTIME: \
    - case CLOCK_MONOTONIC: \
    +# define SYSDEP_DEFAULT_GETRES \
    { \
    int e = EINVAL; \
    \
    @@ -65,7 +58,7 @@
    else \
    __set_errno (e); \
    } \
    - break
    +
    #endif

    #ifdef __NR_clock_getres
    Index: libc/sysdeps/unix/clock_gettime.c
    ===================================================================
    --- libc.orig/sysdeps/unix/clock_gettime.c 2004-10-26 10:34:41.423001432 -0700
    +++ libc/sysdeps/unix/clock_gettime.c 2004-11-18 16:15:48.010663617 -0800
    @@ -23,21 +23,6 @@
    #include <libc-internal.h>
    #include <ldsodefs.h>

    -
    -#if HP_TIMING_AVAIL
    -/* Clock frequency of the processor. We make it a 64-bit variable
    - because some jokers are already playing with processors with more
    - than 4GHz. */
    -static hp_timing_t freq;
    -
    -
    -/* This function is defined in the thread library. */
    -extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
    - struct timespec *tp)
    - __attribute__ ((__weak__));
    -#endif
    -
    -
    /* Get current value of CLOCK and store it in TP. */
    int
    clock_gettime (clockid_t clock_id, struct timespec *tp)
    @@ -66,58 +51,14 @@
    #endif

    default:
    -#if HP_TIMING_AVAIL
    - if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
    - != CLOCK_THREAD_CPUTIME_ID)
    -#endif
    +#ifdef SYSDEP_DEFAULT_GETTIME
    + SYSDEP_DEFAULT_GETTIME;
    +#else
    {
    __set_errno (EINVAL);
    break;
    }
    -
    -#if HP_TIMING_AVAIL
    - /* FALLTHROUGH. */
    - case CLOCK_PROCESS_CPUTIME_ID:
    - {
    - hp_timing_t tsc;
    -
    - if (__builtin_expect (freq == 0, 0))
    - {
    - /* This can only happen if we haven't initialized the `freq'
    - variable yet. Do this now. We don't have to protect this
    - code against multiple execution since all of them should
    - lead to the same result. */
    - freq = __get_clockfreq ();
    - if (__builtin_expect (freq == 0, 0))
    - /* Something went wrong. */
    - break;
    - }
    -
    - if (clock_id != CLOCK_PROCESS_CPUTIME_ID
    - && __pthread_clock_gettime != NULL)
    - {
    - retval = __pthread_clock_gettime (clock_id, freq, tp);
    - break;
    - }
    -
    - /* Get the current counter. */
    - HP_TIMING_NOW (tsc);
    -
    - /* Compute the offset since the start time of the process. */
    - tsc -= GL(dl_cpuclock_offset);
    -
    - /* Compute the seconds. */
    - tp->tv_sec = tsc / freq;
    -
    - /* And the nanoseconds. This computation should be stable until
    - we get machines with about 16GHz frequency. */
    - tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
    -
    - retval = 0;
    - }
    - break;
    #endif
    }
    -
    return retval;
    }
    Index: libc/sysdeps/unix/sysv/linux/ia64/clock_getcpuclockid.c
    ===================================================================
    --- libc.orig/sysdeps/unix/sysv/linux/ia64/clock_getcpuclockid.c 2004-10-26 10:33:48.627027640 -0700
    +++ /dev/null1970-01-01 00:00:00.000000000 +0000
    @@ -1,47 +0,0 @@
    -/* Copyright (C) 2000, 2001, 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; if not, write to the Free
    - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    - 02111-1307 USA. */
    -
    -#include <errno.h>
    -#include <time.h>
    -#include <unistd.h>
    -#include <sys/stat.h>
    -#include <sys/types.h>
    -#include <fcntl.h>
    -
    -
    -#include "has_cpuclock.c"
    -
    -
    -int
    -clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
    -{
    - /* We don't allow any process ID but our own. */
    - if (pid != 0 && pid != getpid ())
    - return EPERM;
    -
    - int retval = ENOENT;
    -
    - if (has_cpuclock () > 0)
    - {
    - /* Store the number. */
    - *clock_id = CLOCK_PROCESS_CPUTIME_ID;
    - retval = 0;
    - }
    -
    - return retval;
    -}
    Index: libc/sysdeps/unix/sysv/linux/clock_settime.c
    ===================================================================
    --- libc.orig/sysdeps/unix/sysv/linux/clock_settime.c 2004-10-26 10:34:42.556829064 -0700
    +++ libc/sysdeps/unix/sysv/linux/clock_settime.c 2004-11-18 16:15:48.067660025 -0800
    @@ -20,21 +20,15 @@

    #include "kernel-features.h"

    -
    #ifdef __ASSUME_POSIX_TIMERS
    -/* This means the REALTIME clock is definitely supported in the
    - kernel. */
    -# define SYSDEP_SETTIME \
    - case CLOCK_REALTIME: \
    - retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp); \
    - break
    +#define SYSDEP_DEFAULT_SETTIME retval = INLINE_SYSCALL(clock_settime, 2, clock_id, tp)
    +
    #elif defined __NR_clock_settime
    /* Is the syscall known to exist? */
    extern int __libc_missing_posix_timers attribute_hidden;

    /* The REALTIME clock might be available. Try the syscall first. */
    -# define SYSDEP_SETTIME \
    - case CLOCK_REALTIME: \
    +# define SYSDEP_DEFAULT_SETTIME \
    { \
    int e = EINVAL; \
    \
    @@ -64,8 +58,7 @@
    __set_errno (e); \
    retval = -1; \
    } \
    - } \
    - break
    + }
    #endif

    #ifdef __NR_clock_settime
    Index: libc/sysdeps/unix/sysv/linux/clock_getcpuclockid.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ libc/sysdeps/unix/sysv/linux/clock_getcpuclockid.c 2004-11-18 16:15:48.069659899 -0800
    @@ -0,0 +1,46 @@
    +
    +/* Copyright (C) 2000, 2001 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 <errno.h>
    +#include <time.h>
    +#include <unistd.h>
    +#include <kernel-features.h>
    +
    +int
    +clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
    +{
    + if (pid != 0 && pid != getpid ())
    +#ifdef __ASSUME_POSIX_TIMERS
    + *clock_id = -pid;
    + return 0;
    +#else
    +/* We don't allow any process ID but our own. */
    + return EPERM;
    +#endif
    +
    +#ifdef CLOCK_PROCESS_CPUTIME_ID
    + /* Store the number. */
    + *clock_id = CLOCK_PROCESS_CPUTIME_ID;
    +
    + return 0;
    +#else
    + /* We don't have a timer for that. */
    + return ENOENT;
    +#endif
    +}
    Index: libc/sysdeps/posix/clock_getres.c
    ===================================================================
    --- libc.orig/sysdeps/posix/clock_getres.c 2004-10-26 10:34:40.703110872 -0700
    +++ libc/sysdeps/posix/clock_getres.c 2004-11-18 16:15:48.088658702 -0800
    @@ -23,13 +23,6 @@
    #include <sys/param.h>
    #include <libc-internal.h>

    -
    -#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME
    -/* Clock frequency of the processor. */
    -static long int nsec;
    -#endif
    -
    -
    /* Get resolution of clock. */
    int
    clock_getres (clockid_t clock_id, struct timespec *res)
    @@ -65,44 +58,15 @@
    #endif /* handled REALTIME */

    default:
    -#if HP_TIMING_AVAIL
    - if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
    - != CLOCK_THREAD_CPUTIME_ID)
    -#endif
    - {
    +#ifdef SYSDEP_DEFAULT_GETRES
    + SYSDEP_DEFAULT_GETRES;
    +#else
    + {
    __set_errno (EINVAL);
    break;
    }
    -
    -#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME
    - /* FALLTHROUGH. */
    - case CLOCK_PROCESS_CPUTIME_ID:
    - {
    - if (__builtin_expect (nsec == 0, 0))
    - {
    - hp_timing_t freq;
    -
    - /* This can only happen if we haven't initialized the `freq'
    - variable yet. Do this now. We don't have to protect this
    - code against multiple execution since all of them should
    - lead to the same result. */
    - freq = __get_clockfreq ();
    - if (__builtin_expect (freq == 0, 0))
    - /* Something went wrong. */
    - break;
    -
    - nsec = MAX (UINT64_C (1000000000) / freq, 1);
    - }
    -
    - /* File in the values. The seconds are always zero (unless we
    - have a 1Hz machine). */
    - res->tv_sec = 0;
    - res->tv_nsec = nsec;
    -
    - retval = 0;
    - }
    - break;
    #endif
    +
    }

    return retval;
    Index: libc/sysdeps/unix/clock_settime.c
    ===================================================================
    --- libc.orig/sysdeps/unix/clock_settime.c 2004-10-26 10:34:41.468994440 -0700
    +++ libc/sysdeps/unix/clock_settime.c 2004-11-18 16:15:48.090658575 -0800
    @@ -22,20 +22,6 @@
    #include <libc-internal.h>
    #include <ldsodefs.h>

    -
    -#if HP_TIMING_AVAIL
    -/* Clock frequency of the processor. We make it a 64-bit variable
    - because some jokers are already playing with processors with more
    - than 4GHz. */
    -static hp_timing_t freq;
    -
    -
    -/* This function is defined in the thread library. */
    -extern void __pthread_clock_settime (clockid_t clock_id, hp_timing_t offset)
    - __attribute__ ((__weak__));
    -#endif
    -
    -
    /* Set CLOCK to value TP. */
    int
    clock_settime (clockid_t clock_id, const struct timespec *tp)
    @@ -70,56 +56,16 @@
    #endif

    default:
    -#if HP_TIMING_AVAIL
    - if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
    - != CLOCK_THREAD_CPUTIME_ID)
    -#endif
    +#ifdef SYSDEP_DEFAULT_SETTIME
    + SYSDEP_DEFAULT_SETTIME;
    +#else
    {
    __set_errno (EINVAL);
    retval = -1;
    break;
    }

    -#if HP_TIMING_AVAIL
    - /* FALLTHROUGH. */
    - case CLOCK_PROCESS_CPUTIME_ID:
    - {
    - hp_timing_t tsc;
    - hp_timing_t usertime;
    -
    - /* First thing is to get the current time. */
    - HP_TIMING_NOW (tsc);
    -
    - if (__builtin_expect (freq == 0, 0))
    - {
    - /* This can only happen if we haven't initialized the `freq'
    - variable yet. Do this now. We don't have to protect this
    - code against multiple execution since all of them should
    - lead to the same result. */
    - freq = __get_clockfreq ();
    - if (__builtin_expect (freq == 0, 0))
    - {
    - /* Something went wrong. */
    - retval = -1;
    - break;
    - }
    - }
    -
    - /* Convert the user-provided time into CPU ticks. */
    - usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull;
    -
    - /* Determine the offset and use it as the new base value. */
    - if (clock_id == CLOCK_PROCESS_CPUTIME_ID
    - || __pthread_clock_settime == NULL)
    - GL(dl_cpuclock_offset) = tsc - usertime;
    - else
    - __pthread_clock_settime (clock_id, tsc - usertime);
    -
    - retval = 0;
    - }
    - break;
    #endif
    }
    -
    return retval;
    }
    Index: libc/sysdeps/unix/sysv/linux/kernel-features.h
    ===================================================================
    --- libc.orig/sysdeps/unix/sysv/linux/kernel-features.h 2004-10-26 10:34:42.632817512 -0700
    +++ libc/sysdeps/unix/sysv/linux/kernel-features.h 2004-11-18 16:15:48.105657630 -0800
    @@ -419,3 +419,11 @@
    #if __LINUX_KERNEL_VERSION >= 0x020609 && defined __alpha__
    #define __ASSUME_IEEE_RAISE_EXCEPTION 1
    #endif
    +
    +/* Starting with version 2.6.9, CLOCK_PROCESS/THREAD_CPUTIME_ID are supported
    + * with clock_gettime and also negative clockids to access other processes clocks
    + */
    +
    +#if __LINUX_KERNEL_VERSION >= 0x020609
    +#define __ASSUME_POSIX_IMPROVED 1
    +#endif
    Index: libc/linuxthreads/sysdeps/pthread/getcpuclockid.c
    ===================================================================
    --- libc.orig/linuxthreads/sysdeps/pthread/getcpuclockid.c 2004-10-26 10:34:38.569435240 -0700
    +++ libc/linuxthreads/sysdeps/pthread/getcpuclockid.c 2004-11-18 16:15:48.120656685 -0800
    @@ -21,25 +21,14 @@
    #include <sys/time.h>
    #include <time.h>
    #include <internals.h>
    +#include <linux/threads.h>

    int
    pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id)
    {
    #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 | (thread_id << CLOCK_IDFIELD_SIZE);
    + *clock_id = - (thread_id + PID_MAX_LIMIT);

    return 0;
    #else
    Index: libc/sysdeps/unix/sysv/linux/clock_gettime.c
    ===================================================================
    --- libc.orig/sysdeps/unix/sysv/linux/clock_gettime.c 2004-10-26 10:34:42.531832864 -0700
    +++ libc/sysdeps/unix/sysv/linux/clock_gettime.c 2004-11-18 16:15:48.123656496 -0800
    @@ -20,24 +20,16 @@

    #include "kernel-features.h"

    -
    #ifdef __ASSUME_POSIX_TIMERS
    -/* This means the REALTIME and MONOTONIC clock are definitely
    - supported in the kernel. */
    -# define SYSDEP_GETTIME \
    - case CLOCK_REALTIME: \
    - case CLOCK_MONOTONIC: \
    - retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \
    - break
    +#define SYSDEP_DEFAULT_GETTIME retval = INLINE_SYSCALL(clock_gettime, 2, clock_id, tp)
    +
    #elif defined __NR_clock_gettime
    /* Is the syscall known to exist? */
    int __libc_missing_posix_timers attribute_hidden;

    /* The REALTIME and MONOTONIC clock might be available. Try the
    syscall first. */
    -# define SYSDEP_GETTIME \
    - case CLOCK_REALTIME: \
    - case CLOCK_MONOTONIC: \
    +# define SYSDEP_DEFAULT_GETTIME \
    { \
    int e = EINVAL; \
    \
    @@ -64,8 +56,7 @@
    HANDLE_REALTIME; \
    else \
    __set_errno (e); \
    - } \
    - break
    + }
    #endif

    #ifdef __NR_clock_gettime
    @@ -74,3 +65,4 @@
    #endif

    #include <sysdeps/unix/clock_gettime.c>
    +
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 14:08    [W:0.082 / U:95.792 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site