aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/posix-timers.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/posix-timers.c')
-rw-r--r--kernel/posix-timers.c151
1 files changed, 27 insertions, 124 deletions
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 6b851a1bf4b0..ba900587b815 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -209,7 +209,8 @@ static inline int common_timer_create(struct k_itimer *new_timer)
209/* 209/*
210 * These ones are defined below. 210 * These ones are defined below.
211 */ 211 */
212static int common_nsleep(const clockid_t, int flags, struct timespec *t); 212static int common_nsleep(const clockid_t, int flags, struct timespec *t,
213 struct timespec __user *rmtp);
213static void common_timer_get(struct k_itimer *, struct itimerspec *); 214static void common_timer_get(struct k_itimer *, struct itimerspec *);
214static int common_timer_set(struct k_itimer *, int, 215static int common_timer_set(struct k_itimer *, int,
215 struct itimerspec *, struct itimerspec *); 216 struct itimerspec *, struct itimerspec *);
@@ -1227,7 +1228,7 @@ int do_posix_clock_notimer_create(struct k_itimer *timer)
1227EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create); 1228EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create);
1228 1229
1229int do_posix_clock_nonanosleep(const clockid_t clock, int flags, 1230int do_posix_clock_nonanosleep(const clockid_t clock, int flags,
1230 struct timespec *t) 1231 struct timespec *t, struct timespec __user *r)
1231{ 1232{
1232#ifndef ENOTSUP 1233#ifndef ENOTSUP
1233 return -EOPNOTSUPP; /* aka ENOTSUP in userland for POSIX */ 1234 return -EOPNOTSUPP; /* aka ENOTSUP in userland for POSIX */
@@ -1387,7 +1388,28 @@ void clock_was_set(void)
1387 up(&clock_was_set_lock); 1388 up(&clock_was_set_lock);
1388} 1389}
1389 1390
1390long clock_nanosleep_restart(struct restart_block *restart_block); 1391/*
1392 * nanosleep for monotonic and realtime clocks
1393 */
1394static int common_nsleep(const clockid_t which_clock, int flags,
1395 struct timespec *tsave, struct timespec __user *rmtp)
1396{
1397 int mode = flags & TIMER_ABSTIME ? HRTIMER_ABS : HRTIMER_REL;
1398 int clockid = which_clock;
1399
1400 switch (which_clock) {
1401 case CLOCK_REALTIME:
1402 /* Posix madness. Only absolute timers on clock realtime
1403 are affected by clock set. */
1404 if (mode == HRTIMER_ABS)
1405 clockid = CLOCK_MONOTONIC;
1406 case CLOCK_MONOTONIC:
1407 break;
1408 default:
1409 return -EINVAL;
1410 }
1411 return hrtimer_nanosleep(tsave, rmtp, mode, clockid);
1412}
1391 1413
1392asmlinkage long 1414asmlinkage long
1393sys_clock_nanosleep(const clockid_t which_clock, int flags, 1415sys_clock_nanosleep(const clockid_t which_clock, int flags,
@@ -1395,9 +1417,6 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags,
1395 struct timespec __user *rmtp) 1417 struct timespec __user *rmtp)
1396{ 1418{
1397 struct timespec t; 1419 struct timespec t;
1398 struct restart_block *restart_block =
1399 &(current_thread_info()->restart_block);
1400 int ret;
1401 1420
1402 if (invalid_clockid(which_clock)) 1421 if (invalid_clockid(which_clock))
1403 return -EINVAL; 1422 return -EINVAL;
@@ -1408,122 +1427,6 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags,
1408 if (!timespec_valid(&t)) 1427 if (!timespec_valid(&t))
1409 return -EINVAL; 1428 return -EINVAL;
1410 1429
1411 /* 1430 return CLOCK_DISPATCH(which_clock, nsleep,
1412 * Do this here as nsleep function does not have the real address. 1431 (which_clock, flags, &t, rmtp));
1413 */
1414 restart_block->arg1 = (unsigned long)rmtp;
1415
1416 ret = CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t));
1417
1418 if ((ret == -ERESTART_RESTARTBLOCK) && rmtp &&
1419 copy_to_user(rmtp, &t, sizeof (t)))
1420 return -EFAULT;
1421 return ret;
1422}
1423
1424
1425static int common_nsleep(const clockid_t which_clock,
1426 int flags, struct timespec *tsave)
1427{
1428 struct timespec t, dum;
1429 DECLARE_WAITQUEUE(abs_wqueue, current);
1430 u64 rq_time = (u64)0;
1431 s64 left;
1432 int abs;
1433 struct restart_block *restart_block =
1434 &current_thread_info()->restart_block;
1435
1436 abs_wqueue.flags = 0;
1437 abs = flags & TIMER_ABSTIME;
1438
1439 if (restart_block->fn == clock_nanosleep_restart) {
1440 /*
1441 * Interrupted by a non-delivered signal, pick up remaining
1442 * time and continue. Remaining time is in arg2 & 3.
1443 */
1444 restart_block->fn = do_no_restart_syscall;
1445
1446 rq_time = restart_block->arg3;
1447 rq_time = (rq_time << 32) + restart_block->arg2;
1448 if (!rq_time)
1449 return -EINTR;
1450 left = rq_time - get_jiffies_64();
1451 if (left <= (s64)0)
1452 return 0; /* Already passed */
1453 }
1454
1455 if (abs && (posix_clocks[which_clock].clock_get !=
1456 posix_clocks[CLOCK_MONOTONIC].clock_get))
1457 add_wait_queue(&nanosleep_abs_wqueue, &abs_wqueue);
1458
1459 do {
1460 t = *tsave;
1461 if (abs || !rq_time) {
1462 adjust_abs_time(&posix_clocks[which_clock], &t, abs,
1463 &rq_time, &dum);
1464 }
1465
1466 left = rq_time - get_jiffies_64();
1467 if (left >= (s64)MAX_JIFFY_OFFSET)
1468 left = (s64)MAX_JIFFY_OFFSET;
1469 if (left < (s64)0)
1470 break;
1471
1472 schedule_timeout_interruptible(left);
1473
1474 left = rq_time - get_jiffies_64();
1475 } while (left > (s64)0 && !test_thread_flag(TIF_SIGPENDING));
1476
1477 if (abs_wqueue.task_list.next)
1478 finish_wait(&nanosleep_abs_wqueue, &abs_wqueue);
1479
1480 if (left > (s64)0) {
1481
1482 /*
1483 * Always restart abs calls from scratch to pick up any
1484 * clock shifting that happened while we are away.
1485 */
1486 if (abs)
1487 return -ERESTARTNOHAND;
1488
1489 left *= TICK_NSEC;
1490 tsave->tv_sec = div_long_long_rem(left,
1491 NSEC_PER_SEC,
1492 &tsave->tv_nsec);
1493 /*
1494 * Restart works by saving the time remaing in
1495 * arg2 & 3 (it is 64-bits of jiffies). The other
1496 * info we need is the clock_id (saved in arg0).
1497 * The sys_call interface needs the users
1498 * timespec return address which _it_ saves in arg1.
1499 * Since we have cast the nanosleep call to a clock_nanosleep
1500 * both can be restarted with the same code.
1501 */
1502 restart_block->fn = clock_nanosleep_restart;
1503 restart_block->arg0 = which_clock;
1504 /*
1505 * Caller sets arg1
1506 */
1507 restart_block->arg2 = rq_time & 0xffffffffLL;
1508 restart_block->arg3 = rq_time >> 32;
1509
1510 return -ERESTART_RESTARTBLOCK;
1511 }
1512
1513 return 0;
1514}
1515/*
1516 * This will restart clock_nanosleep.
1517 */
1518long
1519clock_nanosleep_restart(struct restart_block *restart_block)
1520{
1521 struct timespec t;
1522 int ret = common_nsleep(restart_block->arg0, 0, &t);
1523
1524 if ((ret == -ERESTART_RESTARTBLOCK) && restart_block->arg1 &&
1525 copy_to_user((struct timespec __user *)(restart_block->arg1), &t,
1526 sizeof (t)))
1527 return -EFAULT;
1528 return ret;
1529} 1432}