aboutsummaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorFujii Masao <fujii@postgresql.org>2014-12-18 23:07:51 +0900
committerFujii Masao <fujii@postgresql.org>2014-12-18 23:07:51 +0900
commit38628db8d8caff21eb6cf8d775c0b2d04cf07b9b (patch)
tree39bf2ede12655209e39d8474589dde535abb5997 /src/include
parent19e065c0492c34fbccbd2c3707ba68cff14195a3 (diff)
downloadpostgresql-38628db8d8caff21eb6cf8d775c0b2d04cf07b9b.tar.gz
postgresql-38628db8d8caff21eb6cf8d775c0b2d04cf07b9b.zip
Add memory barriers for PgBackendStatus.st_changecount protocol.
st_changecount protocol needs the memory barriers to ensure that the apparent order of execution is as it desires. Otherwise, for example, the CPU might rearrange the code so that st_changecount is incremented twice before the modification on a machine with weak memory ordering. This surprising result can lead to bugs. This commit introduces the macros to load and store st_changecount with the memory barriers. These are called before and after PgBackendStatus entries are modified or copied into private memory, in order to prevent CPU from reordering PgBackendStatus access. Per discussion on pgsql-hackers, we decided not to back-patch this to 9.4 or before until we get an actual bug report about this. Patch by me. Review by Robert Haas.
Diffstat (limited to 'src/include')
-rw-r--r--src/include/pgstat.h44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 08925336d18..7285f3ee167 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -16,6 +16,7 @@
#include "libpq/pqcomm.h"
#include "portability/instr_time.h"
#include "postmaster/pgarch.h"
+#include "storage/barrier.h"
#include "utils/hsearch.h"
#include "utils/relcache.h"
@@ -714,6 +715,12 @@ typedef struct PgBackendStatus
* st_changecount again. If the value hasn't changed, and if it's even,
* the copy is valid; otherwise start over. This makes updates cheap
* while reads are potentially expensive, but that's the tradeoff we want.
+ *
+ * The above protocol needs the memory barriers to ensure that
+ * the apparent order of execution is as it desires. Otherwise,
+ * for example, the CPU might rearrange the code so that st_changecount
+ * is incremented twice before the modification on a machine with
+ * weak memory ordering. This surprising result can lead to bugs.
*/
int st_changecount;
@@ -745,6 +752,43 @@ typedef struct PgBackendStatus
char *st_activity;
} PgBackendStatus;
+/*
+ * Macros to load and store st_changecount with the memory barriers.
+ *
+ * pgstat_increment_changecount_before() and
+ * pgstat_increment_changecount_after() need to be called before and after
+ * PgBackendStatus entries are modified, respectively. This makes sure that
+ * st_changecount is incremented around the modification.
+ *
+ * Also pgstat_save_changecount_before() and pgstat_save_changecount_after()
+ * need to be called before and after PgBackendStatus entries are copied into
+ * private memory, respectively.
+ */
+#define pgstat_increment_changecount_before(beentry) \
+ do { \
+ beentry->st_changecount++; \
+ pg_write_barrier(); \
+ } while (0)
+
+#define pgstat_increment_changecount_after(beentry) \
+ do { \
+ pg_write_barrier(); \
+ beentry->st_changecount++; \
+ Assert((beentry->st_changecount & 1) == 0); \
+ } while (0)
+
+#define pgstat_save_changecount_before(beentry, save_changecount) \
+ do { \
+ save_changecount = beentry->st_changecount; \
+ pg_read_barrier(); \
+ } while (0)
+
+#define pgstat_save_changecount_after(beentry, save_changecount) \
+ do { \
+ pg_read_barrier(); \
+ save_changecount = beentry->st_changecount; \
+ } while (0)
+
/* ----------
* LocalPgBackendStatus
*