* [parisc-linux] some more questions about __raw_write_trylock() hppa implementation
@ 2006-08-30 20:23 Joel Soete
2006-08-31 3:59 ` Matthew Wilcox
0 siblings, 1 reply; 11+ messages in thread
From: Joel Soete @ 2006-08-30 20:23 UTC (permalink / raw)
To: parisc-linux
Hello all,
I noticed that:
static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
{
__raw_spin_lock(&rw->lock);
if (rw->counter != 0) {
/* this basically never happens */
__raw_spin_unlock(&rw->lock);
return 0;
}
/* got it. now leave without unlocking */
rw->counter = -1; /* remember we are locked */
return 1;
}
so depending the counter is null or not the lock is kept or relaxed?
following my smp pb invextigation the pb I encounter seems to occure rarely and so according to above comment "/* this basically
never happens */" I place here a panic() in the hope to get a better trace if it start to hang by this place. Unfortunately the
comment is wrong and system panicing at boot time ;-(
Looking to some other implementation (powerpc and sh in particular), I don't have the feeling that this fnct should have to keep the
lock in any case. Any idea?
Thanks,
Joel
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-30 20:23 [parisc-linux] some more questions about __raw_write_trylock() hppa implementation Joel Soete @ 2006-08-31 3:59 ` Matthew Wilcox 2006-08-31 6:06 ` Grant Grundler 0 siblings, 1 reply; 11+ messages in thread From: Matthew Wilcox @ 2006-08-31 3:59 UTC (permalink / raw) To: Joel Soete; +Cc: parisc-linux On Wed, Aug 30, 2006 at 08:23:39PM +0000, Joel Soete wrote: > Hello all, > > I noticed that: > static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) > { > __raw_spin_lock(&rw->lock); > if (rw->counter != 0) { > /* this basically never happens */ > __raw_spin_unlock(&rw->lock); > > return 0; > } > > /* got it. now leave without unlocking */ > rw->counter = -1; /* remember we are locked */ > return 1; > } > > > so depending the counter is null or not the lock is kept or relaxed? > > following my smp pb invextigation the pb I encounter seems to occure rarely > and so according to above comment "/* this basically never happens */" I > place here a panic() in the hope to get a better trace if it start to hang > by this place. Unfortunately the comment is wrong and system panicing at > boot time ;-( The comment isn't wrong. It just means that the contention only happens when there's actual write-lock contention. > Looking to some other implementation (powerpc and sh in particular), I > don't have the feeling that this fnct should have to keep the lock in any > case. Any idea? That's how it works. Write locks keep the spinlock locked, read locks release it. Actually, there is a problem with the write locks that I noticed during replying to this mail the first time. Then palinux crashed. How ironic. Grant and I are fixing that right now ... _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 3:59 ` Matthew Wilcox @ 2006-08-31 6:06 ` Grant Grundler 2006-08-31 12:31 ` Matthew Wilcox 0 siblings, 1 reply; 11+ messages in thread From: Grant Grundler @ 2006-08-31 6:06 UTC (permalink / raw) To: Matthew Wilcox; +Cc: parisc-linux On Wed, Aug 30, 2006 at 09:59:32PM -0600, Matthew Wilcox wrote: > Actually, there is a problem with the write locks that I > noticed during replying to this mail the first time. > Then palinux crashed. How ironic. > Grant and I are fixing that right now ... Willy, Here's the patch I ended up with. Diff is also parked on gsyprf11:~grundler/diff-2.6.18-rc4-pa4-rwlocks-01 This is currently running on iodine (a500-5x). I don't know how this needs to be tested other than running "make -j4" on the kernel build. Maybe glibc/toolchain build? Please feel free to apply with your own commit comment, additional changes, and S-o-B line. And kudos for catching this. It's another non-trivial problem that's been around for a while. thanks, grant Commit Comment: We can't use generic__raw_read_trylock() since that will hang instead of returning a failure if the rwlock->lock isn't available. Similarly, __raw_write_trylock() is broken in that it would hang too instead of returning a failure. Signed-off-by: Grant Grundler <grundler@parisc-linux.org> diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index a93960e..d4048a6 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -60,7 +60,6 @@ static inline int __raw_spin_trylock(raw * but only one writer. */ -#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) /* read_lock, read_unlock are pretty straightforward. Of course it somehow * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */ @@ -68,19 +67,25 @@ #define __raw_read_trylock(lock) generic static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { __raw_spin_lock(&rw->lock); - rw->counter++; - __raw_spin_unlock(&rw->lock); } static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { __raw_spin_lock(&rw->lock); - rw->counter--; + __raw_spin_unlock(&rw->lock); +} + +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) +{ + if (!__raw_spin_trylock(&rw->lock)) + return 0; + rw->counter++; __raw_spin_unlock(&rw->lock); + return 1; } /* write_lock is less trivial. We optimistically grab the lock and check @@ -121,15 +126,15 @@ static __inline__ void __raw_write_unlo static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); + if (!__raw_spin_trylock(&rw->lock)) + return 0; + if (rw->counter != 0) { - /* this basically never happens */ __raw_spin_unlock(&rw->lock); ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 6:06 ` Grant Grundler @ 2006-08-31 12:31 ` Matthew Wilcox 2006-08-31 13:01 ` Michael S. Zick 2006-08-31 16:27 ` Grant Grundler 0 siblings, 2 replies; 11+ messages in thread From: Matthew Wilcox @ 2006-08-31 12:31 UTC (permalink / raw) To: Grant Grundler; +Cc: parisc-linux On Thu, Aug 31, 2006 at 12:06:37AM -0600, Grant Grundler wrote: > Here's the patch I ended up with. > Diff is also parked on gsyprf11:~grundler/diff-2.6.18-rc4-pa4-rwlocks-01 > > +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) > +{ > + if (!__raw_spin_trylock(&rw->lock)) > + return 0; > > + rw->counter++; > __raw_spin_unlock(&rw->lock); > + return 1; > } This has the false failure problem. ie if another CPU is doing a read_lock() at the same time, it will fail to acquire the lock, even though it would succeed if it tried again. I don't know if we have any code which depends upon that not failing, but it does seem a bit suboptimal. Fixing this is somewhat Hard. My original suggestion was this: retry: if (__raw_spin_trylock(&rw->lock)) { rw->counter++; __raw_spin_unlock(&rw->lock); return 1; } else if (rw->counter < 0) { return 0; } else { goto retry; } But this leads to deadlock if called from interrupt context and the CPU had got to: static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { retry: __raw_spin_lock(&rw->lock); <<<- here and hadn't set counter to -1. Now, we can fix that: static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { unsigned long flags; retry: local_irq_save(flags); __raw_spin_lock(&rw->lock); if (rw->counter != 0) { /* this basically never happens */ __raw_spin_unlock(&rw->lock); local_irq_restore(flags); while (rw->counter != 0) cpu_relax(); goto retry; } /* got it. now leave without unlocking */ rw->counter = -1; /* remember we are locked */ local_irq_restore(flags); } A similar change has to be made to __raw_write_trylock too: static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { unsigned long flags; int result = 0; local_irq_save(flags); if (__raw_spin_trylock(&rw->lock)) { if (rw->counter == 0) { rw->counter = -1; result = 1; } else { __raw_spin_unlock(&rw->lock); } } local_irq_restore(flags); return result; } Better ideas, anyone? (And perhaps more importantly, anyone spot any holes in my reasoning? I'm not too happy disabling interrupts *after* disabling preemption. And of course, we disable interrupts twice when called with write_lock_irq.) _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 12:31 ` Matthew Wilcox @ 2006-08-31 13:01 ` Michael S. Zick 2006-08-31 13:13 ` Matthew Wilcox 2006-08-31 16:27 ` Grant Grundler 1 sibling, 1 reply; 11+ messages in thread From: Michael S. Zick @ 2006-08-31 13:01 UTC (permalink / raw) To: parisc-linux On Thu August 31 2006 07:31, Matthew Wilcox wrote: > > Better ideas, anyone? > better? not sure, but one thing I am looking at using is tri-state locks, defined as: 0 == Busy, change in process &lock == Locked other == Unlocked Since that can be done with load&clear and the information already on hand in the registers. That is also compatible with the single-linked, bi-directional lists of requesters - I.E: the values and the lock are also the head (or tail) of the list. (race free) No actual code to offer at this time. Not my idea, took it from one of the references mentioned in my pa-risc synchronization constructs write-up. Hmmm... That might be usable (the tri-state logic) in dealing with a wrapping timer cr16 also. Mike _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 13:01 ` Michael S. Zick @ 2006-08-31 13:13 ` Matthew Wilcox 2006-08-31 16:08 ` Grant Grundler 0 siblings, 1 reply; 11+ messages in thread From: Matthew Wilcox @ 2006-08-31 13:13 UTC (permalink / raw) To: Michael S. Zick; +Cc: parisc-linux On Thu, Aug 31, 2006 at 08:01:30AM -0500, Michael S. Zick wrote: > better? not sure, but one thing I am looking at using is > tri-state locks, defined as: > > 0 == Busy, change in process > &lock == Locked > other == Unlocked > > Since that can be done with load&clear and the information > already on hand in the registers. Yep, although I don't think that actually saves us from the reader-interrupted-write-lock problem. The first thing the writer does is ldcw, then if it's interrupted, the reader-in-interrupt-context can't tell if it's a heavily contended read-lock (which would eventually work), or if it's interrupted a write lock attempt. One thing we could do is limit the number of times we retry. Hmm, I just thought. If we interrupted a writer trying to acquire the lock, the writer was about to successfully acquire the lock. But we interrupted them, so they can't be running. And nobody else can acquire the lock because the attempting writer holds the spinlock. So the reader in interrupt context can be deemed to have successfully acquired the lock. Now ... how do we handle releasing that lock, given that it can't acquire the spinlock ... _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 13:13 ` Matthew Wilcox @ 2006-08-31 16:08 ` Grant Grundler 0 siblings, 0 replies; 11+ messages in thread From: Grant Grundler @ 2006-08-31 16:08 UTC (permalink / raw) To: Matthew Wilcox; +Cc: parisc-linux On Thu, Aug 31, 2006 at 07:13:40AM -0600, Matthew Wilcox wrote: > One thing we could do is limit the number of times we retry. Yes, we have to or we face a variant of deadlock. > Hmm, I just thought. If we interrupted a writer trying to acquire the > lock, the writer was about to successfully acquire the lock. But we > interrupted them, so they can't be running. And nobody else can acquire > the lock because the attempting writer holds the spinlock. So the > reader in interrupt context can be deemed to have successfully acquired > the lock. Now ... how do we handle releasing that lock, given that it > can't acquire the spinlock ... nononono...please don't go there. It's complicated enough already. Adding more code just makes it slower and harder to maintain. I'd much rather block interrupts in the writer code path as proposed in your previous email. grant _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 12:31 ` Matthew Wilcox 2006-08-31 13:01 ` Michael S. Zick @ 2006-08-31 16:27 ` Grant Grundler 2006-09-01 14:01 ` Matthew Wilcox 1 sibling, 1 reply; 11+ messages in thread From: Grant Grundler @ 2006-08-31 16:27 UTC (permalink / raw) To: Matthew Wilcox; +Cc: parisc-linux On Thu, Aug 31, 2006 at 06:31:35AM -0600, Matthew Wilcox wrote: > On Thu, Aug 31, 2006 at 12:06:37AM -0600, Grant Grundler wrote: > > Here's the patch I ended up with. > > Diff is also parked on gsyprf11:~grundler/diff-2.6.18-rc4-pa4-rwlocks-01 > > > > +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) > > +{ > > + if (!__raw_spin_trylock(&rw->lock)) > > + return 0; > > > > + rw->counter++; > > __raw_spin_unlock(&rw->lock); > > + return 1; > > } > > This has the false failure problem. ie if another CPU is doing a > read_lock() at the same time, it will fail to acquire the lock, even > though it would succeed if it tried again. I don't know if we have any > code which depends upon that not failing, but it does seem a bit > suboptimal. trylock() variants are expected to fail some of the time. But I agree readers should never fail because of another reader. I guess we have to implement some number of retries (less than 5?). > Fixing this is somewhat Hard. My original suggestion was this: > > retry: > if (__raw_spin_trylock(&rw->lock)) { > rw->counter++; > __raw_spin_unlock(&rw->lock); > return 1; > } else if (rw->counter < 0) { > return 0; > } else { > goto retry; > } > > But this leads to deadlock if called from interrupt context and the CPU > had got to: > > static __inline__ void __raw_write_lock(raw_rwlock_t *rw) > { > retry: > __raw_spin_lock(&rw->lock); > > <<<- here > > and hadn't set counter to -1. Drop the "if (rw->counter < 0)" test and we won't have a deadlock. But your next idea on fixing that sounds good to me for other reasons. > Now, we can fix that: > > static __inline__ void __raw_write_lock(raw_rwlock_t *rw) > { > unsigned long flags; > retry: > local_irq_save(flags); > __raw_spin_lock(&rw->lock); ... I'm thinking we want to block interrupts here anyway to make sure the writer gets done and releases the spinlock. I'm also wondering if the writer code paths need to include "mb()" to prevent the compiler and/or other back-end optimizers from re-organizing the instruction stream and "leaking" other code before "counter = -1" is set. James Bottomley already fixed our regular spinlocks for this problem once before. > A similar change has to be made to __raw_write_trylock too: *nod* > Better ideas, anyone? > (And perhaps more importantly, anyone spot any holes in my reasoning? Nope and nope. > I'm not too happy disabling interrupts *after* disabling preemption. > And of course, we disable interrupts twice when called with > write_lock_irq.) yup. thanks, grant _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-08-31 16:27 ` Grant Grundler @ 2006-09-01 14:01 ` Matthew Wilcox 2006-09-01 15:57 ` Grant Grundler 0 siblings, 1 reply; 11+ messages in thread From: Matthew Wilcox @ 2006-09-01 14:01 UTC (permalink / raw) To: Grant Grundler; +Cc: parisc-linux On Thu, Aug 31, 2006 at 10:27:40AM -0600, Grant Grundler wrote: > trylock() variants are expected to fail some of the time. > But I agree readers should never fail because of another reader. > I guess we have to implement some number of retries (less than 5?). I don't think we need retries; we're guaranteed to make forward progress. If we fail to acquire the lock, it's because it's either held for a short duration by a reader, or for a long duration by a writer. If it's a writer, we'll fail due to the counter being negative; if it's a reader, we'll succeed soon. Mmm. Unless, of course, we interrupted a read-locker ... crap. They need to take the lock in an irqsafe way too. > > But this leads to deadlock if called from interrupt context and the CPU > > had got to: > > > > static __inline__ void __raw_write_lock(raw_rwlock_t *rw) > > { > > retry: > > __raw_spin_lock(&rw->lock); > > > > <<<- here > > > > and hadn't set counter to -1. > > Drop the "if (rw->counter < 0)" test and we won't have a deadlock. > But your next idea on fixing that sounds good to me for other reasons. I don't understand why you think that. Can you explain? > > Now, we can fix that: > > > > static __inline__ void __raw_write_lock(raw_rwlock_t *rw) > > { > > unsigned long flags; > > retry: > > local_irq_save(flags); > > __raw_spin_lock(&rw->lock); > ... > > I'm thinking we want to block interrupts here anyway to make sure > the writer gets done and releases the spinlock. Umm. Sounds like a spectacularly bad idea. If the caller wanted to do that, they would have called write_lock_irqsave() or write_lock_irq(). > I'm also wondering if the writer code paths need to include "mb()" > to prevent the compiler and/or other back-end optimizers from > re-organizing the instruction stream and "leaking" other code > before "counter = -1" is set. James Bottomley already > fixed our regular spinlocks for this problem once before. With the out-of-line spinlocks (and for that matter, write locks), that's not going to matter. The only place that calls __raw_write_lock() is in kernel/spinlock.c, so there's no way for gcc to optimise that away. I can put it in anyway, since it's not going to make a difference. _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-09-01 14:01 ` Matthew Wilcox @ 2006-09-01 15:57 ` Grant Grundler 2006-09-01 17:19 ` Matthew Wilcox 0 siblings, 1 reply; 11+ messages in thread From: Grant Grundler @ 2006-09-01 15:57 UTC (permalink / raw) To: Matthew Wilcox; +Cc: parisc-linux On Fri, Sep 01, 2006 at 08:01:23AM -0600, Matthew Wilcox wrote: > On Thu, Aug 31, 2006 at 10:27:40AM -0600, Grant Grundler wrote: > > trylock() variants are expected to fail some of the time. > > But I agree readers should never fail because of another reader. > > I guess we have to implement some number of retries (less than 5?). > > I don't think we need retries; we're guaranteed to make forward > progress. If we fail to acquire the lock, it's because it's either held > for a short duration by a reader, or for a long duration by a writer. > If it's a writer, we'll fail due to the counter being negative; if it's > a reader, we'll succeed soon. Mmm. Unless, of course, we interrupted a > read-locker ... crap. They need to take the lock in an irqsafe way too. Yup... > > Drop the "if (rw->counter < 0)" test and we won't have a deadlock. > > But your next idea on fixing that sounds good to me for other reasons. > > I don't understand why you think that. Can you explain? Without blocking interrupts, that test is reading a value that's not deterministic. ie we don't when if/when we are interrupting a writer. Failing the read lock is safe even if it's not correct. > > I'm thinking we want to block interrupts here anyway to make sure > > the writer gets done and releases the spinlock. > > Umm. Sounds like a spectacularly bad idea. If the caller wanted to do > that, they would have called write_lock_irqsave() or write_lock_irq(). Well, ok - you're right about caller intentions. But the caller also has no clue about parisc rw_locks and how fsck'd the implementation is. I'm just "speculating out loud" in order to make parisc implementation work better in practice. > With the out-of-line spinlocks (and for that matter, write locks), > that's not going to matter. The only place that calls > __raw_write_lock() is in kernel/spinlock.c, so there's no way for gcc to > optimise that away. I can put it in anyway, since it's not going to > make a difference. I'm not sure that a good reason to put the mb() in. Would "it's correct" be a better reason? I'm thinking other people will look at the code when trying to understand parisc. thanks, grant _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [parisc-linux] some more questions about __raw_write_trylock() hppa implementation 2006-09-01 15:57 ` Grant Grundler @ 2006-09-01 17:19 ` Matthew Wilcox 0 siblings, 0 replies; 11+ messages in thread From: Matthew Wilcox @ 2006-09-01 17:19 UTC (permalink / raw) To: Grant Grundler; +Cc: parisc-linux On Fri, Sep 01, 2006 at 09:57:31AM -0600, Grant Grundler wrote: > > > Drop the "if (rw->counter < 0)" test and we won't have a deadlock. > > > But your next idea on fixing that sounds good to me for other reasons. > > > > I don't understand why you think that. Can you explain? > > Without blocking interrupts, that test is reading a value > that's not deterministic. ie we don't when if/when we are > interrupting a writer. Failing the read lock is safe even > if it's not correct. Oh, OK. Understood. I thought you had a neat optimisation there ;-) > > > I'm thinking we want to block interrupts here anyway to make sure > > > the writer gets done and releases the spinlock. > > > > Umm. Sounds like a spectacularly bad idea. If the caller wanted to do > > that, they would have called write_lock_irqsave() or write_lock_irq(). > > Well, ok - you're right about caller intentions. But the caller also has > no clue about parisc rw_locks and how fsck'd the implementation is. > I'm just "speculating out loud" in order to make parisc implementation > work better in practice. It's not that bad. Really ;-) > > With the out-of-line spinlocks (and for that matter, write locks), > > that's not going to matter. The only place that calls > > __raw_write_lock() is in kernel/spinlock.c, so there's no way for gcc to > > optimise that away. I can put it in anyway, since it's not going to > > make a difference. > > I'm not sure that a good reason to put the mb() in. > Would "it's correct" be a better reason? > I'm thinking other people will look at the code when trying to > understand parisc. I doubt it, or somebody might've spotted the, what, three or four problems with our rwlocks that I've found? - an interrupt while taking or releasing a read_lock can deadlock against a read_lock. - an interrupt while holding a read_lock will deadlock against a read_trylock. - an interrupt while holding a write_lock will deadlock against a read_trylock or write_trylock. Anyway, here's the current diff; I have a make -j4; make clean running in an endless loop on nicol right now. Any further suggestions for stress-testing are welcome ... perhaps I'll install apache and run an apache benchmark. diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index a93960e..97115dc 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -56,50 +56,70 @@ static inline int __raw_spin_trylock(raw } /* - * Read-write spinlocks, allowing multiple readers - * but only one writer. + * Read-write spinlocks, allowing multiple readers but only one writer. + * The spinlock is held by the writer, preventing any readers or other + * writers from grabbing the rwlock. Readers use the lock to serialise their + * access to the counter (which records how many readers currently hold the + * lock). Linux rwlocks are unfair to writers; they can be starved for + * an indefinite time by readers. They can also be taken in interrupt context, + * so we have to disable interrupts when acquiring the spin lock to be sure + * that an interrupting reader doesn't get an inconsistent view of the lock. */ -#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) - -/* read_lock, read_unlock are pretty straightforward. Of course it somehow - * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */ - static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - rw->counter++; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - rw->counter--; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } -/* write_lock is less trivial. We optimistically grab the lock and check - * if we surprised any readers. If so we release the lock and wait till - * they're all gone before trying again - * - * Also note that we don't use the _irqsave / _irqrestore suffixes here. - * If we're called with interrupts enabled and we've got readers (or other - * writers) in interrupt handlers someone fucked up and we'd dead-lock - * sooner or later anyway. prumpf */ +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + retry: + local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + rw->counter++; + __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); + return 1; + } + + local_irq_restore(flags); + /* If write-locked, we fail to acquire the lock */ + if (rw->counter < 0) + return 0; + + /* Wait until we have a realistic chance at the lock */ + while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) + cpu_relax(); + + goto retry; +} -static __inline__ void __raw_write_lock(raw_rwlock_t *rw) +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { + unsigned long flags; retry: + local_irq_save(flags); __raw_spin_lock(&rw->lock); - if(rw->counter != 0) { - /* this basically never happens */ + if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); while (rw->counter != 0) cpu_relax(); @@ -107,31 +127,35 @@ retry: goto retry; } - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ + rw->counter = -1; /* mark as write-locked */ + mb(); + local_irq_restore(flags); } -/* write_unlock is absolutely trivial - we don't have to wait for anything */ - -static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { rw->counter = 0; __raw_spin_unlock(&rw->lock); } -static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) +static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - if (rw->counter != 0) { - /* this basically never happens */ - __raw_spin_unlock(&rw->lock); ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2006-09-01 17:19 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-08-30 20:23 [parisc-linux] some more questions about __raw_write_trylock() hppa implementation Joel Soete 2006-08-31 3:59 ` Matthew Wilcox 2006-08-31 6:06 ` Grant Grundler 2006-08-31 12:31 ` Matthew Wilcox 2006-08-31 13:01 ` Michael S. Zick 2006-08-31 13:13 ` Matthew Wilcox 2006-08-31 16:08 ` Grant Grundler 2006-08-31 16:27 ` Grant Grundler 2006-09-01 14:01 ` Matthew Wilcox 2006-09-01 15:57 ` Grant Grundler 2006-09-01 17:19 ` Matthew Wilcox
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.