lkml.org 
[lkml]   [2010]   [May]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 02/12] rwsem: use single atomic update for sem count when waking up readers.
    Date
    When waking up queued readers, __rwsem_do_wake was using a pair of atomic
    operations (one before looking at the first queued thread and one after
    having looped through all readers). Restructure code to use a single
    atomic operation instead.

    Signed-off-by: Michel Lespinasse <walken@google.com>
    ---
    lib/rwsem.c | 52 ++++++++++++++++++++++++++--------------------------
    1 files changed, 26 insertions(+), 26 deletions(-)

    diff --git a/lib/rwsem.c b/lib/rwsem.c
    index 8d6a13e..caee9b7 100644
    --- a/lib/rwsem.c
    +++ b/lib/rwsem.c
    @@ -41,7 +41,7 @@ struct rwsem_waiter {
    * - if we come here from up_xxxx(), then:
    * - the 'active part' of count (&0x0000ffff) reached 0 (but may have changed)
    * - the 'waiting part' of count (&0xffff0000) is -ve (and will still be so)
    - * - there must be someone on the queue
    + * - there must be someone on the queue
    * - the spinlock must be held by the caller
    * - woken process blocks are discarded from the list after having task zeroed
    * - writers are only woken if downgrading is false
    @@ -54,26 +54,26 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading)
    struct list_head *next;
    signed long oldcount, woken, loop;

    + waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
    + if (!(waiter->flags & RWSEM_WAITING_FOR_WRITE))
    + goto readers_only;
    +
    if (downgrading)
    - goto dont_wake_writers;
    + /* Caller's lock is still active, so we can't possibly
    + * succeed waking writers.
    + */
    + goto out;

    - /* if we came through an up_xxxx() call, we only only wake someone up
    + /* There's a writer at the front of the queue - try to grant it the
    + * write lock. However, we only only wake someone up
    * if we can transition the active part of the count from 0 -> 1
    */
    - try_again:
    + retry_writer:
    oldcount = rwsem_atomic_update(RWSEM_ACTIVE_BIAS, sem)
    - RWSEM_ACTIVE_BIAS;
    if (oldcount & RWSEM_ACTIVE_MASK)
    - goto undo;
    -
    - waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
    -
    - /* try to grant a single write lock if there's a writer at the front
    - * of the queue - note we leave the 'active part' of the count
    - * incremented by 1 and the waiting part incremented by 0x00010000
    - */
    - if (!(waiter->flags & RWSEM_WAITING_FOR_WRITE))
    - goto readers_only;
    + /* Someone grabbed the sem already */
    + goto undo_writer;

    /* We must be careful not to touch 'waiter' after we set ->task = NULL.
    * It is an allocated on the waiter's stack and may become invalid at
    @@ -87,12 +87,6 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading)
    put_task_struct(tsk);
    goto out;

    - /* don't want to wake any writers */
    - dont_wake_writers:
    - waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
    - if (waiter->flags & RWSEM_WAITING_FOR_WRITE)
    - goto out;
    -
    /* grant an infinite number of read locks to the readers at the front
    * of the queue
    * - note we increment the 'active part' of the count by the number of
    @@ -113,11 +107,12 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading)

    loop = woken;
    woken *= RWSEM_ACTIVE_BIAS - RWSEM_WAITING_BIAS;
    - if (!downgrading)
    - /* we'd already done one increment earlier */
    - woken -= RWSEM_ACTIVE_BIAS;

    - rwsem_atomic_add(woken, sem);
    + retry_readers:
    + oldcount = rwsem_atomic_update(woken, sem) - woken;
    + if (!downgrading && (oldcount & RWSEM_ACTIVE_MASK))
    + /* Someone grabbed the sem already */
    + goto undo_readers;

    next = sem->wait_list.next;
    for (; loop > 0; loop--) {
    @@ -137,10 +132,15 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading)
    return sem;

    /* undo the change to count, but check for a transition 1->0 */
    - undo:
    + undo_writer:
    if (rwsem_atomic_update(-RWSEM_ACTIVE_BIAS, sem) & RWSEM_ACTIVE_MASK)
    goto out;
    - goto try_again;
    + goto retry_writer;
    +
    + undo_readers:
    + if (rwsem_atomic_update(-woken, sem) & RWSEM_ACTIVE_MASK)
    + goto out;
    + goto retry_readers;
    }

    /*
    --
    1.7.0.1


    \
     
     \ /
      Last update: 2010-05-12 10:17    [W:0.035 / U:152.380 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site