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. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/