Messages in this thread | | | Date | Wed, 11 Nov 2015 20:39:53 +0100 | From | Oleg Nesterov <> | Subject | Re: [PATCH 4/4] locking: Introduce smp_cond_acquire() |
| |
On 11/11, Peter Zijlstra wrote: > > On Wed, Nov 11, 2015 at 05:39:40PM +0800, Boqun Feng wrote: > > > Just be curious, should spin_unlock_wait() semantically be an ACQUIRE? > > I did wonder the same thing, it would simplify a number of things if > this were so.
Yes, me too.
Sometimes I even think it should have both ACQUIRE + RELEASE semantics. IOW, it should be "equivalent" to spin_lock() + spin_unlock().
Consider this code:
object_t *object; spinlock_t lock;
void update(void) { object_t *o;
spin_lock(&lock); o = READ_ONCE(object); if (o) { BUG_ON(o->dead); do_something(o); } spin_unlock(&lock); }
void destroy(void) // can be called only once, can't race with itself { object_t *o;
o = object; object = NULL;
/* * pairs with lock/ACQUIRE. The next update() must see * object == NULL after spin_lock(); */ smp_mb();
spin_unlock_wait(&lock);
/* * pairs with unlock/RELEASE. The previous update() has * already passed BUG_ON(o->dead). * * (Yes, yes, in this particular case it is not needed, * we can rely on the control dependency). */ smp_mb();
o->dead = true; }
I believe the code above is correct and it needs the barriers on both sides.
If it is wrong, then task_work_run() is buggy: it relies on mb() implied by cmpxchg() before spin_unlock_wait() the same way: the next task_work_cancel() should see the result of our cmpxchg(), it must not try to read work->next or work->func.
Hmm. Not sure I really understand what I am trying to say... Perhaps in fact I mean that unlock_wait() should be removed because it is too subtle for me ;)
Oleg.
| |