[patch] nanosleep() fix for current bk

Andrew Morton (akpm@digeo.com)
Wed, 19 Mar 2003 22:26:33 -0800


This should fix up the various mysterious application failures which people
have been seeing (xmms, mplayer, DB2 at least).

A couple of things:

- if (rq_time <= get_jiffies_64())
- return 0;

That was unsafe against wrapping.

- if ((rq_time - get_jiffies_64()) > MAX_JIFFY_OFFSET){
- new_timer.expires = MAX_JIFFY_OFFSET;

This is the big one. get_jiffies_64() returns unsigned, so the whole
expression is promoted to unsigned. So if rq_time happens to be _before_
jiffies_64 we end up sleeping for 0x7ffffffe jiffies.

Also I think this calculation:

- if (abs || !rq_time){
- adjust_abs_time(&posix_clocks[which_clock], &t, abs);

- tstojiffie(&t, posix_clocks[which_clock].res, &rq_time);
- }

should be outside the loop, yes?

The thing I have not explained is why the failure could only be triggered
after 5 minutes uptime, when jiffies has become positive and when jiffies_64
is using the upper 32 bits. Can you see it??

kernel/posix-timers.c | 49 ++++++++++++++++++++++---------------------------
1 files changed, 22 insertions(+), 27 deletions(-)

diff -puN kernel/posix-timers.c~posix-timers-fixes kernel/posix-timers.c
--- 25/kernel/posix-timers.c~posix-timers-fixes 2003-03-19 20:39:59.000000000 -0800
+++ 25-akpm/kernel/posix-timers.c 2003-03-19 21:56:21.000000000 -0800
@@ -182,8 +182,7 @@ init_posix_timers(void)

__initcall(init_posix_timers);

-static inline int
-tstojiffie(struct timespec *tp, int res, u64 *jiff)
+static void tstojiffie(struct timespec *tp, int res, u64 *jiff)
{
unsigned long sec = tp->tv_sec;
long nsec = tp->tv_nsec + res - 1;
@@ -212,17 +211,14 @@ tstojiffie(struct timespec *tp, int res,
* Split to jiffie and sub jiffie
*/
*jiff += nsec / (NSEC_PER_SEC / HZ);
- /*
- * We trust that the optimizer will use the remainder from the
- * above div in the following operation as long as they are close.
- */
- return 0;
}
+
static void
tstotimer(struct itimerspec *time, struct k_itimer *timer)
{
u64 result;
int res = posix_clocks[timer->it_clock].res;
+
tstojiffie(&time->it_value, res, &result);
timer->it_timer.expires = (unsigned long)result;
tstojiffie(&time->it_interval, res, &result);
@@ -1195,6 +1191,7 @@ sys_clock_nanosleep(clockid_t which_cloc
return ret;

}
+
long
do_clock_nanosleep(clockid_t which_clock, int flags, struct timespec *tsave)
{
@@ -1225,30 +1222,30 @@ do_clock_nanosleep(clockid_t which_clock
rq_time = (rq_time << 32) + restart_block->arg2;
if (!rq_time)
return -EINTR;
- if (rq_time <= get_jiffies_64())
- return 0;
+ left = rq_time - get_jiffies_64();
+ if (left <= 0LL)
+ return 0; /* Already passed */
}

if (abs && (posix_clocks[which_clock].clock_get !=
posix_clocks[CLOCK_MONOTONIC].clock_get)) {
add_wait_queue(&nanosleep_abs_wqueue, &abs_wqueue);
}
- do {
- t = *tsave;
- if (abs || !rq_time){
- adjust_abs_time(&posix_clocks[which_clock], &t, abs);

- tstojiffie(&t, posix_clocks[which_clock].res, &rq_time);
- }
-#if (BITS_PER_LONG < 64)
- if ((rq_time - get_jiffies_64()) > MAX_JIFFY_OFFSET){
- new_timer.expires = MAX_JIFFY_OFFSET;
- }else
-#endif
- {
- new_timer.expires = (long)rq_time;
- }
- current->state = TASK_INTERRUPTIBLE;
+ t = *tsave;
+ if (abs || !rq_time) {
+ adjust_abs_time(&posix_clocks[which_clock], &t, abs);
+ tstojiffie(&t, posix_clocks[which_clock].res, &rq_time);
+ }
+
+ left = rq_time - get_jiffies_64();
+
+ while (left > 0 && !test_thread_flag(TIF_SIGPENDING)) {
+ if (left >= MAX_JIFFY_OFFSET)
+ left = MAX_JIFFY_OFFSET;
+
+ new_timer.expires = jiffies + left;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_timer(&new_timer);

schedule();
@@ -1256,10 +1253,8 @@ do_clock_nanosleep(clockid_t which_clock
del_timer_sync(&new_timer);
left = rq_time - get_jiffies_64();
}
- while ( (left > 0) &&
- !test_thread_flag(TIF_SIGPENDING));

- if( abs_wqueue.task_list.next)
+ if (abs_wqueue.task_list.next)
finish_wait(&nanosleep_abs_wqueue, &abs_wqueue);

if (left > 0) {

_

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/