* [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior
@ 2014-09-10 1:31 Richard Larocque
2014-09-10 1:31 ` [PATCH 1/3] alarmtimer: Return relative times in timer_gettime Richard Larocque
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Richard Larocque @ 2014-09-10 1:31 UTC (permalink / raw)
To: tglx, john.stultz; +Cc: linux-kernel, Richard Larocque
I've been working on some changes to posix-timers.c in an attempt to better
support CRIU. Along the way, I've discovered some issues with the posix alarm
timers that should be fixed independent of any other work.
It seems that there was an older issue with the setting of relative timeouts
with timer_settime(). That was addressed around 3.16 with
16927776ae757d0d132bdbfabbfe2c498342bd59 ("alarmtimer: Fix bug where relative
alarm timers were treated as absolute"). That fixed the setting of times, but
it doesn't fix the retrieval of times.
According to the man pages (and POSIX), timer_gettime() is supposed to return
the time left until the timeout, not the absolute time at which the timeout is
expected to fire. The non-ALARM clocks correctly show relative times, but
CLOCK_BOOTTIME_ALARM and CLOCK_REALTIME_ALARM do not.
A second issue with these timers is that they call posix_event_timer() without
checking the value of it_sigev_notify. This is a problem, because
it_sigev_notify could be SIGEV_NONE, in which case the signal should not be
delivered. The non-alarm timers don't need to check it_sigev_notify in their
timeout handling code path, because they never schedule timeouts for those
kinds of timers in the first place.
See below for a program that demonstrates these behaviors, and some sample output.
The third patch in this stack is the odd one out. I suspect that there's
a locking issue in the alarm timer code, and this is my attempt to fix it.
It's not quite related to the first two, but it does conflict with one of them,
so I figured I should include it in this patch stack.
PS: This is my first upstream patch, so please excuse any etiquette violations.
Richard Larocque (3):
alarmtimer: Return relative times in timer_gettime
alarmtimer: Do not signal SIGEV_NONE timers
alarmtimer: Lock k_itimer during timer callback
kernel/time/alarmtimer.c | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)
--------
/* timer_gettime_test.c: A program to test the behavior of timer_gettime() */
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
static void do_show_timer(clockid_t which_clock);
int main() {
printf("CLOCK_REALTIME\n");
do_show_timer(CLOCK_REALTIME);
printf("\n");
printf("CLOCK_BOOTTIME\n");
do_show_timer(CLOCK_BOOTTIME);
printf("\n");
printf("CLOCK_REALTIME_ALARM\n");
do_show_timer(CLOCK_REALTIME_ALARM);
printf("\n");
printf("CLOCK_BOOTTIME_ALARM\n");
do_show_timer(CLOCK_BOOTTIME_ALARM);
printf("\n");
}
static void do_show_timer(clockid_t which_clock) {
struct sigevent sevp;
timer_t timerid;
struct itimerspec in, out;
struct timespec ts;
int i;
/*
* SIGEV_NONE is supposed to prevent signal delivery, but it doesn't.
* Set signo to SIGSTOP to make the received signal obvious but
* harmless.
*/
sevp.sigev_notify = SIGEV_NONE;
sevp.sigev_signo = SIGSTOP;
if (timer_create(which_clock, &sevp, &timerid) != 0) {
perror("timer_create");
exit(EXIT_FAILURE);
}
if (timer_gettime(timerid, &out) != 0) {
perror("timer_gettime");
exit(EXIT_FAILURE);
}
printf("before timer start: %ld.%09ld\n",
out.it_value.tv_sec, out.it_value.tv_nsec);
/* Use absolute times to sidestep bug in older kernels. */
clock_gettime(which_clock, &ts);
in.it_value.tv_sec = ts.tv_sec + 3600;
in.it_value.tv_nsec = ts.tv_nsec;
in.it_interval.tv_sec = 0;
in.it_interval.tv_nsec = 0;
if (timer_settime(timerid, TIMER_ABSTIME, &in, NULL)) {
perror("timer_settime");
exit(EXIT_FAILURE);
}
for (i = 0; i < 3; ++i) {
if (timer_gettime(timerid, &out) != 0) {
perror("timer_gettime");
exit(EXIT_FAILURE);
}
printf("step %d: %ld.%09ld\n",
i, out.it_value.tv_sec, out.it_value.tv_nsec);
sleep(1);
}
in.it_value.tv_sec = ts.tv_sec;
in.it_value.tv_nsec = ts.tv_nsec;
in.it_interval.tv_sec = 0;
in.it_interval.tv_nsec = 0;
if (timer_settime(timerid, TIMER_ABSTIME, &in, NULL)) {
perror("timer_settime");
exit(EXIT_FAILURE);
}
if (timer_gettime(timerid, &out) != 0) {
perror("timer_gettime");
exit(EXIT_FAILURE);
}
printf("after expiry: %ld.%09ld\n",
out.it_value.tv_sec, out.it_value.tv_nsec);
timer_delete(timerid);
}
--------
ihrt16:~# ./timer_gettime_test
CLOCK_REALTIME
before timer start: 0.000000000
step 0: 3599.999987035
step 1: 3598.999824068
step 2: 3597.999588143
after expiry: 0.000000000
CLOCK_BOOTTIME
before timer start: 0.000000000
step 0: 3599.999996257
step 1: 3598.999871706
step 2: 3597.999753939
after expiry: 0.000000000
CLOCK_REALTIME_ALARM
before timer start: 0.000000000
step 0: 1410314715.145776868
step 1: 1410314715.145776868
step 2: 1410314715.145776868
[1]+ Stopped ./timer_gettime_test
ihrt16:~# fg
./timer_gettime_test
after expiry: 1410311115.145776868
CLOCK_BOOTTIME_ALARM
before timer start: 0.000000000
step 0: 3923.018128712
step 1: 3923.018128712
step 2: 3923.018128712
[1]+ Stopped ./timer_gettime_test
ihrt16:~# fg
./timer_gettime_test
after expiry: 323.018128712
ihrt16:~#
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 1/3] alarmtimer: Return relative times in timer_gettime
2014-09-10 1:31 [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior Richard Larocque
@ 2014-09-10 1:31 ` Richard Larocque
2014-09-10 1:31 ` [PATCH 2/3] alarmtimer: Do not signal SIGEV_NONE timers Richard Larocque
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Richard Larocque @ 2014-09-10 1:31 UTC (permalink / raw)
To: tglx, john.stultz; +Cc: linux-kernel, Richard Larocque
Returns the time remaining for an alarm timer, rather than the time at
which it is scheduled to expire. If the timer has already expired or it
is not currently scheduled, the it_value's members are set to zero.
This new behavior matches that of the other posix-timers and the POSIX
specifications.
This is a change in user-visible behavior, and may break existing
applications. Hopefully, few users rely on the old incorrect behavior.
Signed-off-by: Richard Larocque <rlarocque@google.com>
---
kernel/time/alarmtimer.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 4aec4a4..cb31fd0 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -541,18 +541,21 @@ static int alarm_timer_create(struct k_itimer *new_timer)
* @new_timer: k_itimer pointer
* @cur_setting: itimerspec data to fill
*
- * Copies the itimerspec data out from the k_itimer
+ * Copies out the current itimerspec data
*/
static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
- memset(cur_setting, 0, sizeof(struct itimerspec));
+ ktime_t relative_expiry_time =
+ alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
+ if (ktime_to_ns(relative_expiry_time) > 0) {
+ cur_setting->it_value = ktime_to_timespec(relative_expiry_time);
+ } else {
+ cur_setting->it_value.tv_sec = 0;
+ cur_setting->it_value.tv_nsec = 0;
+ }
- cur_setting->it_interval =
- ktime_to_timespec(timr->it.alarm.interval);
- cur_setting->it_value =
- ktime_to_timespec(timr->it.alarm.alarmtimer.node.expires);
- return;
+ cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval);
}
/**
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/3] alarmtimer: Do not signal SIGEV_NONE timers
2014-09-10 1:31 [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior Richard Larocque
2014-09-10 1:31 ` [PATCH 1/3] alarmtimer: Return relative times in timer_gettime Richard Larocque
@ 2014-09-10 1:31 ` Richard Larocque
2014-09-10 1:31 ` [PATCH 3/3] alarmtimer: Lock k_itimer during timer callback Richard Larocque
2014-09-10 3:33 ` [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior John Stultz
3 siblings, 0 replies; 6+ messages in thread
From: Richard Larocque @ 2014-09-10 1:31 UTC (permalink / raw)
To: tglx, john.stultz; +Cc: linux-kernel, Richard Larocque
Avoids sending a signal to alarm timers created with sigev_notify set to
SIGEV_NONE by checking for that special case in the timeout callback.
The regular posix timers avoid sending signals to SIGEV_NONE timers by
not scheduling any callbacks for them in the first place. Although it
would be possible to do something similar for alarm timers, it's simpler
to handle this as a special case in the timeout.
Prior to this patch, the alarm timer would ignore the sigev_notify value
and try to deliver signals to the process anyway. Even worse, the
sanity check for the value of sigev_signo is skipped when SIGEV_NONE was
specified, so the signal number could be bogus. If sigev_signo was an
unitialized value (as it often would be if SIGEV_NONE is used), then
it's hard to predict which signal will be sent.
Signed-off-by: Richard Larocque <rlarocque@google.com>
---
kernel/time/alarmtimer.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index cb31fd0..091d660 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -466,8 +466,10 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
{
struct k_itimer *ptr = container_of(alarm, struct k_itimer,
it.alarm.alarmtimer);
- if (posix_timer_event(ptr, 0) != 0)
- ptr->it_overrun++;
+ if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) {
+ if (posix_timer_event(ptr, 0) != 0)
+ ptr->it_overrun++;
+ }
/* Re-add periodic timers */
if (ptr->it.alarm.interval.tv64) {
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 3/3] alarmtimer: Lock k_itimer during timer callback
2014-09-10 1:31 [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior Richard Larocque
2014-09-10 1:31 ` [PATCH 1/3] alarmtimer: Return relative times in timer_gettime Richard Larocque
2014-09-10 1:31 ` [PATCH 2/3] alarmtimer: Do not signal SIGEV_NONE timers Richard Larocque
@ 2014-09-10 1:31 ` Richard Larocque
2014-09-10 3:33 ` [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior John Stultz
3 siblings, 0 replies; 6+ messages in thread
From: Richard Larocque @ 2014-09-10 1:31 UTC (permalink / raw)
To: tglx, john.stultz; +Cc: linux-kernel, Richard Larocque
Locks the k_itimer's it_lock member when handling the alarm timer's
expiry callback.
The regular posix timers defined in posix-timers.c have this lock held
during timout processing because their callbacks are routed through
posix_timer_fn(). The alarm timers follow a different path, so they
ought to grab the lock somewhere else.
Signed-off-by: Richard Larocque <rlarocque@google.com>
---
I'm not at all sure this makes sense. Feel free to drop this patch if the
extra locking is wrong or unnecessary. It's here for discussion purposes only.
It's not entirely clear to me what the it_lock is supposed to protect, but it
does seem very odd that the alarm timers don't hold it when their callback is
in progress, while the regular timers do hold it.
The comments at the top of the file specify that the it_lock should not be
modified by timer code, but I'm not sure that's applicable if the timer code
doesn't leverage posix_timer_fn(). Since the alarm timer's call to
posix_event_timer() goes through alarm_handle_timer() instead, nothing actually
grabs that lock before the call to posix_event_timer().
kernel/time/alarmtimer.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 091d660..5f5e5c9 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -464,8 +464,12 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid)
static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
ktime_t now)
{
+ unsigned long flags;
struct k_itimer *ptr = container_of(alarm, struct k_itimer,
it.alarm.alarmtimer);
+ enum alarmtimer_restart result = ALARMTIMER_NORESTART;
+
+ spin_lock_irqsave(&ptr->it_lock, flags);
if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) {
if (posix_timer_event(ptr, 0) != 0)
ptr->it_overrun++;
@@ -475,9 +479,11 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
if (ptr->it.alarm.interval.tv64) {
ptr->it_overrun += alarm_forward(alarm, now,
ptr->it.alarm.interval);
- return ALARMTIMER_RESTART;
+ result = ALARMTIMER_RESTART;
}
- return ALARMTIMER_NORESTART;
+ spin_unlock_irqrestore(&ptr->it_lock, flags);
+
+ return result;
}
/**
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior
2014-09-10 1:31 [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior Richard Larocque
` (2 preceding siblings ...)
2014-09-10 1:31 ` [PATCH 3/3] alarmtimer: Lock k_itimer during timer callback Richard Larocque
@ 2014-09-10 3:33 ` John Stultz
2014-09-10 17:40 ` Richard Larocque
3 siblings, 1 reply; 6+ messages in thread
From: John Stultz @ 2014-09-10 3:33 UTC (permalink / raw)
To: Richard Larocque; +Cc: Thomas Gleixner, lkml
On Tue, Sep 9, 2014 at 6:31 PM, Richard Larocque <rlarocque@google.com> wrote:
> I've been working on some changes to posix-timers.c in an attempt to better
> support CRIU. Along the way, I've discovered some issues with the posix alarm
> timers that should be fixed independent of any other work.
>
> It seems that there was an older issue with the setting of relative timeouts
> with timer_settime(). That was addressed around 3.16 with
> 16927776ae757d0d132bdbfabbfe2c498342bd59 ("alarmtimer: Fix bug where relative
> alarm timers were treated as absolute"). That fixed the setting of times, but
> it doesn't fix the retrieval of times.
>
> According to the man pages (and POSIX), timer_gettime() is supposed to return
> the time left until the timeout, not the absolute time at which the timeout is
> expected to fire. The non-ALARM clocks correctly show relative times, but
> CLOCK_BOOTTIME_ALARM and CLOCK_REALTIME_ALARM do not.
>
> A second issue with these timers is that they call posix_event_timer() without
> checking the value of it_sigev_notify. This is a problem, because
> it_sigev_notify could be SIGEV_NONE, in which case the signal should not be
> delivered. The non-alarm timers don't need to check it_sigev_notify in their
> timeout handling code path, because they never schedule timeouts for those
> kinds of timers in the first place.
>
> See below for a program that demonstrates these behaviors, and some sample output.
>
> The third patch in this stack is the odd one out. I suspect that there's
> a locking issue in the alarm timer code, and this is my attempt to fix it.
> It's not quite related to the first two, but it does conflict with one of them,
> so I figured I should include it in this patch stack.
Oof. More paper bags for me to wear. Thanks so much for discovering
these and providing these fixes.
I'll review and queue these up for my own testing and then send them
on (the locking one I'll have to look closely at). Do you mind if I
add a variant of your demo code to my timekeeping test suite?
thanks
-john
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior
2014-09-10 3:33 ` [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior John Stultz
@ 2014-09-10 17:40 ` Richard Larocque
0 siblings, 0 replies; 6+ messages in thread
From: Richard Larocque @ 2014-09-10 17:40 UTC (permalink / raw)
To: John Stultz; +Cc: Thomas Gleixner, lkml
On Tue, Sep 9, 2014 at 8:33 PM, John Stultz <john.stultz@linaro.org> wrote:
> On Tue, Sep 9, 2014 at 6:31 PM, Richard Larocque <rlarocque@google.com> wrote:
>> I've been working on some changes to posix-timers.c in an attempt to better
>> support CRIU. Along the way, I've discovered some issues with the posix alarm
>> timers that should be fixed independent of any other work.
>>
>> It seems that there was an older issue with the setting of relative timeouts
>> with timer_settime(). That was addressed around 3.16 with
>> 16927776ae757d0d132bdbfabbfe2c498342bd59 ("alarmtimer: Fix bug where relative
>> alarm timers were treated as absolute"). That fixed the setting of times, but
>> it doesn't fix the retrieval of times.
>>
>> According to the man pages (and POSIX), timer_gettime() is supposed to return
>> the time left until the timeout, not the absolute time at which the timeout is
>> expected to fire. The non-ALARM clocks correctly show relative times, but
>> CLOCK_BOOTTIME_ALARM and CLOCK_REALTIME_ALARM do not.
>>
>> A second issue with these timers is that they call posix_event_timer() without
>> checking the value of it_sigev_notify. This is a problem, because
>> it_sigev_notify could be SIGEV_NONE, in which case the signal should not be
>> delivered. The non-alarm timers don't need to check it_sigev_notify in their
>> timeout handling code path, because they never schedule timeouts for those
>> kinds of timers in the first place.
>>
>> See below for a program that demonstrates these behaviors, and some sample output.
>>
>> The third patch in this stack is the odd one out. I suspect that there's
>> a locking issue in the alarm timer code, and this is my attempt to fix it.
>> It's not quite related to the first two, but it does conflict with one of them,
>> so I figured I should include it in this patch stack.
>
> Oof. More paper bags for me to wear. Thanks so much for discovering
> these and providing these fixes.
>
> I'll review and queue these up for my own testing and then send them
> on (the locking one I'll have to look closely at). Do you mind if I
> add a variant of your demo code to my timekeeping test suite?
>
> thanks
> -john
Sure, use the testing code as you see fit. Let me know if you'd like
some boilerplate legalese statements to go along with it.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-09-10 17:40 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-10 1:31 [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior Richard Larocque
2014-09-10 1:31 ` [PATCH 1/3] alarmtimer: Return relative times in timer_gettime Richard Larocque
2014-09-10 1:31 ` [PATCH 2/3] alarmtimer: Do not signal SIGEV_NONE timers Richard Larocque
2014-09-10 1:31 ` [PATCH 3/3] alarmtimer: Lock k_itimer during timer callback Richard Larocque
2014-09-10 3:33 ` [PATCH 0/3] alarmtimer: Fix some non-standard alarm timer behavior John Stultz
2014-09-10 17:40 ` Richard Larocque
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome