forked from mirrors/linux
		
	timekeeping: Add the new CLOCK_MONOTONIC_ACTIVE clock
The planned change to unify the behaviour of the MONOTONIC and BOOTTIME clocks vs. suspend removes the ability to retrieve the active non-suspended time of a system. Provide a new CLOCK_MONOTONIC_ACTIVE clock which returns the active non-suspended time of the system via clock_gettime(). This preserves the old behaviour of CLOCK_MONOTONIC before the BOOTTIME/MONOTONIC unification. This new clock also allows applications to detect programmatically that the MONOTONIC and BOOTTIME clocks are identical. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Kevin Easton <kevin@guarana.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mark Salyzyn <salyzyn@android.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Petr Mladek <pmladek@suse.com> Cc: Prarit Bhargava <prarit@redhat.com> Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/20180301165149.965235774@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									78b98e3c5a
								
							
						
					
					
						commit
						72199320d4
					
				
					 6 changed files with 55 additions and 0 deletions
				
			
		|  | @ -52,6 +52,7 @@ struct tk_read_base { | ||||||
|  * @offs_real:		Offset clock monotonic -> clock realtime |  * @offs_real:		Offset clock monotonic -> clock realtime | ||||||
|  * @offs_boot:		Offset clock monotonic -> clock boottime |  * @offs_boot:		Offset clock monotonic -> clock boottime | ||||||
|  * @offs_tai:		Offset clock monotonic -> clock tai |  * @offs_tai:		Offset clock monotonic -> clock tai | ||||||
|  |  * @time_suspended:	Accumulated suspend time | ||||||
|  * @tai_offset:		The current UTC to TAI offset in seconds |  * @tai_offset:		The current UTC to TAI offset in seconds | ||||||
|  * @clock_was_set_seq:	The sequence number of clock was set events |  * @clock_was_set_seq:	The sequence number of clock was set events | ||||||
|  * @cs_was_changed_seq:	The sequence number of clocksource change events |  * @cs_was_changed_seq:	The sequence number of clocksource change events | ||||||
|  | @ -94,6 +95,7 @@ struct timekeeper { | ||||||
| 	ktime_t			offs_real; | 	ktime_t			offs_real; | ||||||
| 	ktime_t			offs_boot; | 	ktime_t			offs_boot; | ||||||
| 	ktime_t			offs_tai; | 	ktime_t			offs_tai; | ||||||
|  | 	ktime_t			time_suspended; | ||||||
| 	s32			tai_offset; | 	s32			tai_offset; | ||||||
| 	unsigned int		clock_was_set_seq; | 	unsigned int		clock_was_set_seq; | ||||||
| 	u8			cs_was_changed_seq; | 	u8			cs_was_changed_seq; | ||||||
|  |  | ||||||
|  | @ -32,6 +32,7 @@ extern void getrawmonotonic64(struct timespec64 *ts); | ||||||
| extern void ktime_get_ts64(struct timespec64 *ts); | extern void ktime_get_ts64(struct timespec64 *ts); | ||||||
| extern time64_t ktime_get_seconds(void); | extern time64_t ktime_get_seconds(void); | ||||||
| extern time64_t ktime_get_real_seconds(void); | extern time64_t ktime_get_real_seconds(void); | ||||||
|  | extern void ktime_get_active_ts64(struct timespec64 *ts); | ||||||
| 
 | 
 | ||||||
| extern int __getnstimeofday64(struct timespec64 *tv); | extern int __getnstimeofday64(struct timespec64 *tv); | ||||||
| extern void getnstimeofday64(struct timespec64 *tv); | extern void getnstimeofday64(struct timespec64 *tv); | ||||||
|  |  | ||||||
|  | @ -61,6 +61,7 @@ struct itimerval { | ||||||
|  */ |  */ | ||||||
| #define CLOCK_SGI_CYCLE			10 | #define CLOCK_SGI_CYCLE			10 | ||||||
| #define CLOCK_TAI			11 | #define CLOCK_TAI			11 | ||||||
|  | #define CLOCK_MONOTONIC_ACTIVE		12 | ||||||
| 
 | 
 | ||||||
| #define MAX_CLOCKS			16 | #define MAX_CLOCKS			16 | ||||||
| #define CLOCKS_MASK			(CLOCK_REALTIME | CLOCK_MONOTONIC) | #define CLOCKS_MASK			(CLOCK_REALTIME | CLOCK_MONOTONIC) | ||||||
|  |  | ||||||
|  | @ -73,6 +73,8 @@ int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp) | ||||||
| 	case CLOCK_BOOTTIME: | 	case CLOCK_BOOTTIME: | ||||||
| 		get_monotonic_boottime64(tp); | 		get_monotonic_boottime64(tp); | ||||||
| 		break; | 		break; | ||||||
|  | 	case CLOCK_MONOTONIC_ACTIVE: | ||||||
|  | 		ktime_get_active_ts64(tp); | ||||||
| 	default: | 	default: | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -263,6 +263,13 @@ static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int posix_get_monotonic_active(clockid_t which_clock, | ||||||
|  | 				      struct timespec64 *tp) | ||||||
|  | { | ||||||
|  | 	ktime_get_active_ts64(tp); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp) | static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp) | ||||||
| { | { | ||||||
| 	tp->tv_sec = 0; | 	tp->tv_sec = 0; | ||||||
|  | @ -1330,6 +1337,11 @@ static const struct k_clock clock_boottime = { | ||||||
| 	.timer_arm		= common_hrtimer_arm, | 	.timer_arm		= common_hrtimer_arm, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct k_clock clock_monotonic_active = { | ||||||
|  | 	.clock_getres		= posix_get_hrtimer_res, | ||||||
|  | 	.clock_get		= posix_get_monotonic_active, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct k_clock * const posix_clocks[] = { | static const struct k_clock * const posix_clocks[] = { | ||||||
| 	[CLOCK_REALTIME]		= &clock_realtime, | 	[CLOCK_REALTIME]		= &clock_realtime, | ||||||
| 	[CLOCK_MONOTONIC]		= &clock_monotonic, | 	[CLOCK_MONOTONIC]		= &clock_monotonic, | ||||||
|  | @ -1342,6 +1354,7 @@ static const struct k_clock * const posix_clocks[] = { | ||||||
| 	[CLOCK_REALTIME_ALARM]		= &alarm_clock, | 	[CLOCK_REALTIME_ALARM]		= &alarm_clock, | ||||||
| 	[CLOCK_BOOTTIME_ALARM]		= &alarm_clock, | 	[CLOCK_BOOTTIME_ALARM]		= &alarm_clock, | ||||||
| 	[CLOCK_TAI]			= &clock_tai, | 	[CLOCK_TAI]			= &clock_tai, | ||||||
|  | 	[CLOCK_MONOTONIC_ACTIVE]	= &clock_monotonic_active, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct k_clock *clockid_to_kclock(const clockid_t id) | static const struct k_clock *clockid_to_kclock(const clockid_t id) | ||||||
|  |  | ||||||
|  | @ -139,6 +139,9 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm) | ||||||
| static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta) | static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta) | ||||||
| { | { | ||||||
| 	tk->offs_boot = ktime_add(tk->offs_boot, delta); | 	tk->offs_boot = ktime_add(tk->offs_boot, delta); | ||||||
|  | 
 | ||||||
|  | 	/* Accumulate time spent in suspend */ | ||||||
|  | 	tk->time_suspended += delta; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -886,6 +889,39 @@ void ktime_get_ts64(struct timespec64 *ts) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(ktime_get_ts64); | EXPORT_SYMBOL_GPL(ktime_get_ts64); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * ktime_get_active_ts64 - Get the active non-suspended monotonic clock | ||||||
|  |  * @ts:		pointer to timespec variable | ||||||
|  |  * | ||||||
|  |  * The function calculates the monotonic clock from the realtime clock and | ||||||
|  |  * the wall_to_monotonic offset, subtracts the accumulated suspend time and | ||||||
|  |  * stores the result in normalized timespec64 format in the variable | ||||||
|  |  * pointed to by @ts. | ||||||
|  |  */ | ||||||
|  | void ktime_get_active_ts64(struct timespec64 *ts) | ||||||
|  | { | ||||||
|  | 	struct timekeeper *tk = &tk_core.timekeeper; | ||||||
|  | 	struct timespec64 tomono, tsusp; | ||||||
|  | 	u64 nsec, nssusp; | ||||||
|  | 	unsigned int seq; | ||||||
|  | 
 | ||||||
|  | 	WARN_ON(timekeeping_suspended); | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		seq = read_seqcount_begin(&tk_core.seq); | ||||||
|  | 		ts->tv_sec = tk->xtime_sec; | ||||||
|  | 		nsec = timekeeping_get_ns(&tk->tkr_mono); | ||||||
|  | 		tomono = tk->wall_to_monotonic; | ||||||
|  | 		nssusp = tk->time_suspended; | ||||||
|  | 	} while (read_seqcount_retry(&tk_core.seq, seq)); | ||||||
|  | 
 | ||||||
|  | 	ts->tv_sec += tomono.tv_sec; | ||||||
|  | 	ts->tv_nsec = 0; | ||||||
|  | 	timespec64_add_ns(ts, nsec + tomono.tv_nsec); | ||||||
|  | 	tsusp = ns_to_timespec64(nssusp); | ||||||
|  | 	*ts = timespec64_sub(*ts, tsusp); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC |  * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC | ||||||
|  * |  * | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Thomas Gleixner
						Thomas Gleixner