On Thu Aug 24 06:08:47 2023 +0000, Yuxuan Shui wrote:
what if we let `srwlock_transfer_ownership` go beyond the tail of the list when updating the head pointer? (there is at most one node beyond the tail.) and we cmpxchg when updating the head pointer on `srwlock_wait`'s side, if that fails then we know it's up-to-date. it's still possible for `transfer_ownership` to start and finish in between `we successfully written to the head pointer` ~ `we update lock ptr`, but in that case `transfer_ownership` would overwrite the head pointer with the updated one.
Currently there is a gap between reading the head, and pushing our node to the list at all. If a wake happens during that gap, there is no way for it to know that the new waiter needs its head updated. I.e. we have this race:
``` thread Q thread S ------------------------------ read head go through list, change head wake cmpxchg next cmpxchg tail ```
I think you're onto a solution, although I'm not quite sure I correctly understand what you're saying, but in order for it to work, we *also* need to change the order of queueing:
* cmpxchg the "prev->next" pointer (compare to NULL), retry if failure * read prev->head * cmpxchg the "waiter.head" pointer (compare to NULL), ignore if failure * cmpxchg the lock tail pointer; failure should be impossible if there was a prev
Then, when waking, we have to, as you say, not trust the tail to be the actual tail.