On Sun, Apr 28, 2019 at 05:25:48PM -0400, Waiman Long wrote:
> When the front of the wait queue is a reader, other readers
> immediately following the first reader will also be woken up at the
> same time. However, if there is a writer in between. Those readers
> behind the writer will not be woken up.

> @@ -345,13 +359,20 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
>        * 2) For each waiters in the new list, clear waiter->task and
>        *    put them into wake_q to be woken up later.
>        */
> -     list_for_each_entry(waiter, &sem->wait_list, list) {
> +     INIT_LIST_HEAD(&wlist);
> +     list_for_each_entry_safe(waiter, tmp, &sem->wait_list, list) {
>               if (waiter->type == RWSEM_WAITING_FOR_WRITE)
> -                     break;
> +                     continue;
>  
>               woken++;
> +             list_move_tail(&waiter->list, &wlist);
> +
> +             /*
> +              * Limit # of readers that can be woken up per wakeup call.
> +              */
> +             if (woken >= MAX_READERS_WAKEUP)
> +                     break;
>       }
> -     list_cut_before(&wlist, &sem->wait_list, &waiter->list);
>  
>       adjustment = woken * RWSEM_READER_BIAS - adjustment;
>       lockevent_cond_inc(rwsem_wake_reader, woken);

An idea for later; maybe we can simplify this by playing silly games
with the queueing.

Writers: always list_add_tail()
Readers: keep a pointer to first_reader in the queue;
         when NULL; list_add_tail() and set
         otherwise: list_add_tail(, first_reader);

Possily also keep a count of first_reader list size, and if 'big' reset
first_reader.

That way we never have to skip over writers.

Reply via email to