Merge branches 'timers/clocksource', 'timers/hrtimers', 'timers/nohz', 'timers/ntp', 'timers/posixtimers' and 'timers/debug' into v28-timers-for-linus
This commit is contained in:
@@ -313,6 +313,7 @@ void do_schedule_next_timer(struct siginfo *info)
|
||||
|
||||
int posix_timer_event(struct k_itimer *timr, int si_private)
|
||||
{
|
||||
int shared, ret;
|
||||
/*
|
||||
* FIXME: if ->sigq is queued we can race with
|
||||
* dequeue_signal()->do_schedule_next_timer().
|
||||
@@ -326,25 +327,10 @@ int posix_timer_event(struct k_itimer *timr, int si_private)
|
||||
*/
|
||||
timr->sigq->info.si_sys_private = si_private;
|
||||
|
||||
timr->sigq->info.si_signo = timr->it_sigev_signo;
|
||||
timr->sigq->info.si_code = SI_TIMER;
|
||||
timr->sigq->info.si_tid = timr->it_id;
|
||||
timr->sigq->info.si_value = timr->it_sigev_value;
|
||||
|
||||
if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
|
||||
struct task_struct *leader;
|
||||
int ret = send_sigqueue(timr->sigq, timr->it_process, 0);
|
||||
|
||||
if (likely(ret >= 0))
|
||||
return ret;
|
||||
|
||||
timr->it_sigev_notify = SIGEV_SIGNAL;
|
||||
leader = timr->it_process->group_leader;
|
||||
put_task_struct(timr->it_process);
|
||||
timr->it_process = leader;
|
||||
}
|
||||
|
||||
return send_sigqueue(timr->sigq, timr->it_process, 1);
|
||||
shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);
|
||||
ret = send_sigqueue(timr->sigq, timr->it_process, shared);
|
||||
/* If we failed to send the signal the timer stops. */
|
||||
return ret > 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(posix_timer_event);
|
||||
|
||||
@@ -456,7 +442,7 @@ static struct k_itimer * alloc_posix_timer(void)
|
||||
return tmr;
|
||||
if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
|
||||
kmem_cache_free(posix_timers_cache, tmr);
|
||||
tmr = NULL;
|
||||
return NULL;
|
||||
}
|
||||
memset(&tmr->sigq->info, 0, sizeof(siginfo_t));
|
||||
return tmr;
|
||||
@@ -483,11 +469,9 @@ sys_timer_create(const clockid_t which_clock,
|
||||
struct sigevent __user *timer_event_spec,
|
||||
timer_t __user * created_timer_id)
|
||||
{
|
||||
int error = 0;
|
||||
struct k_itimer *new_timer = NULL;
|
||||
int new_timer_id;
|
||||
struct task_struct *process = NULL;
|
||||
unsigned long flags;
|
||||
struct k_itimer *new_timer;
|
||||
int error, new_timer_id;
|
||||
struct task_struct *process;
|
||||
sigevent_t event;
|
||||
int it_id_set = IT_ID_NOT_SET;
|
||||
|
||||
@@ -505,12 +489,11 @@ sys_timer_create(const clockid_t which_clock,
|
||||
goto out;
|
||||
}
|
||||
spin_lock_irq(&idr_lock);
|
||||
error = idr_get_new(&posix_timers_id, (void *) new_timer,
|
||||
&new_timer_id);
|
||||
error = idr_get_new(&posix_timers_id, new_timer, &new_timer_id);
|
||||
spin_unlock_irq(&idr_lock);
|
||||
if (error == -EAGAIN)
|
||||
goto retry;
|
||||
else if (error) {
|
||||
if (error) {
|
||||
if (error == -EAGAIN)
|
||||
goto retry;
|
||||
/*
|
||||
* Weird looking, but we return EAGAIN if the IDR is
|
||||
* full (proper POSIX return value for this)
|
||||
@@ -541,67 +524,43 @@ sys_timer_create(const clockid_t which_clock,
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
new_timer->it_sigev_notify = event.sigev_notify;
|
||||
new_timer->it_sigev_signo = event.sigev_signo;
|
||||
new_timer->it_sigev_value = event.sigev_value;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if ((process = good_sigevent(&event))) {
|
||||
/*
|
||||
* We may be setting up this process for another
|
||||
* thread. It may be exiting. To catch this
|
||||
* case the we check the PF_EXITING flag. If
|
||||
* the flag is not set, the siglock will catch
|
||||
* him before it is too late (in exit_itimers).
|
||||
*
|
||||
* The exec case is a bit more invloved but easy
|
||||
* to code. If the process is in our thread
|
||||
* group (and it must be or we would not allow
|
||||
* it here) and is doing an exec, it will cause
|
||||
* us to be killed. In this case it will wait
|
||||
* for us to die which means we can finish this
|
||||
* linkage with our last gasp. I.e. no code :)
|
||||
*/
|
||||
spin_lock_irqsave(&process->sighand->siglock, flags);
|
||||
if (!(process->flags & PF_EXITING)) {
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list,
|
||||
&process->signal->posix_timers);
|
||||
if (new_timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
get_task_struct(process);
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
process = NULL;
|
||||
}
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
rcu_read_lock();
|
||||
process = good_sigevent(&event);
|
||||
if (process)
|
||||
get_task_struct(process);
|
||||
rcu_read_unlock();
|
||||
if (!process) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
new_timer->it_sigev_notify = SIGEV_SIGNAL;
|
||||
new_timer->it_sigev_signo = SIGALRM;
|
||||
new_timer->it_sigev_value.sival_int = new_timer->it_id;
|
||||
event.sigev_notify = SIGEV_SIGNAL;
|
||||
event.sigev_signo = SIGALRM;
|
||||
event.sigev_value.sival_int = new_timer->it_id;
|
||||
process = current->group_leader;
|
||||
spin_lock_irqsave(&process->sighand->siglock, flags);
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list, &process->signal->posix_timers);
|
||||
spin_unlock_irqrestore(&process->sighand->siglock, flags);
|
||||
get_task_struct(process);
|
||||
}
|
||||
|
||||
new_timer->it_sigev_notify = event.sigev_notify;
|
||||
new_timer->sigq->info.si_signo = event.sigev_signo;
|
||||
new_timer->sigq->info.si_value = event.sigev_value;
|
||||
new_timer->sigq->info.si_tid = new_timer->it_id;
|
||||
new_timer->sigq->info.si_code = SI_TIMER;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
new_timer->it_process = process;
|
||||
list_add(&new_timer->list, ¤t->signal->posix_timers);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* In the case of the timer belonging to another task, after
|
||||
* the task is unlocked, the timer is owned by the other task
|
||||
* and may cease to exist at any time. Don't use or modify
|
||||
* new_timer after the unlock call.
|
||||
*/
|
||||
|
||||
out:
|
||||
if (error)
|
||||
release_posix_timer(new_timer, it_id_set);
|
||||
|
||||
release_posix_timer(new_timer, it_id_set);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -612,7 +571,7 @@ out:
|
||||
* the find to the timer lock. To avoid a dead lock, the timer id MUST
|
||||
* be release with out holding the timer lock.
|
||||
*/
|
||||
static struct k_itimer * lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
{
|
||||
struct k_itimer *timr;
|
||||
/*
|
||||
@@ -620,23 +579,20 @@ static struct k_itimer * lock_timer(timer_t timer_id, unsigned long *flags)
|
||||
* flags part over to the timer lock. Must not let interrupts in
|
||||
* while we are moving the lock.
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&idr_lock, *flags);
|
||||
timr = (struct k_itimer *) idr_find(&posix_timers_id, (int) timer_id);
|
||||
timr = idr_find(&posix_timers_id, (int)timer_id);
|
||||
if (timr) {
|
||||
spin_lock(&timr->it_lock);
|
||||
|
||||
if ((timr->it_id != timer_id) || !(timr->it_process) ||
|
||||
!same_thread_group(timr->it_process, current)) {
|
||||
spin_unlock(&timr->it_lock);
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
timr = NULL;
|
||||
} else
|
||||
if (timr->it_process &&
|
||||
same_thread_group(timr->it_process, current)) {
|
||||
spin_unlock(&idr_lock);
|
||||
} else
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
return timr;
|
||||
}
|
||||
spin_unlock(&timr->it_lock);
|
||||
}
|
||||
spin_unlock_irqrestore(&idr_lock, *flags);
|
||||
|
||||
return timr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -877,8 +833,7 @@ retry_delete:
|
||||
* This keeps any tasks waiting on the spin lock from thinking
|
||||
* they got something (see the lock code above).
|
||||
*/
|
||||
if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
put_task_struct(timer->it_process);
|
||||
put_task_struct(timer->it_process);
|
||||
timer->it_process = NULL;
|
||||
|
||||
unlock_timer(timer, flags);
|
||||
@@ -905,8 +860,7 @@ retry_delete:
|
||||
* This keeps any tasks waiting on the spin lock from thinking
|
||||
* they got something (see the lock code above).
|
||||
*/
|
||||
if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
|
||||
put_task_struct(timer->it_process);
|
||||
put_task_struct(timer->it_process);
|
||||
timer->it_process = NULL;
|
||||
|
||||
unlock_timer(timer, flags);
|
||||
|
||||
Reference in New Issue
Block a user