Re: Read/write locks

Colin Plumb (colin@nyx.net)
Sun, 21 Sep 1997 01:20:47 -0600 (MDT)


David "Sparc" Miller wrote:
> Perhaps I'm feeling dense this evening, but what in the world is the
> difference then between holding the update lock and holding a rwlock
> as a writer? I can't see it...

The difference is that any number of readers may hold the lock at the
same time. An update lock does not conflict with a read lock.

It's the difference between an update lock and a read lock that is
more subtle. Only one update lock may exist at a time, and has
the ability to be upgraded to a write lock without dropping the lock.

So you can get an update lock, verify prerequisites for an operation
(gather all the necessary informatin prior to the first write), then
upgrade to a write lock and do the operation. (Alternatively, if you
detect an error, you can just drop the update lock.)

The rule is that write locks conflict with everything. If someone has
a write lock, that's the only lock there is.

An update lock conflicts with write and other update locks, but NOT with
read locks.

Read locks conflict only with write locks.

The holder of the update lock has "dibs" on the write lock, but doesn't
need to kick other readers out of the data structure yet.

One thing some poeple do is to forbid granting additional read locks
while an update lock is held, but allow the currently active readers
to finish. This doesn't help readers, but makes writers faster, since
they can get useful work done while writers are finishing.

That could be done very easily in asm-i386/spinlock.h by splitting write_lock
into two halves. Getting an update lock sets the high-order bit of the
lock word (forbidding anyone else from entering), while the second spins
until the low 32 bits are all zero.

I.e.
#define update_lock(rw) \
asm volatine("\n1:\t" \
"lock; btsl $31,%0\n\t" \
"jc 2f\n" \
".section .text.lock,\"ax\"\n" \
"2:\tcmpl $0,%0\n\t" \
"js 2b\n\t" \
"jmp 1b\n" \
".previous" \
:"=m" (__dummy_lock(&(rw)->lock)))

#define update_to_write_lock(rw) \
asm volatine("\n1:\t" \
"testl $0x7fffffff,%0\n\t" \
"jne 1b" \
:"=m" (__dummy_lock(&(rw)->lock)))
And, of course,
#define write_lock(rw) update_lock(rw); update_to_write_lock(rw)

The one difference is that the previous code lets new readers in while
a writer is spinning waiting for readers to exit, while this code does not;
while a writer is waiting for readers to exit, the lock is held and new
readers may not enter.

-- 
	-Colin