On Sun, Nov 14, 2021 at 10:38:57PM -0500, Waiman Long wrote:I think your modification already have included the rewrite for that part.
On 11/12/21 07:10, Peter Zijlstra wrote:Argh, yeah, I got confused by the whole !woken case, but that case won't
Argh, rwsem_mark_wake() doesn't clear HANDOFF when list_empty(), andrwsem_mark_wake() does clear the HANDOFF flag if it was set.
write_slowpath() is *far* too clever about all of this.
ever hit list_empty() either. Perhaps that stuff could use a bit of a
reflow too.
Yes, but a random waiter can wake up and see it be set and also starthandoff_set flag is only set when the waiter becomes the first.@@ -1098,7 +1110,7 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)I'm thinking this wants to be something like:
* In this case, we attempt to acquire the lock again
* without sleeping.
*/
- if (wstate == WRITER_HANDOFF) {
+ if (waiter.handoff_set) {
if (rwsem_first_waiter(sem) == &waiter && waiter.handoff_set) {
spinning.
I tried that, but then we get an extra atomic in this path. As is I made+ rwsem_del_waiter(sem, &waiters); ?enum owner_state owner_state;@@ -575,6 +610,11 @@ static inline bool rwsem_try_write_lock(
preempt_disable();
return false;
}
+ /*
+ * Have rwsem_try_write_lock() fully imply rwsem_del_waiter() on
+ * success.
+ */
+ list_del(&waiter->list);
rwsem_set_owner(sem);
return true;
}
@@ -1128,16 +1153,14 @@ rwsem_down_write_slowpath(struct rw_sema
raw_spin_lock_irq(&sem->wait_lock);
}
__set_current_state(TASK_RUNNING);
- list_del(&waiter.list);
try_write_lock() do the full del_waiter, see the hunk above.