diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/time/alarmtimer.c | 34 | ||||
| -rw-r--r-- | kernel/time/time.c | 56 |
2 files changed, 54 insertions, 36 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 4aec4a457431..a7077d3ae52f 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
| @@ -464,18 +464,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid) | |||
| 464 | static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, | 464 | static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, |
| 465 | ktime_t now) | 465 | ktime_t now) |
| 466 | { | 466 | { |
| 467 | unsigned long flags; | ||
| 467 | struct k_itimer *ptr = container_of(alarm, struct k_itimer, | 468 | struct k_itimer *ptr = container_of(alarm, struct k_itimer, |
| 468 | it.alarm.alarmtimer); | 469 | it.alarm.alarmtimer); |
| 469 | if (posix_timer_event(ptr, 0) != 0) | 470 | enum alarmtimer_restart result = ALARMTIMER_NORESTART; |
| 470 | ptr->it_overrun++; | 471 | |
| 472 | spin_lock_irqsave(&ptr->it_lock, flags); | ||
| 473 | if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) { | ||
| 474 | if (posix_timer_event(ptr, 0) != 0) | ||
| 475 | ptr->it_overrun++; | ||
| 476 | } | ||
| 471 | 477 | ||
| 472 | /* Re-add periodic timers */ | 478 | /* Re-add periodic timers */ |
| 473 | if (ptr->it.alarm.interval.tv64) { | 479 | if (ptr->it.alarm.interval.tv64) { |
| 474 | ptr->it_overrun += alarm_forward(alarm, now, | 480 | ptr->it_overrun += alarm_forward(alarm, now, |
| 475 | ptr->it.alarm.interval); | 481 | ptr->it.alarm.interval); |
| 476 | return ALARMTIMER_RESTART; | 482 | result = ALARMTIMER_RESTART; |
| 477 | } | 483 | } |
| 478 | return ALARMTIMER_NORESTART; | 484 | spin_unlock_irqrestore(&ptr->it_lock, flags); |
| 485 | |||
| 486 | return result; | ||
| 479 | } | 487 | } |
| 480 | 488 | ||
| 481 | /** | 489 | /** |
| @@ -541,18 +549,22 @@ static int alarm_timer_create(struct k_itimer *new_timer) | |||
| 541 | * @new_timer: k_itimer pointer | 549 | * @new_timer: k_itimer pointer |
| 542 | * @cur_setting: itimerspec data to fill | 550 | * @cur_setting: itimerspec data to fill |
| 543 | * | 551 | * |
| 544 | * Copies the itimerspec data out from the k_itimer | 552 | * Copies out the current itimerspec data |
| 545 | */ | 553 | */ |
| 546 | static void alarm_timer_get(struct k_itimer *timr, | 554 | static void alarm_timer_get(struct k_itimer *timr, |
| 547 | struct itimerspec *cur_setting) | 555 | struct itimerspec *cur_setting) |
| 548 | { | 556 | { |
| 549 | memset(cur_setting, 0, sizeof(struct itimerspec)); | 557 | ktime_t relative_expiry_time = |
| 558 | alarm_expires_remaining(&(timr->it.alarm.alarmtimer)); | ||
| 559 | |||
| 560 | if (ktime_to_ns(relative_expiry_time) > 0) { | ||
| 561 | cur_setting->it_value = ktime_to_timespec(relative_expiry_time); | ||
| 562 | } else { | ||
| 563 | cur_setting->it_value.tv_sec = 0; | ||
| 564 | cur_setting->it_value.tv_nsec = 0; | ||
| 565 | } | ||
| 550 | 566 | ||
| 551 | cur_setting->it_interval = | 567 | cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval); |
| 552 | ktime_to_timespec(timr->it.alarm.interval); | ||
| 553 | cur_setting->it_value = | ||
| 554 | ktime_to_timespec(timr->it.alarm.alarmtimer.node.expires); | ||
| 555 | return; | ||
| 556 | } | 568 | } |
| 557 | 569 | ||
| 558 | /** | 570 | /** |
diff --git a/kernel/time/time.c b/kernel/time/time.c index f0294ba14634..a9ae20fb0b11 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c | |||
| @@ -559,17 +559,20 @@ EXPORT_SYMBOL(usecs_to_jiffies); | |||
| 559 | * that a remainder subtract here would not do the right thing as the | 559 | * that a remainder subtract here would not do the right thing as the |
| 560 | * resolution values don't fall on second boundries. I.e. the line: | 560 | * resolution values don't fall on second boundries. I.e. the line: |
| 561 | * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. | 561 | * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. |
| 562 | * Note that due to the small error in the multiplier here, this | ||
| 563 | * rounding is incorrect for sufficiently large values of tv_nsec, but | ||
| 564 | * well formed timespecs should have tv_nsec < NSEC_PER_SEC, so we're | ||
| 565 | * OK. | ||
| 562 | * | 566 | * |
| 563 | * Rather, we just shift the bits off the right. | 567 | * Rather, we just shift the bits off the right. |
| 564 | * | 568 | * |
| 565 | * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec | 569 | * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec |
| 566 | * value to a scaled second value. | 570 | * value to a scaled second value. |
| 567 | */ | 571 | */ |
| 568 | unsigned long | 572 | static unsigned long |
| 569 | timespec_to_jiffies(const struct timespec *value) | 573 | __timespec_to_jiffies(unsigned long sec, long nsec) |
| 570 | { | 574 | { |
| 571 | unsigned long sec = value->tv_sec; | 575 | nsec = nsec + TICK_NSEC - 1; |
| 572 | long nsec = value->tv_nsec + TICK_NSEC - 1; | ||
| 573 | 576 | ||
| 574 | if (sec >= MAX_SEC_IN_JIFFIES){ | 577 | if (sec >= MAX_SEC_IN_JIFFIES){ |
| 575 | sec = MAX_SEC_IN_JIFFIES; | 578 | sec = MAX_SEC_IN_JIFFIES; |
| @@ -580,6 +583,13 @@ timespec_to_jiffies(const struct timespec *value) | |||
| 580 | (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; | 583 | (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; |
| 581 | 584 | ||
| 582 | } | 585 | } |
| 586 | |||
| 587 | unsigned long | ||
| 588 | timespec_to_jiffies(const struct timespec *value) | ||
| 589 | { | ||
| 590 | return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); | ||
| 591 | } | ||
| 592 | |||
| 583 | EXPORT_SYMBOL(timespec_to_jiffies); | 593 | EXPORT_SYMBOL(timespec_to_jiffies); |
| 584 | 594 | ||
| 585 | void | 595 | void |
| @@ -596,31 +606,27 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) | |||
| 596 | } | 606 | } |
| 597 | EXPORT_SYMBOL(jiffies_to_timespec); | 607 | EXPORT_SYMBOL(jiffies_to_timespec); |
| 598 | 608 | ||
| 599 | /* Same for "timeval" | 609 | /* |
| 600 | * | 610 | * We could use a similar algorithm to timespec_to_jiffies (with a |
| 601 | * Well, almost. The problem here is that the real system resolution is | 611 | * different multiplier for usec instead of nsec). But this has a |
| 602 | * in nanoseconds and the value being converted is in micro seconds. | 612 | * problem with rounding: we can't exactly add TICK_NSEC - 1 to the |
| 603 | * Also for some machines (those that use HZ = 1024, in-particular), | 613 | * usec value, since it's not necessarily integral. |
| 604 | * there is a LARGE error in the tick size in microseconds. | 614 | * |
| 605 | 615 | * We could instead round in the intermediate scaled representation | |
| 606 | * The solution we use is to do the rounding AFTER we convert the | 616 | * (i.e. in units of 1/2^(large scale) jiffies) but that's also |
| 607 | * microsecond part. Thus the USEC_ROUND, the bits to be shifted off. | 617 | * perilous: the scaling introduces a small positive error, which |
| 608 | * Instruction wise, this should cost only an additional add with carry | 618 | * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1 |
| 609 | * instruction above the way it was done above. | 619 | * units to the intermediate before shifting) leads to accidental |
| 620 | * overflow and overestimates. | ||
| 621 | * | ||
| 622 | * At the cost of one additional multiplication by a constant, just | ||
| 623 | * use the timespec implementation. | ||
| 610 | */ | 624 | */ |
| 611 | unsigned long | 625 | unsigned long |
| 612 | timeval_to_jiffies(const struct timeval *value) | 626 | timeval_to_jiffies(const struct timeval *value) |
| 613 | { | 627 | { |
| 614 | unsigned long sec = value->tv_sec; | 628 | return __timespec_to_jiffies(value->tv_sec, |
| 615 | long usec = value->tv_usec; | 629 | value->tv_usec * NSEC_PER_USEC); |
| 616 | |||
| 617 | if (sec >= MAX_SEC_IN_JIFFIES){ | ||
| 618 | sec = MAX_SEC_IN_JIFFIES; | ||
| 619 | usec = 0; | ||
| 620 | } | ||
| 621 | return (((u64)sec * SEC_CONVERSION) + | ||
| 622 | (((u64)usec * USEC_CONVERSION + USEC_ROUND) >> | ||
| 623 | (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; | ||
| 624 | } | 630 | } |
| 625 | EXPORT_SYMBOL(timeval_to_jiffies); | 631 | EXPORT_SYMBOL(timeval_to_jiffies); |
| 626 | 632 | ||
