diff options
Diffstat (limited to 'kernel/posix-timers.c')
| -rw-r--r-- | kernel/posix-timers.c | 40 | 
1 files changed, 22 insertions, 18 deletions
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index dbd8398ddb0b..e36d5798cbff 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c  | |||
| @@ -289,21 +289,29 @@ void do_schedule_next_timer(struct siginfo *info) | |||
| 289 | else | 289 | else | 
| 290 | schedule_next_timer(timr); | 290 | schedule_next_timer(timr); | 
| 291 | 291 | ||
| 292 | info->si_overrun = timr->it_overrun_last; | 292 | info->si_overrun += timr->it_overrun_last; | 
| 293 | } | 293 | } | 
| 294 | 294 | ||
| 295 | if (timr) | 295 | if (timr) | 
| 296 | unlock_timer(timr, flags); | 296 | unlock_timer(timr, flags); | 
| 297 | } | 297 | } | 
| 298 | 298 | ||
| 299 | int posix_timer_event(struct k_itimer *timr,int si_private) | 299 | int posix_timer_event(struct k_itimer *timr, int si_private) | 
| 300 | { | 300 | { | 
| 301 | memset(&timr->sigq->info, 0, sizeof(siginfo_t)); | 301 | /* | 
| 302 | * FIXME: if ->sigq is queued we can race with | ||
| 303 | * dequeue_signal()->do_schedule_next_timer(). | ||
| 304 | * | ||
| 305 | * If dequeue_signal() sees the "right" value of | ||
| 306 | * si_sys_private it calls do_schedule_next_timer(). | ||
| 307 | * We re-queue ->sigq and drop ->it_lock(). | ||
| 308 | * do_schedule_next_timer() locks the timer | ||
| 309 | * and re-schedules it while ->sigq is pending. | ||
| 310 | * Not really bad, but not that we want. | ||
| 311 | */ | ||
| 302 | timr->sigq->info.si_sys_private = si_private; | 312 | timr->sigq->info.si_sys_private = si_private; | 
| 303 | /* Send signal to the process that owns this timer.*/ | ||
| 304 | 313 | ||
| 305 | timr->sigq->info.si_signo = timr->it_sigev_signo; | 314 | timr->sigq->info.si_signo = timr->it_sigev_signo; | 
| 306 | timr->sigq->info.si_errno = 0; | ||
| 307 | timr->sigq->info.si_code = SI_TIMER; | 315 | timr->sigq->info.si_code = SI_TIMER; | 
| 308 | timr->sigq->info.si_tid = timr->it_id; | 316 | timr->sigq->info.si_tid = timr->it_id; | 
| 309 | timr->sigq->info.si_value = timr->it_sigev_value; | 317 | timr->sigq->info.si_value = timr->it_sigev_value; | 
| @@ -435,6 +443,7 @@ static struct k_itimer * alloc_posix_timer(void) | |||
| 435 | kmem_cache_free(posix_timers_cache, tmr); | 443 | kmem_cache_free(posix_timers_cache, tmr); | 
| 436 | tmr = NULL; | 444 | tmr = NULL; | 
| 437 | } | 445 | } | 
| 446 | memset(&tmr->sigq->info, 0, sizeof(siginfo_t)); | ||
| 438 | return tmr; | 447 | return tmr; | 
| 439 | } | 448 | } | 
| 440 | 449 | ||
| @@ -449,9 +458,6 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set) | |||
| 449 | spin_unlock_irqrestore(&idr_lock, flags); | 458 | spin_unlock_irqrestore(&idr_lock, flags); | 
| 450 | } | 459 | } | 
| 451 | sigqueue_free(tmr->sigq); | 460 | sigqueue_free(tmr->sigq); | 
| 452 | if (unlikely(tmr->it_process) && | ||
| 453 | tmr->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) | ||
| 454 | put_task_struct(tmr->it_process); | ||
| 455 | kmem_cache_free(posix_timers_cache, tmr); | 461 | kmem_cache_free(posix_timers_cache, tmr); | 
| 456 | } | 462 | } | 
| 457 | 463 | ||
| @@ -856,11 +862,10 @@ retry_delete: | |||
| 856 | * This keeps any tasks waiting on the spin lock from thinking | 862 | * This keeps any tasks waiting on the spin lock from thinking | 
| 857 | * they got something (see the lock code above). | 863 | * they got something (see the lock code above). | 
| 858 | */ | 864 | */ | 
| 859 | if (timer->it_process) { | 865 | if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) | 
| 860 | if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) | 866 | put_task_struct(timer->it_process); | 
| 861 | put_task_struct(timer->it_process); | 867 | timer->it_process = NULL; | 
| 862 | timer->it_process = NULL; | 868 | |
| 863 | } | ||
| 864 | unlock_timer(timer, flags); | 869 | unlock_timer(timer, flags); | 
| 865 | release_posix_timer(timer, IT_ID_SET); | 870 | release_posix_timer(timer, IT_ID_SET); | 
| 866 | return 0; | 871 | return 0; | 
| @@ -885,11 +890,10 @@ retry_delete: | |||
| 885 | * This keeps any tasks waiting on the spin lock from thinking | 890 | * This keeps any tasks waiting on the spin lock from thinking | 
| 886 | * they got something (see the lock code above). | 891 | * they got something (see the lock code above). | 
| 887 | */ | 892 | */ | 
| 888 | if (timer->it_process) { | 893 | if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) | 
| 889 | if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) | 894 | put_task_struct(timer->it_process); | 
| 890 | put_task_struct(timer->it_process); | 895 | timer->it_process = NULL; | 
| 891 | timer->it_process = NULL; | 896 | |
| 892 | } | ||
| 893 | unlock_timer(timer, flags); | 897 | unlock_timer(timer, flags); | 
| 894 | release_posix_timer(timer, IT_ID_SET); | 898 | release_posix_timer(timer, IT_ID_SET); | 
| 895 | } | 899 | } | 
