Posix compliant cpu clocks V6 [1/3]: Generic Kernel patch

From: Christoph Lameter
Date: Fri Oct 01 2004 - 15:11:05 EST


Changelog
* Add CLOCK_THREAD_CPUTIME and CLOCK_PROCESS_CPUTIME_ID processing
* Add timer_create override for posix clocks
* Complete implementation of nanosleep overrride for posix clocks
* export posix clock registration in include/linux/posix-timers.h
* Allow up to 16 posix clocks

Signed-off-by: Christoph Lameter <clameter@xxxxxxx>

Index: linux-2.6.9-rc3/kernel/posix-timers.c
===================================================================
--- linux-2.6.9-rc3.orig/kernel/posix-timers.c 2004-09-29 20:04:47.000000000 -0700
+++ linux-2.6.9-rc3/kernel/posix-timers.c 2004-10-01 12:48:55.000000000 -0700
@@ -10,6 +10,10 @@
* 2004-06-01 Fix CLOCK_REALTIME clock/timer TIMER_ABSTIME bug.
* Copyright (C) 2004 Boris Hu
*
+ * 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
@@ -133,18 +137,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...
@@ -162,7 +158,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
@@ -197,8 +193,16 @@
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 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);
+int do_posix_clock_notimer_create(int which_clock,
+ struct sigevent __user *time_event_spec,
+ timer_t __user *created_timer_id);
+int do_posix_clock_nonanosleep(int which_clock, int flags, struct timespec * t);

static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
{
@@ -218,6 +222,20 @@
.clock_get = do_posix_clock_monotonic_gettime,
.clock_set = do_posix_clock_monotonic_settime
};
+ struct k_clock clock_thread = {.res = CLOCK_REALTIME_RES,
+ .abs_struct = NULL,
+ .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,
+ .abs_struct = NULL,
+ .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
+ };

#ifdef CONFIG_TIME_INTERPOLATION
/* Clocks are more accurate with time interpolators */
@@ -226,6 +244,8 @@

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, NULL, NULL);
@@ -577,6 +597,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;
@@ -1222,11 +1246,88 @@
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(&current->sighand->siglock);
+ /* The signal structure is shared between all threads */
+ ticks = current->signal->utime + current->signal->stime;
+
+ /* 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(&current->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)
{
@@ -1413,7 +1514,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-2.6.9-rc3/include/linux/sched.h
===================================================================
--- linux-2.6.9-rc3.orig/include/linux/sched.h 2004-09-29 20:03:54.000000000 -0700
+++ linux-2.6.9-rc3/include/linux/sched.h 2004-10-01 08:40:30.000000000 -0700
@@ -293,6 +293,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;
@@ -509,6 +510,7 @@
unsigned long utime, stime;
unsigned long nvcsw, nivcsw; /* 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;
/* process credentials */
Index: linux-2.6.9-rc3/include/linux/posix-timers.h
===================================================================
--- linux-2.6.9-rc3.orig/include/linux/posix-timers.h 2004-09-29 20:04:46.000000000 -0700
+++ linux-2.6.9-rc3/include/linux/posix-timers.h 2004-10-01 08:40:30.000000000 -0700
@@ -13,9 +13,10 @@
struct k_clock_abs *abs_struct;
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);
@@ -23,6 +24,16 @@
void (*timer_get) (struct k_itimer * timr,
struct itimerspec * cur_setting);
};
+
+void register_posix_clock(int clock_id, struct k_clock *new_clock);
+
+/* Error handlers for timer_create and nanosleep */
+int do_posix_clock_notimer_create(int which_clock,
+ struct sigevent __user *time_event_spec,
+ timer_t __user *created_timer_id);
+
+int do_posix_clock_nonanosleep(int which_clock, int flags, struct timespec * t);
+
struct now_struct {
unsigned long jiffies;
};
@@ -42,3 +53,4 @@
} \
}while (0)
#endif
+
Index: linux-2.6.9-rc3/include/linux/time.h
===================================================================
--- linux-2.6.9-rc3.orig/include/linux/time.h 2004-09-29 20:05:18.000000000 -0700
+++ linux-2.6.9-rc3/include/linux/time.h 2004-10-01 08:40:30.000000000 -0700
@@ -413,7 +413,12 @@
#define CLOCK_REALTIME_HR 4
#define CLOCK_MONOTONIC_HR 5

-#define MAX_CLOCKS 6
+/*
+ * The IDs of various hardware clocks
+ */
+
+
+#define MAX_CLOCKS 16
#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC | \
CLOCK_REALTIME_HR | CLOCK_MONOTONIC_HR)
#define CLOCKS_MONO (CLOCK_MONOTONIC & CLOCK_MONOTONIC_HR)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/