On Thu, 15 May 2014 08:47:09 +0200
Ingo Molnar <mi...@kernel.org> wrote:

> 
> A couple of suggestions:
> 
> 1)
> 
> * Thomas Gleixner <t...@linutronix.de> wrote:
> 
> > +   if (requeue) {
> > +           if (waiter == rt_mutex_top_waiter(lock)) {
> 
> So we have a 'top_waiter' local variable already at this point, and we 
> use it here:
> 
> > +                   /* Boost the owner */
> > +                   rt_mutex_dequeue_pi(task, top_waiter);
> > +                   rt_mutex_enqueue_pi(task, waiter);
> > +                   __rt_mutex_adjust_prio(task);
> > +
> > +           } else if (top_waiter == waiter) {
> 
> To me it's a bit confusing that we have both the 'top_waiter' local 
> variable and also evaluate 'rt_mutex_top_waiter()' directly.
> 
> So what happens is that when we do the requeue, the top waiter might 
> change. I'd really suggest to signal that via naming - i.e. add 
> another local variable (which GCC will optimize out happily), named 
> descriptively:
> 
>       orig_top_waiter = top_waiter;
> 
> and use that variable after that point.

I wouldn't use "orig_top_waiter" as all the "orig_*" variables are
passed in via the parameters and do not change.

Maybe: last_top_waiter?


> 
> > +                   /* Deboost the owner */
> > +                   rt_mutex_dequeue_pi(task, waiter);
> > +                   waiter = rt_mutex_top_waiter(lock);
> > +                   rt_mutex_enqueue_pi(task, waiter);
> > +                   __rt_mutex_adjust_prio(task);
> > +           }
> >     }
> 
> 2)
> 
> Also another small flow of control side comment, because this code is 
> apparently rather tricky, I'd suggest a bit more explicit structure to 
> show the real flow of the logic: for example in the first reading of 
> the above block I mistakenly read it as a usual 'if () { } else { }' 
> block pattern - which it really isn't.
> 
> Something like this would be slightly easier to understand 'at a 
> glance', IMHO:
> 
>       if (requeue) {
>               if (waiter == top_waiter) {
>                       /* Boost the owner */
>                       rt_mutex_dequeue_pi(task, orig_top_waiter);
>                       rt_mutex_enqueue_pi(task, waiter);
>                       __rt_mutex_adjust_prio(task);
> 
>               } else {
>                       if (orig_top_waiter == waiter) {
>                               /* Deboost the owner */
>                               rt_mutex_dequeue_pi(task, waiter);
>                               waiter = rt_mutex_top_waiter(lock);
>                               rt_mutex_enqueue_pi(task, waiter);
>                               __rt_mutex_adjust_prio(task);
>                       } else {
>                               /* The requeueing did not affect us, no need to 
> boost or deboost */
>                       }
>               }
>       }
> 
> Assuming you agree with this structure, it's a bit more verbose, but 
> this might be one of the cases where verbosity helps readability. 
> (Note that I already propagated the 'orig_top_waiter' name into it.)

Instead of the nesting, what about:

        if (requeue) {
                if (waiter == top_waiter) {
                        /* Boost the owner */
                        rt_mutex_dequeue_pi(task, last_top_waiter);
                        rt_mutex_enqueue_pi(task, waiter);
                        __rt_mutex_adjust_prio(task);

                } else if (last_top_waiter == waiter) {
                        /* Deboost the owner */
                        rt_mutex_dequeue_pi(task, waiter);
                        waiter = rt_mutex_top_waiter(lock);
                        rt_mutex_enqueue_pi(task, waiter);
                        __rt_mutex_adjust_prio(task);
                } else {
                        /*
                         * The requeueing did not affect us, no need to
                         * boost or deboost
                         */
                }
        }

That last else should also visually keep one from thinking this is a
simple "if { } else { }" construct.

(Note that I already propagated the 'last_top_waiter' name into it ;-)

                

> 
> 3)
> 
> Also note how the code continues:
> 
>         raw_spin_unlock_irqrestore(&task->pi_lock, flags);
> 
>         top_waiter = rt_mutex_top_waiter(lock);
>         raw_spin_unlock(&lock->wait_lock);
> 
>         if (!detect_deadlock && waiter != top_waiter)
>                 goto out_put_task;
> 
>         goto again;
> 
> So we evaluate 'top_waiter' again - maybe we could move that line to 
> the two branches that actually have a chance to change the top waiter, 
> and not change it in the 'no need to requeue' case.

This is probably a good idea and needs my change I suggested earlier
(which doesn't do the wakeup if requeue == 0).

-- Steve

> 
> So ... all in one, what I would suggest is something like the patch 
> below, on top of your two patches. Totally untested and such.
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to