diff options
Diffstat (limited to 'kernel/posix-timers.c')
-rw-r--r-- | kernel/posix-timers.c | 151 |
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 | */ |
212 | static int common_nsleep(const clockid_t, int flags, struct timespec *t); | 212 | static int common_nsleep(const clockid_t, int flags, struct timespec *t, |
213 | struct timespec __user *rmtp); | ||
213 | static void common_timer_get(struct k_itimer *, struct itimerspec *); | 214 | static void common_timer_get(struct k_itimer *, struct itimerspec *); |
214 | static int common_timer_set(struct k_itimer *, int, | 215 | static 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) | |||
1227 | EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create); | 1228 | EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create); |
1228 | 1229 | ||
1229 | int do_posix_clock_nonanosleep(const clockid_t clock, int flags, | 1230 | int 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 | ||
1390 | long clock_nanosleep_restart(struct restart_block *restart_block); | 1391 | /* |
1392 | * nanosleep for monotonic and realtime clocks | ||
1393 | */ | ||
1394 | static 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 | ||
1392 | asmlinkage long | 1414 | asmlinkage long |
1393 | sys_clock_nanosleep(const clockid_t which_clock, int flags, | 1415 | sys_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 | |||
1425 | static 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 | ¤t_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 | */ | ||
1518 | long | ||
1519 | clock_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 | } |