--- v10
+++ v8
@@ -1,61 +1,423 @@
-This patch adds the clock_adjtime system call to the x86 architecture.
-
-Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
+Paraphrasing tglx:
+
+This patch simplifies and clarifies the code, doing the normal thing
+with function pointer structures. Stuff which is not implemented does
+not magically become called via some common function. There is no
+point in doing that.
+
+We fill in the various k_clock structs with the correct pointers in
+the first place and let the NULL case return a sensible error
+value. The data structure does not become larger that way. It's a
+little bit more init code, but that's fine if we make the code better
+in general. In that case it's not even more init code, it's just
+filling the data structures which we register.
+
+My own words:
+
+For now, each of the registered k_clocks has the previously NULL
+functions assigned to the common_xyz function, since that usage was
+implicitly enforced by the CLOCK_DISPTACH macro. These functions are
+marked with a /* default: */ comment.
+
+As as possible further improvement for the future, one could go
+through and replace the various no_xyz function pointers in the
+k_clocks with NULL pointers.
+
+Signed-off-by: Richard Cochran <richard.cochran-3mrvs1K0uXizZXS1Dc/lvw@public.gmane.org>
---
- arch/x86/ia32/ia32entry.S | 1 +
- arch/x86/include/asm/unistd_32.h | 3 ++-
- arch/x86/include/asm/unistd_64.h | 2 ++
- arch/x86/kernel/syscall_table_32.S | 1 +
- 4 files changed, 6 insertions(+), 1 deletions(-)
-
-diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
-index 518bb99..0ed7896 100644
---- a/arch/x86/ia32/ia32entry.S
-+++ b/arch/x86/ia32/ia32entry.S
-@@ -851,4 +851,5 @@ ia32_sys_call_table:
- .quad sys_fanotify_init
- .quad sys32_fanotify_mark
- .quad sys_prlimit64 /* 340 */
-+ .quad compat_sys_clock_adjtime
- ia32_syscall_end:
-diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
-index b766a5e..b6f73f1 100644
---- a/arch/x86/include/asm/unistd_32.h
-+++ b/arch/x86/include/asm/unistd_32.h
-@@ -346,10 +346,11 @@
- #define __NR_fanotify_init 338
- #define __NR_fanotify_mark 339
- #define __NR_prlimit64 340
-+#define __NR_clock_adjtime 341
-
- #ifdef __KERNEL__
-
--#define NR_syscalls 341
-+#define NR_syscalls 342
-
- #define __ARCH_WANT_IPC_PARSE_VERSION
- #define __ARCH_WANT_OLD_READDIR
-diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
-index 363e9b8..5ee3085 100644
---- a/arch/x86/include/asm/unistd_64.h
-+++ b/arch/x86/include/asm/unistd_64.h
-@@ -669,6 +669,8 @@ __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
- __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
- #define __NR_prlimit64 302
- __SYSCALL(__NR_prlimit64, sys_prlimit64)
-+#define __NR_clock_adjtime 303
-+__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
-
- #ifndef __NO_STUBS
- #define __ARCH_WANT_OLD_READDIR
-diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
-index b35786d..68c7b9a 100644
---- a/arch/x86/kernel/syscall_table_32.S
-+++ b/arch/x86/kernel/syscall_table_32.S
-@@ -340,3 +340,4 @@ ENTRY(sys_call_table)
- .long sys_fanotify_init
- .long sys_fanotify_mark
- .long sys_prlimit64 /* 340 */
-+ .long sys_clock_adjtime
+ include/linux/posix-timers.h | 14 +++
+ include/linux/time.h | 2 +
+ kernel/posix-timers.c | 241 ++++++++++++++++++++++++++++++++++--------
+ 3 files changed, 213 insertions(+), 44 deletions(-)
+
+diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
+index b05d9b8..eef7f9c 100644
+--- a/include/linux/posix-timers.h
++++ b/include/linux/posix-timers.h
+@@ -18,6 +18,18 @@ struct cpu_timer_list {
+ int firing;
+ };
+
++/* Bit fields within a clockid:
++ *
++ * The most significant 29 bits hold either a pid or a file descriptor.
++ *
++ * Bit 2 indicates whether a cpu clock refers to a thread or a process.
++ *
++ * Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or FD=3.
++ *
++ * A clockid is invalid if bits 2, 1, and 0 all set (see also CLOCK_INVALID
++ * in include/linux/time.h)
++ */
++
+ #define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3))
+ #define CPUCLOCK_PERTHREAD(clock) \
+ (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
+@@ -29,6 +41,8 @@ struct cpu_timer_list {
+ #define CPUCLOCK_VIRT 1
+ #define CPUCLOCK_SCHED 2
+ #define CPUCLOCK_MAX 3
++#define CLOCKFD CPUCLOCK_MAX
++#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
+
+ #define MAKE_PROCESS_CPUCLOCK(pid, clock) \
+ ((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
+diff --git a/include/linux/time.h b/include/linux/time.h
+index b402134..99d4b14 100644
+--- a/include/linux/time.h
++++ b/include/linux/time.h
+@@ -300,6 +300,8 @@ struct itimerval {
+ #define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
+ #define CLOCKS_MONO CLOCK_MONOTONIC
+
++#define CLOCK_INVALID -1
++
+ /*
+ * The various flags for setting POSIX.1b interval timers:
+ */
+diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
+index 502bde4..65b0599 100644
+--- a/kernel/posix-timers.c
++++ b/kernel/posix-timers.c
+@@ -138,6 +138,7 @@ static struct k_clock posix_clocks[MAX_CLOCKS];
+ */
+ static int common_nsleep(const clockid_t, int flags, struct timespec *t,
+ struct timespec __user *rmtp);
++static long common_nsleep_restart(struct restart_block *restart_block);
+ static void common_timer_get(struct k_itimer *, struct itimerspec *);
+ static int common_timer_set(struct k_itimer *, int,
+ struct itimerspec *, struct itimerspec *);
+@@ -152,41 +153,14 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
+ spin_unlock_irqrestore(&timr->it_lock, flags);
+ }
+
+-/*
+- * Call the k_clock hook function if non-null, or the default function.
+- */
+-#define CLOCK_DISPATCH(clock, call, arglist) \
+- ((clock) < 0 ? posix_cpu_##call arglist : \
+- (posix_clocks[clock].call != NULL \
+- ? (*posix_clocks[clock].call) arglist : common_##call arglist))
+-
+-/*
+- * Default clock hook functions when the struct k_clock passed
+- * to register_posix_clock leaves a function pointer null.
+- *
+- * The function common_CALL is the default implementation for
+- * the function pointer CALL in struct k_clock.
+- */
+
+-static inline int common_clock_getres(const clockid_t which_clock,
+- struct timespec *tp)
+-{
+- tp->tv_sec = 0;
+- tp->tv_nsec = posix_clocks[which_clock].res;
+- return 0;
+-}
+-
+-/*
+- * Get real time for posix timers
+- */
+ static int common_clock_get(clockid_t which_clock, struct timespec *tp)
+ {
+ ktime_get_real_ts(tp);
+ return 0;
+ }
+
+-static inline int common_clock_set(const clockid_t which_clock,
+- struct timespec *tp)
++static int common_clock_set(const clockid_t which_clock, struct timespec *tp)
+ {
+ return do_sys_settimeofday(tp, NULL);
+ }
+@@ -197,7 +171,7 @@ static int common_timer_create(struct k_itimer *new_timer)
+ return 0;
+ }
+
+-static inline int common_clock_adj(const clockid_t which_clock, struct timex *t)
++static int common_clock_adj(const clockid_t which_clock, struct timex *t)
+ {
+ return do_adjtimex(t);
+ }
+@@ -214,19 +188,14 @@ static int no_nsleep(const clockid_t which_clock, int flags,
+ }
+
+ /*
+- * Return nonzero if we know a priori this clockid_t value is bogus.
++ * Return 'true' if we know a priori this clockid_t value is bogus.
+ */
+-static inline int invalid_clockid(const clockid_t which_clock)
++static inline bool invalid_clockid(const clockid_t which_clock)
+ {
+- if (which_clock < 0) /* CPU clock, posix_cpu_* will check it */
+- return 0;
+- if ((unsigned) which_clock >= MAX_CLOCKS)
+- return 1;
+- if (posix_clocks[which_clock].clock_getres != NULL)
+- return 0;
+- if (posix_clocks[which_clock].res != 0)
+- return 0;
+- return 1;
++ if (which_clock >= MAX_CLOCKS)
++ return true;
++ else
++ return false;
+ }
+
+ /*
+@@ -273,12 +242,29 @@ static __init int init_posix_timers(void)
+ {
+ struct k_clock clock_realtime = {
+ .clock_getres = hrtimer_get_res,
++ /* defaults: */
++ .clock_adj = common_clock_adj,
++ .clock_get = common_clock_get,
++ .clock_set = common_clock_set,
++ .nsleep = common_nsleep,
++ .nsleep_restart = common_nsleep_restart,
++ .timer_create = common_timer_create,
++ .timer_del = common_timer_del,
++ .timer_get = common_timer_get,
++ .timer_set = common_timer_set,
+ };
+ struct k_clock clock_monotonic = {
+ .clock_getres = hrtimer_get_res,
+ .clock_get = posix_ktime_get_ts,
+ .clock_set = do_posix_clock_nosettime,
+ .clock_adj = do_posix_clock_noadjtime,
++ /* defaults: */
++ .nsleep = common_nsleep,
++ .nsleep_restart = common_nsleep_restart,
++ .timer_create = common_timer_create,
++ .timer_del = common_timer_del,
++ .timer_get = common_timer_get,
++ .timer_set = common_timer_set,
+ };
+ struct k_clock clock_monotonic_raw = {
+ .clock_getres = hrtimer_get_res,
+@@ -287,6 +273,11 @@ static __init int init_posix_timers(void)
+ .clock_adj = do_posix_clock_noadjtime,
+ .timer_create = no_timer_create,
+ .nsleep = no_nsleep,
++ /* defaults: */
++ .nsleep_restart = common_nsleep_restart,
++ .timer_del = common_timer_del,
++ .timer_get = common_timer_get,
++ .timer_set = common_timer_set,
+ };
+ struct k_clock clock_realtime_coarse = {
+ .clock_getres = posix_get_coarse_res,
+@@ -295,6 +286,11 @@ static __init int init_posix_timers(void)
+ .clock_adj = do_posix_clock_noadjtime,
+ .timer_create = no_timer_create,
+ .nsleep = no_nsleep,
++ /* defaults: */
++ .nsleep_restart = common_nsleep_restart,
++ .timer_del = common_timer_del,
++ .timer_get = common_timer_get,
++ .timer_set = common_timer_set,
+ };
+ struct k_clock clock_monotonic_coarse = {
+ .clock_getres = posix_get_coarse_res,
+@@ -303,6 +299,11 @@ static __init int init_posix_timers(void)
+ .clock_adj = do_posix_clock_noadjtime,
+ .timer_create = no_timer_create,
+ .nsleep = no_nsleep,
++ /* defaults: */
++ .nsleep_restart = common_nsleep_restart,
++ .timer_del = common_timer_del,
++ .timer_get = common_timer_get,
++ .timer_set = common_timer_set,
+ };
+
+ register_posix_clock(CLOCK_REALTIME, &clock_realtime);
+@@ -526,6 +527,160 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
+ kmem_cache_free(posix_timers_cache, tmr);
+ }
+
++static inline bool clock_is_posix_cpu(const clockid_t id)
++{
++ if ((id & CLOCKFD_MASK) == CLOCKFD)
++ return false;
++ else
++ return true;
++}
++
++static inline int dispatch_clock_getres(const clockid_t id, struct timespec *ts)
++{
++ if (id >= 0) {
++ return posix_clocks[id].clock_getres ?
++ posix_clocks[id].clock_getres(id, ts) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_clock_getres(id, ts);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_clock_set(const clockid_t id, struct timespec *ts)
++{
++ if (id >= 0) {
++ return posix_clocks[id].clock_set ?
++ posix_clocks[id].clock_set(id, ts) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_clock_set(id, ts);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_clock_get(const clockid_t id, struct timespec *ts)
++{
++ if (id >= 0) {
++ return posix_clocks[id].clock_get ?
++ posix_clocks[id].clock_get(id, ts) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_clock_get(id, ts);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_clock_adj(const clockid_t id, struct timex *tx)
++{
++ if (id >= 0) {
++ return posix_clocks[id].clock_adj ?
++ posix_clocks[id].clock_adj(id, tx) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_clock_adj(id, tx);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_timer_create(struct k_itimer *kit)
++{
++ clockid_t id = kit->it_clock;
++
++ if (id >= 0) {
++ return posix_clocks[id].timer_create ?
++ posix_clocks[id].timer_create(kit) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_timer_create(kit);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_nsleep(const clockid_t id, int flags,
++ struct timespec *ts,
++ struct timespec __user *rts)
++{
++ if (id >= 0) {
++ return posix_clocks[id].nsleep ?
++ posix_clocks[id].nsleep(id, flags, ts, rts) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_nsleep(id, flags, ts, rts);
++
++ return -EINVAL;
++}
++
++static inline long dispatch_nsleep_restart(struct restart_block *block)
++{
++ clockid_t id = block->arg0;
++
++ if (id >= 0) {
++ return posix_clocks[id].nsleep_restart ?
++ posix_clocks[id].nsleep_restart(block) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_nsleep_restart(block);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_timer_set(struct k_itimer *kit, int flags,
++ struct itimerspec *tsp,
++ struct itimerspec *old)
++{
++ clockid_t id = kit->it_clock;
++
++ if (id >= 0) {
++ return posix_clocks[id].timer_set ?
++ posix_clocks[id].timer_set(kit, flags, tsp, old) :
++ -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_timer_set(kit, flags, tsp, old);
++
++ return -EINVAL;
++}
++
++static inline int dispatch_timer_del(struct k_itimer *kit)
++{
++ clockid_t id = kit->it_clock;
++
++ if (id >= 0) {
++ return posix_clocks[id].timer_del ?
++ posix_clocks[id].timer_del(kit) : -EINVAL;
++ }
++
++ if (clock_is_posix_cpu(id))
++ return posix_cpu_timer_del(kit);
++
++ return -EINVAL;
++}
++
++static inline void dispatch_timer_get(struct k_itimer *kit,
++ struct itimerspec *tsp)
++{
++ clockid_t id = kit->it_clock;
++
++ if (id >= 0 && posix_clocks[id].timer_get)
++
++ posix_clocks[id].timer_get(kit, tsp);
++
++ else if (clock_is_posix_cpu(id))
++
++ posix_cpu_timer_get(kit, tsp);
++}
++
++#define CLOCK_DISPATCH(clock, call, arglist) dispatch_##call arglist
++
+ /* Create a POSIX.1b interval timer. */
+
+ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
+@@ -847,7 +1002,7 @@ retry:
+ return error;
+ }
+
+-static inline int common_timer_del(struct k_itimer *timer)
++static int common_timer_del(struct k_itimer *timer)
+ {
+ timer->it.real.interval.tv64 = 0;
+
+@@ -1056,7 +1211,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
+ /*
+ * nanosleep_restart for monotonic and realtime clocks
+ */
+-static int common_nsleep_restart(struct restart_block *restart_block)
++static long common_nsleep_restart(struct restart_block *restart_block)
+ {
+ return hrtimer_nanosleep_restart(restart_block);
+ }
+@@ -1068,8 +1223,6 @@ static int common_nsleep_restart(struct restart_block *restart_block)
+ long
+ clock_nanosleep_restart(struct restart_block *restart_block)
+ {
+- clockid_t which_clock = restart_block->arg0;
+-
+ return CLOCK_DISPATCH(which_clock, nsleep_restart,
+ (restart_block));
+ }
--
1.7.0.4