diff options
author | Tomas Janousek <tjanouse@redhat.com> | 2007-07-16 02:39:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:41 -0400 |
commit | 7c3f1a573237b90ef331267260358a0ec4ac9079 (patch) | |
tree | f308047c4f40022d4b8f7226fba73b067dcd2d70 | |
parent | 35ef63f635aa0e414ad6cdb2a4092e1caf99272c (diff) |
Introduce boot based time
The commits
411187fb05cd11676b0979d9fbf3291db69dbce2 (GTOD: persistent clock support)
c1d370e167d66b10bca3b602d3740405469383de (i386: use GTOD persistent clock
support)
changed the monotonic time so that it no longer jumps after resume, but it's
not possible to use it for boot time and process start time calculations then.
Also, the uptime no longer increases during suspend.
I add a variable to track the wall_to_monotonic changes, a function to get the
real boot time and a function to get the boot based time from the monotonic
one.
[akpm@linux-foundation.org: remove exports, add comment]
Signed-off-by: Tomas Janousek <tjanouse@redhat.com>
Cc: Tomas Smetana <tsmetana@redhat.com>
Cc: John Stultz <johnstul@us.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/time.h | 2 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 37 |
2 files changed, 39 insertions, 0 deletions
diff --git a/include/linux/time.h b/include/linux/time.h index dda9be685ab6..4bb05a829be9 100644 --- a/include/linux/time.h +++ b/include/linux/time.h | |||
@@ -116,6 +116,8 @@ extern int do_setitimer(int which, struct itimerval *value, | |||
116 | extern unsigned int alarm_setitimer(unsigned int seconds); | 116 | extern unsigned int alarm_setitimer(unsigned int seconds); |
117 | extern int do_getitimer(int which, struct itimerval *value); | 117 | extern int do_getitimer(int which, struct itimerval *value); |
118 | extern void getnstimeofday(struct timespec *tv); | 118 | extern void getnstimeofday(struct timespec *tv); |
119 | extern void getboottime(struct timespec *ts); | ||
120 | extern void monotonic_to_bootbased(struct timespec *ts); | ||
119 | 121 | ||
120 | extern struct timespec timespec_trunc(struct timespec t, unsigned gran); | 122 | extern struct timespec timespec_trunc(struct timespec t, unsigned gran); |
121 | extern int timekeeping_is_continuous(void); | 123 | extern int timekeeping_is_continuous(void); |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 3d1042f82a68..728cedfd3cbd 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -36,9 +36,17 @@ EXPORT_SYMBOL(xtime_lock); | |||
36 | * at zero at system boot time, so wall_to_monotonic will be negative, | 36 | * at zero at system boot time, so wall_to_monotonic will be negative, |
37 | * however, we will ALWAYS keep the tv_nsec part positive so we can use | 37 | * however, we will ALWAYS keep the tv_nsec part positive so we can use |
38 | * the usual normalization. | 38 | * the usual normalization. |
39 | * | ||
40 | * wall_to_monotonic is moved after resume from suspend for the monotonic | ||
41 | * time not to jump. We need to add total_sleep_time to wall_to_monotonic | ||
42 | * to get the real boot based time offset. | ||
43 | * | ||
44 | * - wall_to_monotonic is no longer the boot time, getboottime must be | ||
45 | * used instead. | ||
39 | */ | 46 | */ |
40 | struct timespec xtime __attribute__ ((aligned (16))); | 47 | struct timespec xtime __attribute__ ((aligned (16))); |
41 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); | 48 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); |
49 | static unsigned long total_sleep_time; /* seconds */ | ||
42 | 50 | ||
43 | EXPORT_SYMBOL(xtime); | 51 | EXPORT_SYMBOL(xtime); |
44 | 52 | ||
@@ -251,6 +259,7 @@ void __init timekeeping_init(void) | |||
251 | xtime.tv_nsec = 0; | 259 | xtime.tv_nsec = 0; |
252 | set_normalized_timespec(&wall_to_monotonic, | 260 | set_normalized_timespec(&wall_to_monotonic, |
253 | -xtime.tv_sec, -xtime.tv_nsec); | 261 | -xtime.tv_sec, -xtime.tv_nsec); |
262 | total_sleep_time = 0; | ||
254 | 263 | ||
255 | write_sequnlock_irqrestore(&xtime_lock, flags); | 264 | write_sequnlock_irqrestore(&xtime_lock, flags); |
256 | } | 265 | } |
@@ -282,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev) | |||
282 | 291 | ||
283 | xtime.tv_sec += sleep_length; | 292 | xtime.tv_sec += sleep_length; |
284 | wall_to_monotonic.tv_sec -= sleep_length; | 293 | wall_to_monotonic.tv_sec -= sleep_length; |
294 | total_sleep_time += sleep_length; | ||
285 | } | 295 | } |
286 | /* re-base the last cycle value */ | 296 | /* re-base the last cycle value */ |
287 | clock->cycle_last = clocksource_read(clock); | 297 | clock->cycle_last = clocksource_read(clock); |
@@ -476,3 +486,30 @@ void update_wall_time(void) | |||
476 | change_clocksource(); | 486 | change_clocksource(); |
477 | update_vsyscall(&xtime, clock); | 487 | update_vsyscall(&xtime, clock); |
478 | } | 488 | } |
489 | |||
490 | /** | ||
491 | * getboottime - Return the real time of system boot. | ||
492 | * @ts: pointer to the timespec to be set | ||
493 | * | ||
494 | * Returns the time of day in a timespec. | ||
495 | * | ||
496 | * This is based on the wall_to_monotonic offset and the total suspend | ||
497 | * time. Calls to settimeofday will affect the value returned (which | ||
498 | * basically means that however wrong your real time clock is at boot time, | ||
499 | * you get the right time here). | ||
500 | */ | ||
501 | void getboottime(struct timespec *ts) | ||
502 | { | ||
503 | set_normalized_timespec(ts, | ||
504 | - (wall_to_monotonic.tv_sec + total_sleep_time), | ||
505 | - wall_to_monotonic.tv_nsec); | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * monotonic_to_bootbased - Convert the monotonic time to boot based. | ||
510 | * @ts: pointer to the timespec to be converted | ||
511 | */ | ||
512 | void monotonic_to_bootbased(struct timespec *ts) | ||
513 | { | ||
514 | ts->tv_sec += total_sleep_time; | ||
515 | } | ||