Message ID | 503cd1fa268867573001cfc9bb5681ee3b5b32fa.1293820862.git.richard.cochran@omicron.at |
---|---|
State | Not Applicable, archived |
Delegated to: | David Miller |
Headers | show |
On Fri, 2010-12-31 at 20:15 +0100, Richard Cochran wrote:
> +#define CLOCK_DISPATCH(clock, call, arglist) dispatch_##call arglist
How about you run something like:
:% s/CLOCK_DISPATCH([^,]*, \([^,]*\), \([^)]*)\))/dispatch_\1\2/g
and remove that cruft all together?
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Jan 03, 2011 at 10:29:09AM +0100, Peter Zijlstra wrote: > On Fri, 2010-12-31 at 20:15 +0100, Richard Cochran wrote: > > +#define CLOCK_DISPATCH(clock, call, arglist) dispatch_##call arglist > > How about you run something like: > > :% s/CLOCK_DISPATCH([^,]*, \([^,]*\), \([^)]*)\))/dispatch_\1\2/g > > and remove that cruft all together? Gladly ;^) Richard -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, 31 Dec 2010, Richard Cochran wrote: > +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); I wonder whether we should be a bit more clever here and create an extra entry for posix_cpu_timers in the posix_clocks array and do the following: /* These are local to posix-timer.c and not exposed to anything else */ #define POSIX_INV_CLOCK_ID MAX_CLOCKS #define POSIX_CPU_CLOCK_ID (MAX_CLOCKS + 1) #define NR_CLOCK_ENTRIES (MAX_CLOCKS + 2) static struct k_clock posix_clocks[NR_CLOCK_ENTRIES]; static __init int init_posix_timers(void) { ...... /* * We leave the POSIX_INV_CLOCK_ID entries zeroed out, so the * the dispatch code will return -EINVAL. */ init_posix_cpu_timer_entries(); } static clockid_t clock_get_array_id(const clockid_t id) { if (id >= 0) return id < MAX_CLOCKS ? id : POSIX_INV_CLOCK_ID; if (clock_is_posix_cpu(id)) return POSIX_CPU_CLOCK_ID; return POSIX_INV_CLOCK_ID; } static inline int dispatch_clock_getres(const clockid_t id, struct timespec *ts) { struct k_clock *clk = &posix_clocks[clock_get_array_id(id)]; return clk->clock_getres ? clk->clock_getres(id, ts) : -EINVAL; } That reduces the code significantly and the MAX_CLOCKS check in clock_get_array_id() replaces the invalid_clock() check in the syscalls as well. It does not matter whether we check this before or after copying stuff from user. Adding your new stuff requires just another entry in the array, the setup of the function pointers and the CLOCKFD check in clock_get_array_id(). Everything else just falls in place. > + > +#define CLOCK_DISPATCH(clock, call, arglist) dispatch_##call arglist > + Can we get rid of this completely please ? > clock_nanosleep_restart(struct restart_block *restart_block) > { > - clockid_t which_clock = restart_block->arg0; > - How does that compile ? > return CLOCK_DISPATCH(which_clock, nsleep_restart, > (restart_block)); > } Thanks, tglx -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Jan 11, 2011 at 01:57:23PM +0100, Thomas Gleixner wrote: > I wonder whether we should be a bit more clever here and create an > extra entry for posix_cpu_timers in the posix_clocks array and do the > following: ... > That reduces the code significantly and the MAX_CLOCKS check in > clock_get_array_id() replaces the invalid_clock() check in the > syscalls as well. It does not matter whether we check this before or > after copying stuff from user. Well, this does reduce the number of LOC, but the number of comparisons is the same. I think the code size would be also no different. > Adding your new stuff requires just another entry in the array, the > setup of the function pointers and the CLOCKFD check in > clock_get_array_id(). Everything else just falls in place. For me, I am not sure if either version is really very pretty or easy to understand. My instinct is to keep the posix_cpu_X and pc_X functions out of the array of static clock id functions, if only to make the distinction between the legacy static ids and new dynamic ids clear. The conclusion from the "dynamic clock as file" discussion was that we don't want to add any more static clock ids, and new clocks should use the new, dynamic clock API. So, we should discourage any future attempt to add to that function array! Having said that, if you insist on it, I won't mind reworking the dispatch code as you suggested. > > + > > +#define CLOCK_DISPATCH(clock, call, arglist) dispatch_##call arglist > > + > > Can we get rid of this completely please ? Yes, gladly. > > clock_nanosleep_restart(struct restart_block *restart_block) > > { > > - clockid_t which_clock = restart_block->arg0; > > - > > How does that compile ? Because the CLOCK_DISPATCH macro, above, makes no use of the first argument! I have removed the macro for the next round. > > return CLOCK_DISPATCH(which_clock, nsleep_restart, > > (restart_block)); > > } Thanks, Richard -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, 12 Jan 2011, Richard Cochran wrote: > On Tue, Jan 11, 2011 at 01:57:23PM +0100, Thomas Gleixner wrote: > > I wonder whether we should be a bit more clever here and create an > > extra entry for posix_cpu_timers in the posix_clocks array and do the > > following: > ... > > That reduces the code significantly and the MAX_CLOCKS check in > > clock_get_array_id() replaces the invalid_clock() check in the > > syscalls as well. It does not matter whether we check this before or > > after copying stuff from user. > > Well, this does reduce the number of LOC, but the number of > comparisons is the same. I think the code size would be also no > different. Right, It's about lines of code and ever repeated if / else constructs in the dispatch functions. The number of comparisons is probably the same, but I'm sure that the binary size will be smaller. We probably can remove the dispatch inlines that way completely and do the call directly from the syscall function. > > Adding your new stuff requires just another entry in the array, the > > setup of the function pointers and the CLOCKFD check in > > clock_get_array_id(). Everything else just falls in place. > > For me, I am not sure if either version is really very pretty or easy > to understand. Well, if we document clock_get_array_id() proper, then it's easier to follow than 10 dispatch functions which have all the same checks and comparisons inside. > My instinct is to keep the posix_cpu_X and pc_X functions out of the > array of static clock id functions, if only to make the distinction > between the legacy static ids and new dynamic ids clear. > > The conclusion from the "dynamic clock as file" discussion was that we > don't want to add any more static clock ids, and new clocks should use > the new, dynamic clock API. So, we should discourage any future > attempt to add to that function array! These IDs are not public, they are helpers to make the code simpler, nothing else. I agree, that we don't want to extend the static ids for public consumption, but implementation wise we can do that confined to posix-timers.c. > Having said that, if you insist on it, I won't mind reworking the > dispatch code as you suggested. I'm not insisting. I just saw the repeated if/else constructs and added the clockfd check mentally :) That's where I started to wonder about a way to do the same thing with way less lines of code. > > > clock_nanosleep_restart(struct restart_block *restart_block) > > > { > > > - clockid_t which_clock = restart_block->arg0; > > > - > > > > How does that compile ? > > Because the CLOCK_DISPATCH macro, above, makes no use of the first Missed that, sorry. > argument! I have removed the macro for the next round. Cool. Thanks, tglx -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Jan 12, 2011 at 12:16:10PM +0100, Thomas Gleixner wrote: > > We probably can remove the dispatch inlines that way completely and do > the call directly from the syscall function. Right, okay. I also wanted to put the whole logic into the syscall itself. I'll try it that way. Thanks, Richard -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Jan 11, 2011 at 01:57:23PM +0100, Thomas Gleixner wrote: > > static clockid_t clock_get_array_id(const clockid_t id) > { > if (id >= 0) > return id < MAX_CLOCKS ? id : POSIX_INV_CLOCK_ID; > > if (clock_is_posix_cpu(id)) > return POSIX_CPU_CLOCK_ID; > > return POSIX_INV_CLOCK_ID; > } > > static inline int dispatch_clock_getres(const clockid_t id, struct timespec *ts) > { > struct k_clock *clk = &posix_clocks[clock_get_array_id(id)]; > > return clk->clock_getres ? clk->clock_getres(id, ts) : -EINVAL; > } I would like to take this idea one step further, like so: static struct k_clock *clockid_to_kclock(const clockid_t id) { if (id >= 0) return id < MAX_CLOCKS ? &posix_clocks[id] : &posix_clocks[POSIX_INV_CLOCK_ID]; ... } SYSCALL( ... , const clockid_t id, struct timespec *ts) { struct k_clock *clk = clockid_to_kclock(id); return clk->clock_getres ? clk->clock_getres(id, ts) : -EINVAL; } What do you think? Thanks, Richard -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, 13 Jan 2011, Richard Cochran wrote: > On Tue, Jan 11, 2011 at 01:57:23PM +0100, Thomas Gleixner wrote: > > > > static clockid_t clock_get_array_id(const clockid_t id) > > { > > if (id >= 0) > > return id < MAX_CLOCKS ? id : POSIX_INV_CLOCK_ID; > > > > if (clock_is_posix_cpu(id)) > > return POSIX_CPU_CLOCK_ID; > > > > return POSIX_INV_CLOCK_ID; > > } > > > > static inline int dispatch_clock_getres(const clockid_t id, struct timespec *ts) > > { > > struct k_clock *clk = &posix_clocks[clock_get_array_id(id)]; > > > > return clk->clock_getres ? clk->clock_getres(id, ts) : -EINVAL; > > } > > I would like to take this idea one step further, like so: > > static struct k_clock *clockid_to_kclock(const clockid_t id) > { > if (id >= 0) > return id < MAX_CLOCKS ? > &posix_clocks[id] : &posix_clocks[POSIX_INV_CLOCK_ID]; > ... > } > > SYSCALL( ... , const clockid_t id, struct timespec *ts) > { > struct k_clock *clk = clockid_to_kclock(id); > > return clk->clock_getres ? clk->clock_getres(id, ts) : -EINVAL; > } > > What do you think? Yeah, that's even better! -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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)); }
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@omicron.at> --- include/linux/posix-timers.h | 14 +++ include/linux/time.h | 2 + kernel/posix-timers.c | 241 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 213 insertions(+), 44 deletions(-)