summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2016-03-17 17:20:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 18:09:34 -0400
commitda8b44d5a9f8bf26da637b7336508ca534d6b319 (patch)
treef8ce464a2adfa25d255ada3bd4ec762e0af9628a /kernel
parent0a687aace3b8e215e08eed8a67014f5b8f133ab0 (diff)
timer: convert timer_slack_ns from unsigned long to u64
This patchset introduces a /proc/<pid>/timerslack_ns interface which would allow controlling processes to be able to set the timerslack value on other processes in order to save power by avoiding wakeups (Something Android currently does via out-of-tree patches). The first patch tries to fix the internal timer_slack_ns usage which was defined as a long, which limits the slack range to ~4 seconds on 32bit systems. It converts it to a u64, which provides the same basically unlimited slack (500 years) on both 32bit and 64bit machines. The second patch introduces the /proc/<pid>/timerslack_ns interface which allows the full 64bit slack range for a task to be read or set on both 32bit and 64bit machines. With these two patches, on a 32bit machine, after setting the slack on bash to 10 seconds: $ time sleep 1 real 0m10.747s user 0m0.001s sys 0m0.005s The first patch is a little ugly, since I had to chase the slack delta arguments through a number of functions converting them to u64s. Let me know if it makes sense to break that up more or not. Other than that things are fairly straightforward. This patch (of 2): The timer_slack_ns value in the task struct is currently a unsigned long. This means that on 32bit applications, the maximum slack is just over 4 seconds. However, on 64bit machines, its much much larger (~500 years). This disparity could make application development a little (as well as the default_slack) to a u64. This means both 32bit and 64bit systems have the same effective internal slack range. Now the existing ABI via PR_GET_TIMERSLACK and PR_SET_TIMERSLACK specify the interface as a unsigned long, so we preserve that limitation on 32bit systems, where SET_TIMERSLACK can only set the slack to a unsigned long value, and GET_TIMERSLACK will return ULONG_MAX if the slack is actually larger then what can be stored by an unsigned long. This patch also modifies hrtimer functions which specified the slack delta as a unsigned long. Signed-off-by: John Stultz <john.stultz@linaro.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Oren Laadan <orenl@cellrox.com> Cc: Ruchi Kandoi <kandoiruchi@google.com> Cc: Rom Lemarchand <romlem@android.com> Cc: Kees Cook <keescook@chromium.org> Cc: Android Kernel Team <kernel-team@android.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sys.c5
-rw-r--r--kernel/time/hrtimer.c8
-rw-r--r--kernel/time/timer.c4
3 files changed, 10 insertions, 7 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 78947de6f969..cf8ba545c7d3 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2169,7 +2169,10 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
2169 error = perf_event_task_enable(); 2169 error = perf_event_task_enable();
2170 break; 2170 break;
2171 case PR_GET_TIMERSLACK: 2171 case PR_GET_TIMERSLACK:
2172 error = current->timer_slack_ns; 2172 if (current->timer_slack_ns > ULONG_MAX)
2173 error = ULONG_MAX;
2174 else
2175 error = current->timer_slack_ns;
2173 break; 2176 break;
2174 case PR_SET_TIMERSLACK: 2177 case PR_SET_TIMERSLACK:
2175 if (arg2 <= 0) 2178 if (arg2 <= 0)
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index fa909f9fd559..58a321c34cfb 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -979,7 +979,7 @@ static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim,
979 * relative (HRTIMER_MODE_REL) 979 * relative (HRTIMER_MODE_REL)
980 */ 980 */
981void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, 981void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
982 unsigned long delta_ns, const enum hrtimer_mode mode) 982 u64 delta_ns, const enum hrtimer_mode mode)
983{ 983{
984 struct hrtimer_clock_base *base, *new_base; 984 struct hrtimer_clock_base *base, *new_base;
985 unsigned long flags; 985 unsigned long flags;
@@ -1548,7 +1548,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
1548 struct restart_block *restart; 1548 struct restart_block *restart;
1549 struct hrtimer_sleeper t; 1549 struct hrtimer_sleeper t;
1550 int ret = 0; 1550 int ret = 0;
1551 unsigned long slack; 1551 u64 slack;
1552 1552
1553 slack = current->timer_slack_ns; 1553 slack = current->timer_slack_ns;
1554 if (dl_task(current) || rt_task(current)) 1554 if (dl_task(current) || rt_task(current))
@@ -1724,7 +1724,7 @@ void __init hrtimers_init(void)
1724 * @clock: timer clock, CLOCK_MONOTONIC or CLOCK_REALTIME 1724 * @clock: timer clock, CLOCK_MONOTONIC or CLOCK_REALTIME
1725 */ 1725 */
1726int __sched 1726int __sched
1727schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta, 1727schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta,
1728 const enum hrtimer_mode mode, int clock) 1728 const enum hrtimer_mode mode, int clock)
1729{ 1729{
1730 struct hrtimer_sleeper t; 1730 struct hrtimer_sleeper t;
@@ -1792,7 +1792,7 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
1792 * 1792 *
1793 * Returns 0 when the timer has expired otherwise -EINTR 1793 * Returns 0 when the timer has expired otherwise -EINTR
1794 */ 1794 */
1795int __sched schedule_hrtimeout_range(ktime_t *expires, unsigned long delta, 1795int __sched schedule_hrtimeout_range(ktime_t *expires, u64 delta,
1796 const enum hrtimer_mode mode) 1796 const enum hrtimer_mode mode)
1797{ 1797{
1798 return schedule_hrtimeout_range_clock(expires, delta, mode, 1798 return schedule_hrtimeout_range_clock(expires, delta, mode,
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index bbc5d1114583..d1798fa0c743 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1698,10 +1698,10 @@ EXPORT_SYMBOL(msleep_interruptible);
1698static void __sched do_usleep_range(unsigned long min, unsigned long max) 1698static void __sched do_usleep_range(unsigned long min, unsigned long max)
1699{ 1699{
1700 ktime_t kmin; 1700 ktime_t kmin;
1701 unsigned long delta; 1701 u64 delta;
1702 1702
1703 kmin = ktime_set(0, min * NSEC_PER_USEC); 1703 kmin = ktime_set(0, min * NSEC_PER_USEC);
1704 delta = (max - min) * NSEC_PER_USEC; 1704 delta = (u64)(max - min) * NSEC_PER_USEC;
1705 schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL); 1705 schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL);
1706} 1706}
1707 1707