Index: linux/kernel/posix-timers.c =================================================================== --- linux.orig/kernel/posix-timers.c 2004-10-04 15:12:01.000000000 -0700 +++ linux/kernel/posix-timers.c 2004-10-09 07:57:29.000000000 -0700 @@ -7,6 +7,10 @@ * * Copyright (C) 2002 2003 by MontaVista Software. * + * 2004-07-27 Provide POSIX compliant clocks + * CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID. + * by Christoph Lameter + * * 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 @@ -129,18 +133,10 @@ * resolution. Here we define the standard CLOCK_REALTIME as a * 1/HZ resolution clock. * - * CPUTIME & THREAD_CPUTIME: We are not, at this time, definding these - * two clocks (and the other process related clocks (Std - * 1003.1d-1999). The way these should be supported, we think, - * is to use large negative numbers for the two clocks that are - * pinned to the executing process and to use -pid for clocks - * pinned to particular pids. Calls which supported these clock - * ids would split early in the function. - * * RESOLUTION: Clock resolution is used to round up timer and interval * times, NOT to report clock times, which are reported with as * much resolution as the system can muster. In some cases this - * resolution may depend on the underlaying clock hardware and + * resolution may depend on the underlying clock hardware and * may not be quantifiable until run time, and only then is the * necessary code is written. The standard says we should say * something about this issue in the documentation... @@ -158,7 +154,7 @@ * * At this time all functions EXCEPT clock_nanosleep can be * redirected by the CLOCKS structure. Clock_nanosleep is in - * there, but the code ignors it. + * there, but the code ignores it. * * Permissions: It is assumed that the clock_settime() function defined * for each clock will take care of permission checks. Some @@ -187,10 +183,23 @@ static u64 do_posix_clock_monotonic_gettime_parts( struct timespec *tp, struct timespec *mo); int do_posix_clock_monotonic_gettime(struct timespec *tp); -int do_posix_clock_monotonic_settime(struct timespec *tp); +static int do_posix_clock_monotonic_settime(struct timespec *tp); +static u64 do_posix_clock_monotonic_gettime_parts( + struct timespec *tp, struct timespec *mo); +static int do_posix_clock_process_gettime(struct timespec *tp); +static int do_posix_clock_process_settime(struct timespec *tp); +static int do_posix_clock_thread_gettime(struct timespec *tp); +static int do_posix_clock_thread_settime(struct timespec *tp); static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags); static inline void unlock_timer(struct k_itimer *timr, unsigned long flags); +static int do_posix_clock_notimer_create(int which_clock, + struct sigevent __user *time_event_spec, + timer_t __user *created_timer_id); +static int do_posix_clock_nonanosleep(int which_clock, int flags, struct timespec * t); + +static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags); + /* * Initialize everything, well, just everything in Posix clocks/timers ;) */ @@ -201,9 +210,23 @@ .clock_get = do_posix_clock_monotonic_gettime, .clock_set = do_posix_clock_monotonic_settime }; + struct k_clock clock_thread = {.res = CLOCK_REALTIME_RES, + .clock_get = do_posix_clock_thread_gettime, + .clock_set = do_posix_clock_thread_settime, + .timer_create = do_posix_clock_notimer_create, + .nsleep = do_posix_clock_nonanosleep + }; + struct k_clock clock_process = {.res = CLOCK_REALTIME_RES, + .clock_get = do_posix_clock_process_gettime, + .clock_set = do_posix_clock_process_settime, + .timer_create = do_posix_clock_notimer_create, + .nsleep = do_posix_clock_nonanosleep + }; register_posix_clock(CLOCK_REALTIME, &clock_realtime); register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); + register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &clock_process); + register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &clock_thread); posix_timers_cache = kmem_cache_create("posix_timers_cache", sizeof (struct k_itimer), 0, 0, 0, 0); @@ -434,6 +457,10 @@ !posix_clocks[which_clock].res) return -EINVAL; + if (posix_clocks[which_clock].timer_create) + return posix_clocks[which_clock].timer_create(which_clock, + timer_event_spec, created_timer_id); + new_timer = alloc_posix_timer(); if (unlikely(!new_timer)) return -EAGAIN; @@ -1064,11 +1091,87 @@ return 0; } -int do_posix_clock_monotonic_settime(struct timespec *tp) +static int do_posix_clock_monotonic_settime(struct timespec *tp) { return -EINVAL; } +int do_posix_clock_notimer_create(int which_clock, + struct sigevent __user *timer_event_spec, + timer_t __user *created_timer_id) { + return -EINVAL; +} + +int do_posix_clock_nonanosleep(int which_lock, int flags,struct timespec * t) { +/* Single Unix specficiation says to return ENOTSUP but we do not have that */ + return -EINVAL; +} + +/* + * Single Unix Specification V3: + * + * Implementations shall also support the special clockid_t value + * CLOCK_THREAD_CPUTIME_ID, which represents the CPU-time clock of the calling + * thread when invoking one of the clock_*() or timer_*() functions. For these + * clock IDs, the values returned by clock_gettime() and specified by + * clock_settime() shall represent the amount of execution time of the thread + * associated with the clock. + */ +static int do_posix_clock_thread_gettime(struct timespec *tp) +{ + jiffies_to_timespec(current->utime + current->stime + + current->thread_clock_offset, tp); + return 0; +} + +static int do_posix_clock_thread_settime(struct timespec *tp) +{ + current->thread_clock_offset = timespec_to_jiffies(tp) + - current->utime - current->stime; + return 0; +} + +/* + * Single Unix Specification V3: + * + * Implementations shall also support the special clockid_t value + * CLOCK_PROCESS_CPUTIME_ID, which represents the CPU-time clock of the + * calling process when invoking one of the clock_*() or timer_*() functions. + * For these clock IDs, the values returned by clock_gettime() and specified + * by clock_settime() represent the amount of execution time of the process + * associated with the clock. + */ + +static unsigned long process_ticks(void) { + unsigned long ticks; + task_t *t; + + spin_lock(¤t->sighand->siglock); + ticks = 0; + + /* Add up the cpu time for all the still running threads of this process */ + t = current; + do { + ticks += t->utime + t->stime; + t = next_thread(t); + } while (t != current); + + spin_unlock(¤t->sighand->siglock); + return ticks; +} + +static int do_posix_clock_process_gettime(struct timespec *tp) +{ + jiffies_to_timespec(current->signal->process_clock_offset + process_ticks(), tp); + return 0; +} + +static int do_posix_clock_process_settime(struct timespec *tp) +{ + current->signal->process_clock_offset = timespec_to_jiffies(tp) - process_ticks(); + return 0; +} + asmlinkage long sys_clock_settime(clockid_t which_clock, const struct timespec __user *tp) { @@ -1175,7 +1278,10 @@ if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0) return -EINVAL; - ret = do_clock_nanosleep(which_clock, flags, &t); + if (posix_clocks[which_clock].nsleep) + ret = posix_clocks[which_clock].nsleep(which_clock, flags, &t); + else + ret = do_clock_nanosleep(which_clock, flags, &t); /* * Do this here as do_clock_nanosleep does not have the real address */ Index: linux/include/linux/sched.h =================================================================== --- linux.orig/include/linux/sched.h 2004-10-04 15:11:59.000000000 -0700 +++ linux/include/linux/sched.h 2004-10-04 15:17:15.000000000 -0700 @@ -280,6 +280,7 @@ /* POSIX.1b Interval Timers */ struct list_head posix_timers; + int process_clock_offset; /* for CLOCK_PROCESS_CPUTIME_ID */ /* job control IDs */ pid_t pgrp; @@ -450,6 +451,7 @@ unsigned long utime, stime, cutime, cstime; unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; /* context switch counts */ u64 start_time; + int thread_clock_offset; /* offset to thread_clock for CLOCK_THREAD_CPUTIME_ID */ /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; /* process credentials */ Index: linux/include/linux/posix-timers.h =================================================================== --- linux.orig/include/linux/posix-timers.h 2004-04-03 19:37:06.000000000 -0800 +++ linux/include/linux/posix-timers.h 2004-10-04 15:15:53.000000000 -0700 @@ -5,9 +5,10 @@ int res; /* in nano seconds */ int (*clock_set) (struct timespec * tp); int (*clock_get) (struct timespec * tp); - int (*nsleep) (int flags, - struct timespec * new_setting, - struct itimerspec * old_setting); + int (*timer_create) (int which_clock, struct sigevent __user *timer_event_spec, + timer_t __user * created_timer_id); + int (*nsleep) (int which_clock, int flags, + struct timespec * t); int (*timer_set) (struct k_itimer * timr, int flags, struct itimerspec * new_setting, struct itimerspec * old_setting);