aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToyo Abe <toyoa@mvista.com>2006-09-29 05:00:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 12:18:15 -0400
commite4b765551aa6355eae60b644bed851a9477c4e2b (patch)
treed1636c58e475407e2a770659430d54c7d67d72be
parent1711ef3866b0360e102327389fe4b76c849bbe83 (diff)
[PATCH] posix-timers: Fix the flags handling in posix_cpu_nsleep()
When a posix_cpu_nsleep() sleep is interrupted by a signal more than twice, it incorrectly reports the sleep time remaining to the user. Because posix_cpu_nsleep() doesn't report back to the user when it's called from restart function due to the wrong flags handling. This patch, which applies after previous one, moves the nanosleep() function from posix_cpu_nsleep() to do_cpu_nanosleep() and cleans up the flags handling appropriately. Signed-off-by: Toyo Abe <toyoa@mvista.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--kernel/posix-cpu-timers.c84
1 files changed, 58 insertions, 26 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 5667fef89dd1..479b16b44f79 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -1393,23 +1393,13 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
1393 } 1393 }
1394} 1394}
1395 1395
1396int posix_cpu_nsleep(const clockid_t which_clock, int flags, 1396static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
1397 struct timespec *rqtp, struct timespec __user *rmtp) 1397 struct timespec *rqtp, struct itimerspec *it)
1398{ 1398{
1399 struct restart_block *restart_block =
1400 &current_thread_info()->restart_block;
1401 struct k_itimer timer; 1399 struct k_itimer timer;
1402 int error; 1400 int error;
1403 1401
1404 /* 1402 /*
1405 * Diagnose required errors first.
1406 */
1407 if (CPUCLOCK_PERTHREAD(which_clock) &&
1408 (CPUCLOCK_PID(which_clock) == 0 ||
1409 CPUCLOCK_PID(which_clock) == current->pid))
1410 return -EINVAL;
1411
1412 /*
1413 * Set up a temporary timer and then wait for it to go off. 1403 * Set up a temporary timer and then wait for it to go off.
1414 */ 1404 */
1415 memset(&timer, 0, sizeof timer); 1405 memset(&timer, 0, sizeof timer);
@@ -1420,11 +1410,12 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
1420 timer.it_process = current; 1410 timer.it_process = current;
1421 if (!error) { 1411 if (!error) {
1422 static struct itimerspec zero_it; 1412 static struct itimerspec zero_it;
1423 struct itimerspec it = { .it_value = *rqtp, 1413
1424 .it_interval = {} }; 1414 memset(it, 0, sizeof *it);
1415 it->it_value = *rqtp;
1425 1416
1426 spin_lock_irq(&timer.it_lock); 1417 spin_lock_irq(&timer.it_lock);
1427 error = posix_cpu_timer_set(&timer, flags, &it, NULL); 1418 error = posix_cpu_timer_set(&timer, flags, it, NULL);
1428 if (error) { 1419 if (error) {
1429 spin_unlock_irq(&timer.it_lock); 1420 spin_unlock_irq(&timer.it_lock);
1430 return error; 1421 return error;
@@ -1452,33 +1443,56 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
1452 * We were interrupted by a signal. 1443 * We were interrupted by a signal.
1453 */ 1444 */
1454 sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); 1445 sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
1455 posix_cpu_timer_set(&timer, 0, &zero_it, &it); 1446 posix_cpu_timer_set(&timer, 0, &zero_it, it);
1456 spin_unlock_irq(&timer.it_lock); 1447 spin_unlock_irq(&timer.it_lock);
1457 1448
1458 if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) { 1449 if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {
1459 /* 1450 /*
1460 * It actually did fire already. 1451 * It actually did fire already.
1461 */ 1452 */
1462 return 0; 1453 return 0;
1463 } 1454 }
1464 1455
1456 error = -ERESTART_RESTARTBLOCK;
1457 }
1458
1459 return error;
1460}
1461
1462int posix_cpu_nsleep(const clockid_t which_clock, int flags,
1463 struct timespec *rqtp, struct timespec __user *rmtp)
1464{
1465 struct restart_block *restart_block =
1466 &current_thread_info()->restart_block;
1467 struct itimerspec it;
1468 int error;
1469
1470 /*
1471 * Diagnose required errors first.
1472 */
1473 if (CPUCLOCK_PERTHREAD(which_clock) &&
1474 (CPUCLOCK_PID(which_clock) == 0 ||
1475 CPUCLOCK_PID(which_clock) == current->pid))
1476 return -EINVAL;
1477
1478 error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
1479
1480 if (error == -ERESTART_RESTARTBLOCK) {
1481
1482 if (flags & TIMER_ABSTIME)
1483 return -ERESTARTNOHAND;
1465 /* 1484 /*
1466 * Report back to the user the time still remaining. 1485 * Report back to the user the time still remaining.
1467 */ 1486 */
1468 if (rmtp != NULL && !(flags & TIMER_ABSTIME) && 1487 if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
1469 copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
1470 return -EFAULT; 1488 return -EFAULT;
1471 1489
1472 restart_block->fn = posix_cpu_nsleep_restart; 1490 restart_block->fn = posix_cpu_nsleep_restart;
1473 /* Caller already set restart_block->arg1 */
1474 restart_block->arg0 = which_clock; 1491 restart_block->arg0 = which_clock;
1475 restart_block->arg1 = (unsigned long) rmtp; 1492 restart_block->arg1 = (unsigned long) rmtp;
1476 restart_block->arg2 = rqtp->tv_sec; 1493 restart_block->arg2 = rqtp->tv_sec;
1477 restart_block->arg3 = rqtp->tv_nsec; 1494 restart_block->arg3 = rqtp->tv_nsec;
1478
1479 error = -ERESTART_RESTARTBLOCK;
1480 } 1495 }
1481
1482 return error; 1496 return error;
1483} 1497}
1484 1498
@@ -1487,13 +1501,31 @@ long posix_cpu_nsleep_restart(struct restart_block *restart_block)
1487 clockid_t which_clock = restart_block->arg0; 1501 clockid_t which_clock = restart_block->arg0;
1488 struct timespec __user *rmtp; 1502 struct timespec __user *rmtp;
1489 struct timespec t; 1503 struct timespec t;
1504 struct itimerspec it;
1505 int error;
1490 1506
1491 rmtp = (struct timespec __user *) restart_block->arg1; 1507 rmtp = (struct timespec __user *) restart_block->arg1;
1492 t.tv_sec = restart_block->arg2; 1508 t.tv_sec = restart_block->arg2;
1493 t.tv_nsec = restart_block->arg3; 1509 t.tv_nsec = restart_block->arg3;
1494 1510
1495 restart_block->fn = do_no_restart_syscall; 1511 restart_block->fn = do_no_restart_syscall;
1496 return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t, rmtp); 1512 error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
1513
1514 if (error == -ERESTART_RESTARTBLOCK) {
1515 /*
1516 * Report back to the user the time still remaining.
1517 */
1518 if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
1519 return -EFAULT;
1520
1521 restart_block->fn = posix_cpu_nsleep_restart;
1522 restart_block->arg0 = which_clock;
1523 restart_block->arg1 = (unsigned long) rmtp;
1524 restart_block->arg2 = t.tv_sec;
1525 restart_block->arg3 = t.tv_nsec;
1526 }
1527 return error;
1528
1497} 1529}
1498 1530
1499 1531