summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/lmgr/lwlock.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 88d9cbec215..196b1110326 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -35,6 +35,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"
@@ -1102,6 +1103,8 @@ LWLockUpdateVar(LWLock *l, 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);
}
@@ -1222,6 +1225,17 @@ LWLockRelease(LWLock *l)
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);
}