Skip to content

Commit

Permalink
arch/tile: fix rwlock so would-be write lockers don't block new readers
Browse files Browse the repository at this point in the history
This avoids a deadlock in the IGMP code where one core gets a read
lock, another core starts trying to get a write lock (thus blocking
new readers), and then the first core tries to recursively re-acquire
the read lock.

We still try to preserve some degree of balance by giving priority
to additional write lockers that come along while the lock is held
for write, so they can all complete quickly and return the lock to
the readers.

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
  • Loading branch information
Chris Metcalf committed Nov 15, 2010
1 parent d02db4f commit 24f3f6b
Showing 1 changed file with 18 additions and 11 deletions.
29 changes: 18 additions & 11 deletions arch/tile/lib/spinlock_32.c
Original file line number Diff line number Diff line change
@@ -167,23 +167,30 @@ void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val)
* when we compare them.
*/
u32 my_ticket_;
u32 iterations = 0;

/* Take out the next ticket; this will also stop would-be readers. */
if (val & 1)
val = get_rwlock(rwlock);
rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
/*
* Wait until there are no readers, then bump up the next
* field and capture the ticket value.
*/
for (;;) {
if (!(val & 1)) {
if ((val >> RD_COUNT_SHIFT) == 0)
break;
rwlock->lock = val;
}
delay_backoff(iterations++);
val = __insn_tns((int *)&rwlock->lock);
}

/* Extract my ticket value from the original word. */
/* Take out the next ticket and extract my ticket value. */
rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
my_ticket_ = val >> WR_NEXT_SHIFT;

/*
* Wait until the "current" field matches our ticket, and
* there are no remaining readers.
*/
/* Wait until the "current" field matches our ticket. */
for (;;) {
u32 curr_ = val >> WR_CURR_SHIFT;
u32 readers = val >> RD_COUNT_SHIFT;
u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers;
u32 delta = ((my_ticket_ - curr_) & WR_MASK);
if (likely(delta == 0))
break;

0 comments on commit 24f3f6b

Please sign in to comment.