diff options
Diffstat (limited to 'kernel/posix-cpu-timers.c')
| -rw-r--r-- | kernel/posix-cpu-timers.c | 91 |
1 files changed, 52 insertions, 39 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index ad85d3f0dcc4..bf374fceb39c 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c | |||
| @@ -91,7 +91,7 @@ static inline union cpu_time_count cpu_time_sub(clockid_t which_clock, | |||
| 91 | * Update expiry time from increment, and increase overrun count, | 91 | * Update expiry time from increment, and increase overrun count, |
| 92 | * given the current clock sample. | 92 | * given the current clock sample. |
| 93 | */ | 93 | */ |
| 94 | static inline void bump_cpu_timer(struct k_itimer *timer, | 94 | static void bump_cpu_timer(struct k_itimer *timer, |
| 95 | union cpu_time_count now) | 95 | union cpu_time_count now) |
| 96 | { | 96 | { |
| 97 | int i; | 97 | int i; |
| @@ -110,7 +110,7 @@ static inline void bump_cpu_timer(struct k_itimer *timer, | |||
| 110 | for (i = 0; incr < delta - incr; i++) | 110 | for (i = 0; incr < delta - incr; i++) |
| 111 | incr = incr << 1; | 111 | incr = incr << 1; |
| 112 | for (; i >= 0; incr >>= 1, i--) { | 112 | for (; i >= 0; incr >>= 1, i--) { |
| 113 | if (delta <= incr) | 113 | if (delta < incr) |
| 114 | continue; | 114 | continue; |
| 115 | timer->it.cpu.expires.sched += incr; | 115 | timer->it.cpu.expires.sched += incr; |
| 116 | timer->it_overrun += 1 << i; | 116 | timer->it_overrun += 1 << i; |
| @@ -128,7 +128,7 @@ static inline void bump_cpu_timer(struct k_itimer *timer, | |||
| 128 | for (i = 0; cputime_lt(incr, cputime_sub(delta, incr)); i++) | 128 | for (i = 0; cputime_lt(incr, cputime_sub(delta, incr)); i++) |
| 129 | incr = cputime_add(incr, incr); | 129 | incr = cputime_add(incr, incr); |
| 130 | for (; i >= 0; incr = cputime_halve(incr), i--) { | 130 | for (; i >= 0; incr = cputime_halve(incr), i--) { |
| 131 | if (cputime_le(delta, incr)) | 131 | if (cputime_lt(delta, incr)) |
| 132 | continue; | 132 | continue; |
| 133 | timer->it.cpu.expires.cpu = | 133 | timer->it.cpu.expires.cpu = |
| 134 | cputime_add(timer->it.cpu.expires.cpu, incr); | 134 | cputime_add(timer->it.cpu.expires.cpu, incr); |
| @@ -380,14 +380,9 @@ int posix_cpu_timer_create(struct k_itimer *new_timer) | |||
| 380 | int posix_cpu_timer_del(struct k_itimer *timer) | 380 | int posix_cpu_timer_del(struct k_itimer *timer) |
| 381 | { | 381 | { |
| 382 | struct task_struct *p = timer->it.cpu.task; | 382 | struct task_struct *p = timer->it.cpu.task; |
| 383 | int ret = 0; | ||
| 383 | 384 | ||
| 384 | if (timer->it.cpu.firing) | 385 | if (likely(p != NULL)) { |
| 385 | return TIMER_RETRY; | ||
| 386 | |||
| 387 | if (unlikely(p == NULL)) | ||
| 388 | return 0; | ||
| 389 | |||
| 390 | if (!list_empty(&timer->it.cpu.entry)) { | ||
| 391 | read_lock(&tasklist_lock); | 386 | read_lock(&tasklist_lock); |
| 392 | if (unlikely(p->signal == NULL)) { | 387 | if (unlikely(p->signal == NULL)) { |
| 393 | /* | 388 | /* |
| @@ -396,18 +391,20 @@ int posix_cpu_timer_del(struct k_itimer *timer) | |||
| 396 | */ | 391 | */ |
| 397 | BUG_ON(!list_empty(&timer->it.cpu.entry)); | 392 | BUG_ON(!list_empty(&timer->it.cpu.entry)); |
| 398 | } else { | 393 | } else { |
| 399 | /* | ||
| 400 | * Take us off the task's timer list. | ||
| 401 | */ | ||
| 402 | spin_lock(&p->sighand->siglock); | 394 | spin_lock(&p->sighand->siglock); |
| 403 | list_del(&timer->it.cpu.entry); | 395 | if (timer->it.cpu.firing) |
| 396 | ret = TIMER_RETRY; | ||
| 397 | else | ||
| 398 | list_del(&timer->it.cpu.entry); | ||
| 404 | spin_unlock(&p->sighand->siglock); | 399 | spin_unlock(&p->sighand->siglock); |
| 405 | } | 400 | } |
| 406 | read_unlock(&tasklist_lock); | 401 | read_unlock(&tasklist_lock); |
| 402 | |||
| 403 | if (!ret) | ||
| 404 | put_task_struct(p); | ||
| 407 | } | 405 | } |
| 408 | put_task_struct(p); | ||
| 409 | 406 | ||
| 410 | return 0; | 407 | return ret; |
| 411 | } | 408 | } |
| 412 | 409 | ||
| 413 | /* | 410 | /* |
| @@ -424,7 +421,6 @@ static void cleanup_timers(struct list_head *head, | |||
| 424 | cputime_t ptime = cputime_add(utime, stime); | 421 | cputime_t ptime = cputime_add(utime, stime); |
| 425 | 422 | ||
| 426 | list_for_each_entry_safe(timer, next, head, entry) { | 423 | list_for_each_entry_safe(timer, next, head, entry) { |
| 427 | timer->task = NULL; | ||
| 428 | list_del_init(&timer->entry); | 424 | list_del_init(&timer->entry); |
| 429 | if (cputime_lt(timer->expires.cpu, ptime)) { | 425 | if (cputime_lt(timer->expires.cpu, ptime)) { |
| 430 | timer->expires.cpu = cputime_zero; | 426 | timer->expires.cpu = cputime_zero; |
| @@ -436,7 +432,6 @@ static void cleanup_timers(struct list_head *head, | |||
| 436 | 432 | ||
| 437 | ++head; | 433 | ++head; |
| 438 | list_for_each_entry_safe(timer, next, head, entry) { | 434 | list_for_each_entry_safe(timer, next, head, entry) { |
| 439 | timer->task = NULL; | ||
| 440 | list_del_init(&timer->entry); | 435 | list_del_init(&timer->entry); |
| 441 | if (cputime_lt(timer->expires.cpu, utime)) { | 436 | if (cputime_lt(timer->expires.cpu, utime)) { |
| 442 | timer->expires.cpu = cputime_zero; | 437 | timer->expires.cpu = cputime_zero; |
| @@ -448,7 +443,6 @@ static void cleanup_timers(struct list_head *head, | |||
| 448 | 443 | ||
| 449 | ++head; | 444 | ++head; |
| 450 | list_for_each_entry_safe(timer, next, head, entry) { | 445 | list_for_each_entry_safe(timer, next, head, entry) { |
| 451 | timer->task = NULL; | ||
| 452 | list_del_init(&timer->entry); | 446 | list_del_init(&timer->entry); |
| 453 | if (timer->expires.sched < sched_time) { | 447 | if (timer->expires.sched < sched_time) { |
| 454 | timer->expires.sched = 0; | 448 | timer->expires.sched = 0; |
| @@ -492,6 +486,9 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 492 | struct task_struct *t = p; | 486 | struct task_struct *t = p; |
| 493 | unsigned int nthreads = atomic_read(&p->signal->live); | 487 | unsigned int nthreads = atomic_read(&p->signal->live); |
| 494 | 488 | ||
| 489 | if (!nthreads) | ||
| 490 | return; | ||
| 491 | |||
| 495 | switch (clock_idx) { | 492 | switch (clock_idx) { |
| 496 | default: | 493 | default: |
| 497 | BUG(); | 494 | BUG(); |
| @@ -500,7 +497,7 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 500 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), | 497 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), |
| 501 | nthreads); | 498 | nthreads); |
| 502 | do { | 499 | do { |
| 503 | if (!unlikely(t->exit_state)) { | 500 | if (!unlikely(t->flags & PF_EXITING)) { |
| 504 | ticks = cputime_add(prof_ticks(t), left); | 501 | ticks = cputime_add(prof_ticks(t), left); |
| 505 | if (cputime_eq(t->it_prof_expires, | 502 | if (cputime_eq(t->it_prof_expires, |
| 506 | cputime_zero) || | 503 | cputime_zero) || |
| @@ -515,7 +512,7 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 515 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), | 512 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), |
| 516 | nthreads); | 513 | nthreads); |
| 517 | do { | 514 | do { |
| 518 | if (!unlikely(t->exit_state)) { | 515 | if (!unlikely(t->flags & PF_EXITING)) { |
| 519 | ticks = cputime_add(virt_ticks(t), left); | 516 | ticks = cputime_add(virt_ticks(t), left); |
| 520 | if (cputime_eq(t->it_virt_expires, | 517 | if (cputime_eq(t->it_virt_expires, |
| 521 | cputime_zero) || | 518 | cputime_zero) || |
| @@ -530,7 +527,7 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 530 | nsleft = expires.sched - val.sched; | 527 | nsleft = expires.sched - val.sched; |
| 531 | do_div(nsleft, nthreads); | 528 | do_div(nsleft, nthreads); |
| 532 | do { | 529 | do { |
| 533 | if (!unlikely(t->exit_state)) { | 530 | if (!unlikely(t->flags & PF_EXITING)) { |
| 534 | ns = t->sched_time + nsleft; | 531 | ns = t->sched_time + nsleft; |
| 535 | if (t->it_sched_expires == 0 || | 532 | if (t->it_sched_expires == 0 || |
| 536 | t->it_sched_expires > ns) { | 533 | t->it_sched_expires > ns) { |
| @@ -569,6 +566,9 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now) | |||
| 569 | struct cpu_timer_list *next; | 566 | struct cpu_timer_list *next; |
| 570 | unsigned long i; | 567 | unsigned long i; |
| 571 | 568 | ||
| 569 | if (CPUCLOCK_PERTHREAD(timer->it_clock) && (p->flags & PF_EXITING)) | ||
| 570 | return; | ||
| 571 | |||
| 572 | head = (CPUCLOCK_PERTHREAD(timer->it_clock) ? | 572 | head = (CPUCLOCK_PERTHREAD(timer->it_clock) ? |
| 573 | p->cpu_timers : p->signal->cpu_timers); | 573 | p->cpu_timers : p->signal->cpu_timers); |
| 574 | head += CPUCLOCK_WHICH(timer->it_clock); | 574 | head += CPUCLOCK_WHICH(timer->it_clock); |
| @@ -579,17 +579,15 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now) | |||
| 579 | listpos = head; | 579 | listpos = head; |
| 580 | if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) { | 580 | if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) { |
| 581 | list_for_each_entry(next, head, entry) { | 581 | list_for_each_entry(next, head, entry) { |
| 582 | if (next->expires.sched > nt->expires.sched) { | 582 | if (next->expires.sched > nt->expires.sched) |
| 583 | listpos = &next->entry; | ||
| 584 | break; | 583 | break; |
| 585 | } | 584 | listpos = &next->entry; |
| 586 | } | 585 | } |
| 587 | } else { | 586 | } else { |
| 588 | list_for_each_entry(next, head, entry) { | 587 | list_for_each_entry(next, head, entry) { |
| 589 | if (cputime_gt(next->expires.cpu, nt->expires.cpu)) { | 588 | if (cputime_gt(next->expires.cpu, nt->expires.cpu)) |
| 590 | listpos = &next->entry; | ||
| 591 | break; | 589 | break; |
| 592 | } | 590 | listpos = &next->entry; |
| 593 | } | 591 | } |
| 594 | } | 592 | } |
| 595 | list_add(&nt->entry, listpos); | 593 | list_add(&nt->entry, listpos); |
| @@ -733,9 +731,15 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, | |||
| 733 | * Disarm any old timer after extracting its expiry time. | 731 | * Disarm any old timer after extracting its expiry time. |
| 734 | */ | 732 | */ |
| 735 | BUG_ON(!irqs_disabled()); | 733 | BUG_ON(!irqs_disabled()); |
| 734 | |||
| 735 | ret = 0; | ||
| 736 | spin_lock(&p->sighand->siglock); | 736 | spin_lock(&p->sighand->siglock); |
| 737 | old_expires = timer->it.cpu.expires; | 737 | old_expires = timer->it.cpu.expires; |
| 738 | list_del_init(&timer->it.cpu.entry); | 738 | if (unlikely(timer->it.cpu.firing)) { |
| 739 | timer->it.cpu.firing = -1; | ||
| 740 | ret = TIMER_RETRY; | ||
| 741 | } else | ||
| 742 | list_del_init(&timer->it.cpu.entry); | ||
| 739 | spin_unlock(&p->sighand->siglock); | 743 | spin_unlock(&p->sighand->siglock); |
| 740 | 744 | ||
| 741 | /* | 745 | /* |
| @@ -783,7 +787,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, | |||
| 783 | } | 787 | } |
| 784 | } | 788 | } |
| 785 | 789 | ||
| 786 | if (unlikely(timer->it.cpu.firing)) { | 790 | if (unlikely(ret)) { |
| 787 | /* | 791 | /* |
| 788 | * We are colliding with the timer actually firing. | 792 | * We are colliding with the timer actually firing. |
| 789 | * Punt after filling in the timer's old value, and | 793 | * Punt after filling in the timer's old value, and |
| @@ -791,8 +795,6 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags, | |||
| 791 | * it as an overrun (thanks to bump_cpu_timer above). | 795 | * it as an overrun (thanks to bump_cpu_timer above). |
| 792 | */ | 796 | */ |
| 793 | read_unlock(&tasklist_lock); | 797 | read_unlock(&tasklist_lock); |
| 794 | timer->it.cpu.firing = -1; | ||
| 795 | ret = TIMER_RETRY; | ||
| 796 | goto out; | 798 | goto out; |
| 797 | } | 799 | } |
| 798 | 800 | ||
| @@ -958,14 +960,16 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) | |||
| 958 | static void check_thread_timers(struct task_struct *tsk, | 960 | static void check_thread_timers(struct task_struct *tsk, |
| 959 | struct list_head *firing) | 961 | struct list_head *firing) |
| 960 | { | 962 | { |
| 963 | int maxfire; | ||
| 961 | struct list_head *timers = tsk->cpu_timers; | 964 | struct list_head *timers = tsk->cpu_timers; |
| 962 | 965 | ||
| 966 | maxfire = 20; | ||
| 963 | tsk->it_prof_expires = cputime_zero; | 967 | tsk->it_prof_expires = cputime_zero; |
| 964 | while (!list_empty(timers)) { | 968 | while (!list_empty(timers)) { |
| 965 | struct cpu_timer_list *t = list_entry(timers->next, | 969 | struct cpu_timer_list *t = list_entry(timers->next, |
| 966 | struct cpu_timer_list, | 970 | struct cpu_timer_list, |
| 967 | entry); | 971 | entry); |
| 968 | if (cputime_lt(prof_ticks(tsk), t->expires.cpu)) { | 972 | if (!--maxfire || cputime_lt(prof_ticks(tsk), t->expires.cpu)) { |
| 969 | tsk->it_prof_expires = t->expires.cpu; | 973 | tsk->it_prof_expires = t->expires.cpu; |
| 970 | break; | 974 | break; |
| 971 | } | 975 | } |
| @@ -974,12 +978,13 @@ static void check_thread_timers(struct task_struct *tsk, | |||
| 974 | } | 978 | } |
| 975 | 979 | ||
| 976 | ++timers; | 980 | ++timers; |
| 981 | maxfire = 20; | ||
| 977 | tsk->it_virt_expires = cputime_zero; | 982 | tsk->it_virt_expires = cputime_zero; |
| 978 | while (!list_empty(timers)) { | 983 | while (!list_empty(timers)) { |
| 979 | struct cpu_timer_list *t = list_entry(timers->next, | 984 | struct cpu_timer_list *t = list_entry(timers->next, |
| 980 | struct cpu_timer_list, | 985 | struct cpu_timer_list, |
| 981 | entry); | 986 | entry); |
| 982 | if (cputime_lt(virt_ticks(tsk), t->expires.cpu)) { | 987 | if (!--maxfire || cputime_lt(virt_ticks(tsk), t->expires.cpu)) { |
| 983 | tsk->it_virt_expires = t->expires.cpu; | 988 | tsk->it_virt_expires = t->expires.cpu; |
| 984 | break; | 989 | break; |
| 985 | } | 990 | } |
| @@ -988,12 +993,13 @@ static void check_thread_timers(struct task_struct *tsk, | |||
| 988 | } | 993 | } |
| 989 | 994 | ||
| 990 | ++timers; | 995 | ++timers; |
| 996 | maxfire = 20; | ||
| 991 | tsk->it_sched_expires = 0; | 997 | tsk->it_sched_expires = 0; |
| 992 | while (!list_empty(timers)) { | 998 | while (!list_empty(timers)) { |
| 993 | struct cpu_timer_list *t = list_entry(timers->next, | 999 | struct cpu_timer_list *t = list_entry(timers->next, |
| 994 | struct cpu_timer_list, | 1000 | struct cpu_timer_list, |
| 995 | entry); | 1001 | entry); |
| 996 | if (tsk->sched_time < t->expires.sched) { | 1002 | if (!--maxfire || tsk->sched_time < t->expires.sched) { |
| 997 | tsk->it_sched_expires = t->expires.sched; | 1003 | tsk->it_sched_expires = t->expires.sched; |
| 998 | break; | 1004 | break; |
| 999 | } | 1005 | } |
| @@ -1010,6 +1016,7 @@ static void check_thread_timers(struct task_struct *tsk, | |||
| 1010 | static void check_process_timers(struct task_struct *tsk, | 1016 | static void check_process_timers(struct task_struct *tsk, |
| 1011 | struct list_head *firing) | 1017 | struct list_head *firing) |
| 1012 | { | 1018 | { |
| 1019 | int maxfire; | ||
| 1013 | struct signal_struct *const sig = tsk->signal; | 1020 | struct signal_struct *const sig = tsk->signal; |
| 1014 | cputime_t utime, stime, ptime, virt_expires, prof_expires; | 1021 | cputime_t utime, stime, ptime, virt_expires, prof_expires; |
| 1015 | unsigned long long sched_time, sched_expires; | 1022 | unsigned long long sched_time, sched_expires; |
| @@ -1042,12 +1049,13 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1042 | } while (t != tsk); | 1049 | } while (t != tsk); |
| 1043 | ptime = cputime_add(utime, stime); | 1050 | ptime = cputime_add(utime, stime); |
| 1044 | 1051 | ||
| 1052 | maxfire = 20; | ||
| 1045 | prof_expires = cputime_zero; | 1053 | prof_expires = cputime_zero; |
| 1046 | while (!list_empty(timers)) { | 1054 | while (!list_empty(timers)) { |
| 1047 | struct cpu_timer_list *t = list_entry(timers->next, | 1055 | struct cpu_timer_list *t = list_entry(timers->next, |
| 1048 | struct cpu_timer_list, | 1056 | struct cpu_timer_list, |
| 1049 | entry); | 1057 | entry); |
| 1050 | if (cputime_lt(ptime, t->expires.cpu)) { | 1058 | if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) { |
| 1051 | prof_expires = t->expires.cpu; | 1059 | prof_expires = t->expires.cpu; |
| 1052 | break; | 1060 | break; |
| 1053 | } | 1061 | } |
| @@ -1056,12 +1064,13 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1056 | } | 1064 | } |
| 1057 | 1065 | ||
| 1058 | ++timers; | 1066 | ++timers; |
| 1067 | maxfire = 20; | ||
| 1059 | virt_expires = cputime_zero; | 1068 | virt_expires = cputime_zero; |
| 1060 | while (!list_empty(timers)) { | 1069 | while (!list_empty(timers)) { |
| 1061 | struct cpu_timer_list *t = list_entry(timers->next, | 1070 | struct cpu_timer_list *t = list_entry(timers->next, |
| 1062 | struct cpu_timer_list, | 1071 | struct cpu_timer_list, |
| 1063 | entry); | 1072 | entry); |
| 1064 | if (cputime_lt(utime, t->expires.cpu)) { | 1073 | if (!--maxfire || cputime_lt(utime, t->expires.cpu)) { |
| 1065 | virt_expires = t->expires.cpu; | 1074 | virt_expires = t->expires.cpu; |
| 1066 | break; | 1075 | break; |
| 1067 | } | 1076 | } |
| @@ -1070,12 +1079,13 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1070 | } | 1079 | } |
| 1071 | 1080 | ||
| 1072 | ++timers; | 1081 | ++timers; |
| 1082 | maxfire = 20; | ||
| 1073 | sched_expires = 0; | 1083 | sched_expires = 0; |
| 1074 | while (!list_empty(timers)) { | 1084 | while (!list_empty(timers)) { |
| 1075 | struct cpu_timer_list *t = list_entry(timers->next, | 1085 | struct cpu_timer_list *t = list_entry(timers->next, |
| 1076 | struct cpu_timer_list, | 1086 | struct cpu_timer_list, |
| 1077 | entry); | 1087 | entry); |
| 1078 | if (sched_time < t->expires.sched) { | 1088 | if (!--maxfire || sched_time < t->expires.sched) { |
| 1079 | sched_expires = t->expires.sched; | 1089 | sched_expires = t->expires.sched; |
| 1080 | break; | 1090 | break; |
| 1081 | } | 1091 | } |
| @@ -1158,6 +1168,9 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1158 | unsigned long long sched_left, sched; | 1168 | unsigned long long sched_left, sched; |
| 1159 | const unsigned int nthreads = atomic_read(&sig->live); | 1169 | const unsigned int nthreads = atomic_read(&sig->live); |
| 1160 | 1170 | ||
| 1171 | if (!nthreads) | ||
| 1172 | return; | ||
| 1173 | |||
| 1161 | prof_left = cputime_sub(prof_expires, utime); | 1174 | prof_left = cputime_sub(prof_expires, utime); |
| 1162 | prof_left = cputime_sub(prof_left, stime); | 1175 | prof_left = cputime_sub(prof_left, stime); |
| 1163 | prof_left = cputime_div(prof_left, nthreads); | 1176 | prof_left = cputime_div(prof_left, nthreads); |
| @@ -1194,7 +1207,7 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1194 | 1207 | ||
| 1195 | do { | 1208 | do { |
| 1196 | t = next_thread(t); | 1209 | t = next_thread(t); |
| 1197 | } while (unlikely(t->exit_state)); | 1210 | } while (unlikely(t->flags & PF_EXITING)); |
| 1198 | } while (t != tsk); | 1211 | } while (t != tsk); |
| 1199 | } | 1212 | } |
| 1200 | } | 1213 | } |
