aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 26a550f5082..43f4d6b6534 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);
}