diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 26a550f50824271f26248e4e0d4f3ce4127239a5..43f4d6b6534bc46de60762c1e8c1bce165069688 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -36,6 +36,7 @@ #include "miscadmin.h" #include "pg_trace.h" #include "replication/slot.h" +#include "storage/barrier.h" #include "storage/ipc.h" #include "storage/predicate.h" #include "storage/proc.h" @@ -1133,6 +1134,8 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val) proc = head; head = proc->lwWaitLink; proc->lwWaitLink = NULL; + /* check comment in LWLockRelease() about this barrier */ + pg_write_barrier(); proc->lwWaiting = false; PGSemaphoreUnlock(&proc->sem); } @@ -1253,6 +1256,17 @@ LWLockRelease(LWLock *lock) proc = head; head = proc->lwWaitLink; proc->lwWaitLink = NULL; + /* + * Guarantee that lwWaiting being unset only becomes visible once the + * unlink from the link has completed. Otherwise the target backend + * could be woken up for other reason and enqueue for a new lock - if + * that happens before the list unlink happens, the list would end up + * being corrupted. + * + * The barrier pairs with the SpinLockAcquire() when enqueing for + * another lock. + */ + pg_write_barrier(); proc->lwWaiting = false; PGSemaphoreUnlock(&proc->sem); }